NetworksRelease VersioningOffline transaction signingGlossary
Hardfork Update Process

Signing Transactions with Multisig Accounts

Learn how to create multisignature accounts here.

Once you have created the multisignature accounts, signing a transaction involves the following steps:

  1. Create an unsigned transaction for participants to sign
  2. Create the signing commitment (performed by each participant)
  3. Aggregate the signing commitments to create the signing package (performed by a coordinator)
  4. Create signature shares using the signing package (performed by each participant)
  5. Aggregate the signature shares to create the final signed transaction (performed by a coordinator)

In the examples below, we will be signing a transaction with 2 of 2 multisig accounts.

Create the unsigned transaction 

Any account in the multisig group (or a view-only account that possesses the group view keys) can initiate sending a transaction by generating an "unsigned transaction". A raw transaction contains the parameters of a transaction, like which notes will be spent, which notes will be created, and who will own the notes. An unsigned transaction contains pre-computed zero-knowledge proofs in its spend, output, mint, and burn descriptions, but lacks the authorizing signature required for valid spends and mints.

The example below shows how to create a raw transaction to send 10 $ORE to two addresses and then generate an unsigned transaction from that raw transaction:

import { Asset } from '@ironfish/rust-nodejs'
import {
} from '@ironfish/sdk'

async function main(): Promise<void> {
  const sdk = await IronfishSdk.init({ dataDir: '~/.dev0' });
  const client = await sdk.connectRpc();

  const accountName = 'MyMultisigAccount';

  // Create the raw transaction
  const createOptions: CreateTransactionRequest = {
    account: accountName,
    outputs: [
        publicAddress: 'b28b5d5a629b57f15e73ee6040efe9a8a0abca54a439e9ef5a8686b5765684ee',
        amount: CurrencyUtils.encode(10n),
        memo: '',
        assetId: Asset.nativeId().toString('hex'),
        publicAddress: '34ba96315e36de52a3138475776f91df215ebbd868757c61a32dfe34563bd51f',
        amount: CurrencyUtils.encode(10n),
        memo: '',
        assetId: Asset.nativeId().toString('hex'),
    fee: CurrencyUtils.encode(1n),
    // don't expire until 60 blocks from the current chain head to allow enough time for signing
    expirationDelta: 60,

  const createResponse = await client.wallet.createTransaction(createOptions);
  const rawTransaction = createResponse.content.transaction;

  // Build the raw transaction to create an unsigned transaction
  const buildOptions: BuildTransactionRequest = {
    account: accountName,

  const buildResponse = await client.wallet.buildTransaction(buildOptions);

Tip: Make sure the unsigned transaction has a sufficient expiration time to allow for the completion of the signing process. The expiration can be set to 0 to ensure the transaction never expires.

Create the signing commitment 

Once the participants agree on the contents of a transaction and who is going to participate in signing, each participant will create a signing commitment.

The identities of the participant and the unsigned transaction are required to generate a commitment.

import { multisig } from '@ironfish/rust-nodejs'

const participantIdentities = [

const participantCommitment = multisig.createSigningCommitment( 

Aggregate the signing commitments to create the signing package 

Once all participants have created their signing commitments, the commitments are aggregated to create the signing package.

Note: This action can be performed by any participant or the coordinator.

import { UnsignedTransaction } from '@ironfish/rust-nodejs'

const unsignedTransactionData = "01010000000000000002000000000000...9f3fb432907a84c8483586a6a565d308"

const unsignedTransaction = new UnsignedTransaction(
    Buffer.from(unsignedTransactionData, 'hex'),

const participantCommitments = [

const signingPackage = unsignedTransaction.signingPackage(participantCommitments)

Create signature shares 

Once the signing package is created and distributed to all participants, each participant can create a signature share using their secret key and the signing package.

import { multisig } from '@ironfish/rust-nodejs'

const participantSignature = multisig.createSignatureShare(

Aggregate the signature shares to create the signed transaction 

Once all participants have created their signature shares, the shares are aggregated to create the final signed transaction.

Note: This action can be performed by any participant or the coordinator.

import { multisig } from '@ironfish/rust-nodejs'

const participantSignatures = [

const serialized = multisig.aggregateSignatureShares(

const transaction = new Transaction(serialized)

Join our newsletter and stay up to date with privacy and crypto.

Discover our impactful presence — read our blog.


  • FAQ
  • Whitepaper
  • Tokenomics


  • Get Started
  • Node App
  • Mine
  • Block Explorer
  • Ecosystem


  • Documentation
  • Github


  • Foundation
  • Governance
  • Grants
  • Our Community


  • About Us
  • Media Kit
  • Contact Us
Privacy Policy


Copyright 2024 Iron Fish.