Signing Transactions | Algorand Developer Portal
Signing Transactions
This section explains how to authorize transactions on the Algorand Network. Transaction signing is a fundamental security feature that proves ownership of an account and authorizes specific actions on the blockchain.
Before a transaction is sent to the network, it must first be authorized by the sender.
There are different transactions signatures to be described in the following sections:
Single Signatures
A single signature corresponds to a signature from the private key of an Algorand public/private key pair.
This is an example of a transaction signed by an Algorand private key displayed with goal clerk inspect command:
{
"sig": "ynA5Hmq+qtMhRVx63pTO2RpDrYiY1wzF/9Rnnlms6NvEQ1ezJI/Ir9nPAT6+u+K8BQ32pplVrj5NTEMZQqy9Dw==",
"txn": {
"amt": 10000000,
"fee": 1000,
"fv": 4694301,
"gen": "testnet-v1.0",
"gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
"lv": 4695301,
"rcv": "QC7XT7QU7X6IHNRJZBR67RBMKCAPH67PCSX4LYH4QKVSQ7DQZ32PG5HSVQ",
"snd": "EW64GC6F24M7NDSC5R3ES4YUVE3ZXXNMARJHDCCCLIHZU6TBEOC7XRSBG4",
"type": "pay"
}
}
This transaction sends 10 Algo from "EW64GC..." to "QC7XT7..." on TestNet. The transaction was signed with the private key that corresponds to the "snd" address of "EW64GC...". The base64 encoded signature is shown as the value of the "sig" field.
How to
The following example will demonstrate how to sign a transaction with an account which originally doesn’t have a signer.
/* When working with account types that do not include a signer,
* you can set the signer using the `setSigner` method.
*/
// Generate an account with no signer. The method returns a secret key and address.
const { sk: accountNoSignerSecretKey, addr: accountNoSignerAddress } = algosdk.generateAccount()
// Ensure the account is funded from the dispenser account
await algorand.account.ensureFunded(accountNoSignerAddress, dispenser, algo(10))
// This payment transaction fails with `Error: No signer found` because the account has no signer
try {
await algorand.send.payment({
sender: accountNoSignerAddress,
receiver: randomAccountA,
amount: algo(1),
note: 'Sending payment with account that has no signer',
})
} catch (e) {
console.log(`Error: ${e}`)
}
// Track the given account for later signing.
algorand.account.setSigner(
accountNoSignerAddress,
algosdk.makeBasicAccountTransactionSigner({
sk: accountNoSignerSecretKey,
addr: accountNoSignerAddress,
}),
)
// Now the account is tracked and has the signer set so it can be used to sign transactions
const accountWithSigner = algorand.account.getAccount(accountNoSignerAddress)
await algorand.send.payment({
sender: accountWithSigner.addr,
receiver: randomAccountA,
amount: algo(1),
signer: accountWithSigner.signer,
note: 'Sending payment with account that has a signer explicitly set',
})
Multisignatures
When a transaction’s sender is a multisignature account, authorization requires signatures from multiple private keys. The number of signatures must be equal to or greater than the account’s threshold value.
To sign a multisignature transaction, you need the complete multisignature account details: the list and order of authorized addresses, the threshold value, and the version. This information must be available either in the transaction itself or to the signing agent.
Here is what the same transaction above would look like if sent from a 2/3 multisig account.
{
"msig": {
"subsig": [
{"pk": "SYGHTA2DR5DYFWJE6D4T34P4AWGCG7JTNMY4VI6EDUVRMX7NG4KTA2WMDA"},
{"pk": "VBDMPQACQCH5M6SBXKQXRWQIL7QSR4FH2UI6EYI4RCJSB2T2ZYF2JDHZ2Q"},
{"pk": "W3KONPXCGFNUGXGDCOCQYVD64KZOLUMHZ7BNM2ZBK5FSSARRDEXINLYHPI"}
],
"thr": 2,
"v": 1
},
"txn": {
"amt": 10000000,
"fee": 1000,
"fv": 4694301,
"gen": "testnet-v1.0",
"gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
"lv": 4695301,
"rcv": "QC7XT7QU7X6IHNRJZBR67RBMKCAPH67PCSX4LYH4QKVSQ7DQZ32PG5HSVQ",
"snd": "GQ3QPLJL4VKVGQCHPXT5UZTNZIJAGVJPXUHCJLRWQMFRVL4REVW7LJ3FGY",
"type": "pay"
}
}
The difference between this transaction and the one above is the form of its signature component. For multisignature accounts, an "msig" struct is added which contains the public addresses, the threshold value, and the version.
How-To
The following code example demonstrates how to execute a transaction signed by a multisig account.
// Create a 2-of-3 multisig account that requires only 2 signatures to authorize transactions
const multisigAccount = algorand.account.multisig(
{ version: 1, threshold: 2, addrs: [randomAccountA, randomAccountB, randomAccountC] },
[randomAccountA.account, randomAccountB.account, randomAccountC.account],
)
await algorand.account.ensureFunded(multisigAccount, dispenser, algo(10))
// Method 1: Create an unsigned transaction from the multisig account and sign it
const unsignedMultisigPayTxn = await algorand.createTransaction.payment({
sender: multisigAccount,
receiver: randomAccountA,
amount: algo(1),
note: 'Sending payment with multisig account using method 1',
})
await algorand.newGroup().addTransaction(unsignedMultisigPayTxn, multisigAccount.signer).send()
// Method 2: Send a payment transaction from the multisig account
await algorand.send.payment({
sender: multisigAccount,
receiver: randomAccountA,
amount: algo(1),
note: 'Sending payment with multisig account using method 2',
})