[[module]] name = "sol" derivation_prefix = "m/44'/501'/0'" algorithm = "Ed25519" [[module.workflow]] # The name of the workflow, which can be called by: # `icepick workflow sol transfer-token` name = "transfer-token" # These values are used as inputs for other workflows, acquired from the CLI. # These values can only be strings, but other values can be any value that can # be serialized by serde_json::Value. # These values can also be loaded using "internal-load-file", using some form # of later-defined signature validation. inputs = ["from_address", "to_address", "token_name", "token_amount"] # Get the token address and token decimals for the given token [[module.workflow.step]] type = "sol-get-token-info" # The key is the key that is passed to the program in the # `values` field. The value is the item in storage. In this case, # we read a `token-name` from our input, but the operation expects `token`. inputs = { token = "token_name" } # Because these two fields are currently unused in our storage, we can grab # them from the outputs of our module. The key is the key of the output value # we want to store, and the value is the name to be assigned in storage. outputs = { token_address = "token_address", token_decimals = "token_decimals" } # Load the transaction nonce from the SD card [[module.workflow.step]] type = "internal-load-file" # Pre-defined values to be passed to the module. # In this case, the `filename` field is reserved for marking which file to load. values = { filename = "nonce.json" } # This value is marked to be saved in-memory, and can be used as an input for # later steps. outputs = { nonce_authority = "nonce_authority", nonce_data = "nonce_data", nonce_address = "nonce_address" } [[module.workflow.step]] # Generate an unsigned Transaction # This step MUST run immediately before sol-sign, as in the current version of # Icepick, keys are only held in memory in-between a single module invocation. type = "sol-transfer-token" # If using a lot of inputs, it may be best to use a non-inline table. # Non-inline tables _must_ be the last step, as otherwise, `outputs` for # example would be considered a member of `inputs`. In this case, we use a # non-inline table for `outputs` even though it would fit on one line, to avoid # the ambiguity. [module.workflow.step.inputs] amount = "token_amount" token_address = "token_address" decimals = "token_decimals" to_address = "to_address" from_address = "from_address" [module.workflow.step.outputs] instructions = "instructions" derivation_accounts = "derivation_accounts" [[module.workflow.step]] type = "sol-compile" [module.workflow.step.inputs] instructions = "instructions" derivation_accounts = "derivation_accounts" nonce_address = "nonce_address" nonce_authority = "nonce_authority" nonce_data = "nonce_data" [module.workflow.step.outputs] transaction = "unsigned_transaction" # Sign the transaction [[module.workflow.step]] type = "sol-sign" [module.workflow.step.inputs] transaction = "unsigned_transaction" blockhash = "nonce_data" [module.workflow.step.outputs] transaction = "signed_transaction" # Write the signed transaction to a file [[module.workflow.step]] type = "internal-save-file" # We are using a static filename here, so we use `values` instead of `inputs`. values = { filename = "transaction.json" } # All fields in both `inputs` and `values`, other than `filename`, will be # persisted to the file. In this case, the `transaction` field of the file will # contain the signed transaction. inputs = { transaction = "signed_transaction" } # NOTE: To get a nonce address, the `generate-nonce-account` workflow should be # run. It is the only workflow that uses a blockhash, which is why a # `broadcast-with-blockhash` or similar is not, and should not be, implemented. [[module.workflow]] name = "broadcast" inputs = ["nonce_address", "cluster"] [[module.workflow.step]] type = "sol-get-nonce-account-data" inputs = { nonce_address = "nonce_address", cluster = "cluster" } outputs = { authority = "nonce_authority", durable_nonce = "nonce" } [[module.workflow.step]] type = "internal-save-file" values = { filename = "nonce.json" } inputs = { nonce_authority = "nonce_authority", nonce_data = "nonce", nonce_address = "nonce_address" } [[module.workflow.step]] type = "internal-load-file" values = { filename = "transaction.json" } outputs = { transaction = "transaction" } [[module.workflow.step]] type = "sol-broadcast" inputs = { cluster = "cluster", transaction = "transaction" } outputs = { status = "status", url = "url", error = "error" } [[module.workflow]] name = "generate-nonce-account" inputs = ["cluster", "authorization_address"] [[module.workflow.step]] type = "sol-generate-wallet" [[module.workflow.step]] type = "sol-get-wallet-address" outputs = { pubkey = "wallet_pubkey" } [[module.workflow.step]] type = "sol-await-funds" inputs = { address = "wallet_pubkey", cluster = "cluster" } # enough to cover two signatures and the 1_500_000 approx. rent fee values = { lamports = "1510000" } [[module.workflow.step]] type = "sol-get-blockhash" inputs = { cluster = "cluster" } outputs = { blockhash = "blockhash" } [[module.workflow.step]] type = "sol-create-nonce-account-and-signing-key" [module.workflow.step.inputs] from_address = "wallet_pubkey" authorization_address = "authorization_address" [module.workflow.step.outputs] transaction = "unsigned_transaction" nonce_pubkey = "nonce_pubkey" nonce_privkey = "private_keys" [[module.workflow.step]] type = "sol-sign" [module.workflow.step.inputs] blockhash = "blockhash" signing_keys = "private_keys" transaction = "unsigned_transaction" [module.workflow.step.outputs] transaction = "signed_transaction" [[module.workflow.step]] type = "sol-broadcast" inputs = { cluster = "cluster", transaction = "signed_transaction" } outputs = { status = "status", url = "url" } [[module.workflow.step]] type = "internal-cat" inputs = { status = "status", url = "url", nonce_account = "nonce_pubkey" } outputs = { status = "status", url = "url", nonce_account = "nonce_account" } [[module.workflow]] # Transfer SOL from one address to another. name = "transfer" inputs = ["to_address", "from_address", "amount"] [[module.workflow.step]] type = "internal-load-file" values = { filename = "nonce.json" } outputs = { nonce_authority = "nonce_authority", nonce_data = "nonce_data", nonce_address = "nonce_address" } [[module.workflow.step]] type = "sol-transfer" inputs = { from_address = "from_address", to_address = "to_address", amount = "amount" } outputs = { instructions = "instructions", derivation_accounts = "derivation_accounts" } [[module.workflow.step]] type = "sol-compile" [module.workflow.step.inputs] instructions = "instructions" derivation_accounts = "derivation_accounts" nonce_address = "nonce_address" nonce_authority = "nonce_authority" nonce_data = "nonce_data" [module.workflow.step.outputs] transaction = "unsigned_transaction" [[module.workflow.step]] type = "sol-sign" inputs = { blockhash = "nonce_data", transaction = "unsigned_transaction" } outputs = { transaction = "signed_transaction" } [[module.workflow.step]] type = "internal-save-file" values = { filename = "transaction.json" } inputs = { transaction = "signed_transaction" } [[module]] name = "cosmos" derivation_prefix = "m/44'/118'/0'" algorithm = "Secp256k1" [[module.workflow]] name = "transfer" inputs = ["from_address", "to_address", "asset_name", "chain_name", "asset_amount"] [[module.workflow.step]] # NOTE: chain_name can't be discoverable by filtering from asset_name, since # some asset devnets reuse the name. There's no difference between KYVE on Kyve # or Korellia (devnet). type = "cosmos-get-chain-info" inputs = { chain_name = "chain_name" } outputs = { blockchain_config = "blockchain_config" } [[module.workflow.step]] type = "internal-load-file" values = { filename = "account_info.json" } outputs = { account_number = "account_number", sequence_number = "sequence_number" } [[module.workflow.step]] type = "cosmos-transfer" [module.workflow.step.inputs] from_address = "from_address" to_address = "to_address" amount = "asset_amount" denom = "asset_name" blockchain_config = "blockchain_config" [module.workflow.step.outputs] fee = "fee" tx_messages = "tx_messages" [[module.workflow.step]] type = "cosmos-sign" [module.workflow.step.inputs] fee = "fee" tx_messages = "tx_messages" account_number = "account_number" sequence_number = "sequence_number" blockchain_config = "blockchain_config" [module.workflow.step.outputs] transaction = "signed_transaction" [[module.workflow.step]] type = "internal-save-file" values = { filename = "transaction.json" } inputs = { transaction = "signed_transaction" } [[module.workflow]] name = "broadcast" # NOTE: For the purpose of Cosmos, the nonce is a direct part of the signer's # account. inputs = ["nonce_address", "chain_name"] [[module.workflow.step]] type = "cosmos-get-chain-info" inputs = { chain_name = "chain_name" } outputs = { blockchain_config = "blockchain_config" } [[module.workflow.step]] type = "cosmos-get-account-data" inputs = { account_id = "nonce_address", blockchain_config = "blockchain_config" } outputs = { account_number = "account_number", sequence_number = "sequence_number" } [[module.workflow.step]] type = "internal-save-file" values = { filename = "account_info.json" } inputs = { account_number = "account_number", sequence_number = "sequence_number" } [[module.workflow.step]] type = "internal-load-file" values = { filename = "transaction.json" } outputs = { transaction = "transaction" } [[module.workflow.step]] type = "cosmos-broadcast" inputs = { blockchain_config = "blockchain_config", transaction = "transaction" } outputs = { status = "status", url = "url", error = "error", error_code = "error_code" }