Skip to main content

Signing and Submitting Transactions

In Move-based blockchains, transactions are the primary means to interact with the network, such as invoking smart contract functions or transferring assets.

Understanding Transactions in Move

Transactions in Move represent function calls or operations that affect the state of the blockchain. They are executed based on provided inputs, which can be:

After constructing a transaction—typically using Programmable Transaction Blocks (PTBs)—you need to sign it and submit it to the network.

The signature must be generated using your private key, and the corresponding public key must match the sender's blockchain address.

IOTA uses a IotaKeyPair for signature generation, committing to the Blake2b hash of the intent message (intent || serialized transaction data). Supported signature schemes include Ed25519, ECDSA Secp256k1, ECDSA Secp256r1, and Multisig.

You can instantiate key pairs for Ed25519, ECDSA Secp256k1, and ECDSA Secp256r1 using IotaKeyPair and use them to sign transactions.

Multisig

For Multisig, please refer to its dedicated guide.

Once you have the signature and the transaction bytes, you can submit the transaction for execution on-chain.

Workflow Overview

Here is a high-level overview of the steps involved in constructing, signing, and executing a transaction:

  1. Construct the Transaction Data: Create a Transaction where you can chain multiple operations. Refer to Creating Programmable Transaction Blocks for guidance.
  2. Select Gas Coin and Estimate Gas: Use the SDK's built-in tools for gas estimation and coin selection.
  3. Sign the Transaction: Generate a signature using your private key.
  4. Submit the Transaction: Send the Transaction and its signature to the network for execution.
info

If you wish to specify a particular gas coin, locate the gas coin object ID that you own and include it explicitly in the PTB. If you don't have a gas coin object, use the splitCoin operation to create one. Ensure that the split coin transaction is the first call in the PTB.

Examples

Below are examples demonstrating how to sign and submit transactions using Rust, TypeScript, or the Move CLI.

There are several methods to create a key pair and derive its public key and Move address using the Move TypeScript SDK.

import { fromHEX } from '@iota/bcs';
import { getFullnodeUrl, IOTAClient } from '@iota/iota-sdk/client';
import { type Keypair } from '@iota/iota-sdk/cryptography';
import { Ed25519Keypair } from '@iota/iota-sdk/keypairs/ed25519';
import { Secp256k1Keypair } from '@iota/iota-sdk/keypairs/secp256k1';
import { Secp256r1Keypair } from '@iota/iota-sdk/keypairs/secp256r1';
import { Transaction } from '@iota/iota-sdk/transactions';

const kp_rand_0 = new Ed25519Keypair();
const kp_rand_1 = new Secp256k1Keypair();
const kp_rand_2 = new Secp256r1Keypair();

const kp_import_0 = Ed25519Keypair.fromSecretKey(
fromHex('0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82'),
);
const kp_import_1 = Secp256k1Keypair.fromSecretKey(
fromHex('0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82'),
);
const kp_import_2 = Secp256r1Keypair.fromSecretKey(
fromHex('0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82'),
);

// $MNEMONICS refers to 12/15/18/21/24 words from the wordlist, e.g. "retire skin goose will hurry this field stadium drastic label husband venture cruel toe wire". Refer to [Keys and Addresses](../cryptography/transaction-auth/keys-addresses.mdx) for more.
const kp_derive_0 = Ed25519Keypair.deriveKeypair('$MNEMONICS');
const kp_derive_1 = Secp256k1Keypair.deriveKeypair('$MNEMONICS');
const kp_derive_2 = Secp256r1Keypair.deriveKeypair('$MNEMONICS');

const kp_derive_with_path_0 = Ed25519Keypair.deriveKeypair('$MNEMONICS', "m/44'/4218'/1'/0'/0'");
const kp_derive_with_path_1 = Secp256k1Keypair.deriveKeypair('$MNEMONICS', "m/54'/4218'/1'/0/0");
const kp_derive_with_path_2 = Secp256r1Keypair.deriveKeypair('$MNEMONICS', "m/74'/4218'/1'/0/0");

// replace `kp_rand_0` with the variable names above.
const pk = kp_rand_0.getPublicKey();
const sender = pk.toIOTAAddress();

// create an example transaction block.
const txb = new Transaction();
txb.setSender(sender);
txb.setGasPrice(5);
txb.setGasBudget(100);
const bytes = await txb.build();
const serializedSignature = (await keypair.signTransaction(bytes)).signature;

// verify the signature locally
expect(await keypair.getPublicKey().verifyTransaction(bytes, serializedSignature)).toEqual(
true,
);

// define iota client for the desired network.
const client = new IOTAClient({ url: getFullnodeUrl('testnet') });

// execute transaction.
let res = client.executeTransaction({
Transaction: bytes,
signature: serializedSignature,
});
console.log(res);

Additional Notes

  1. This tutorial focuses on signing with a single private key. For more complex signing policies, refer to the Multisig guide.
  2. If you implement your own signing mechanism, consult the Signatures documentation for accepted specifications.
  3. The 'flag' is a byte that differentiates signature schemes. See Signatures for supported schemes and their flags.
  4. The execute_transaction_block endpoint accepts a list of signatures, typically requiring only one user signature unless using sponsored transactions. For more information, see Sponsored Transactions.

Question 1/2

What does the `IotaKeyPair` commit to when signing a transaction?