Send a Multi-Signed Transaction
The following procedure demonstrates how to create, sign, and submit a multi-signed transaction.
Prerequisites
-
You must have already set up multi-signing for your address.
-
Multi-signing must be available. Multi-signing has been enabled by an Amendment to the XRP Ledger Consensus Protocol since 2016-06-27.
1. Create the transaction
Create a JSON object that represents the transaction you want to submit. You have to specify everything about this transaction, including Fee
and Sequence
. Also include the field SigningPubKey
as an empty string, to indicate that the transaction is multi-signed.
Keep in mind that the Fee
for multi-signed transactions is significantly higher than for regularly-signed transactions. It should be at least (N+1) times the normal transaction cost, where N is the number of signatures you plan to provide. Since it sometimes takes a while to collect signatures from multiple sources, you may want to specify more than the current minimum, in case the transaction cost increases in that time.
Here's an example transaction ready to be multi-signed:
{
"TransactionType": "TrustSet",
"Account": "rEuLyBCvcw4CFmzv8RepSiAoNgF8tTGJQC",
"Flags": 262144,
"LimitAmount": {
"currency": "USD",
"issuer": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"value": "100"
},
"Sequence": 2,
"SigningPubKey": "",
"Fee": "30000"
}
(This transaction creates an accounting relationship from rEuLyBCvcw4CFmzv8RepSiAoNgF8tTGJQC
to rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh
with a maximum balance of 100 USD.)
2. Get one signature
Use the sign_for method with the secret key and address of one of the members of your SignerList to get a signature for that member.
Caution: Never submit a secret key to a server you do not control. Do not send a secret key unencrypted over the network.
$ rippled sign_for rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW <rsA2L..'s secret> '{
> "TransactionType": "TrustSet",
> "Account": "rEuLyBCvcw4CFmzv8RepSiAoNgF8tTGJQC",
> "Flags": 262144,
> "LimitAmount": {
> "currency": "USD",
> "issuer": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
> "value": "100"
> },
> "Sequence": 2,
> "SigningPubKey": "",
> "Fee": "30000"
> }'
Loading: "/etc/opt/ripple/rippled.cfg"
Connecting to 127.0.0.1:5005
{
"result" : {
"status" : "success",
"tx_blob" : "1200142200040000240000000263D5038D7EA4C680000000000000000000000000005553440000000000B5F762798A53D543A014CAF8B297CFF8F2F937E868400000000000753073008114A3780F5CB5A44D366520FC44055E8ED44D9A2270F3E010732102B3EC4E5DD96029A647CFA20DA07FE1F85296505552CCAC114087E66B46BD77DF744730450221009C195DBBF7967E223D8626CA19CF02073667F2B22E206727BFE848FF42BEAC8A022048C323B0BED19A988BDBEFA974B6DE8AA9DCAE250AA82BBD1221787032A864E58114204288D2E47F8EF6C99BCC457966320D12409711E1F1",
"tx_json" : {
"Account" : "rEuLyBCvcw4CFmzv8RepSiAoNgF8tTGJQC",
"Fee" : "30000",
"Flags" : 262144,
"LimitAmount" : {
"currency" : "USD",
"issuer" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"value" : "100"
},
"Sequence" : 2,
"Signers" : [
{
"Signer" : {
"Account" : "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
"SigningPubKey" : "02B3EC4E5DD96029A647CFA20DA07FE1F85296505552CCAC114087E66B46BD77DF",
"TxnSignature" : "30450221009C195DBBF7967E223D8626CA19CF02073667F2B22E206727BFE848FF42BEAC8A022048C323B0BED19A988BDBEFA974B6DE8AA9DCAE250AA82BBD1221787032A864E5"
}
}
],
"SigningPubKey" : "",
"TransactionType" : "TrustSet",
"hash" : "A94A6417D1A7AAB059822B894E13D322ED3712F7212CE9257801F96DE6C3F6AE"
}
}
}
Save the tx_json
field of the response: it has the new signature in the Signers
field. You can discard the value of the tx_blob
field.
If you have a problem in stand-alone mode or a non-production network, check that multi-sign is enabled.
3. Get additional signatures
You can collect additional signatures in parallel or in serial:
- In parallel: Use the
sign_for
command with the original JSON for the transaction. Each response has a single signature in theSigners
array. - In serial: Use the
sign_for
command with thetx_json
value from the previoussign_for
response. Each response adds a new signature to the existingSigners
array.
Caution: Never submit a secret key to a server you do not control. Do not send a secret key unencrypted over the network.
$ rippled sign_for rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v <rUpy..'s secret> '{
> "Account" : "rEuLyBCvcw4CFmzv8RepSiAoNgF8tTGJQC",
> "Fee" : "30000",
> "Flags" : 262144,
> "LimitAmount" : {
> "currency" : "USD",
> "issuer" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
> "value" : "100"
> },
> "Sequence" : 2,
> "Signers" : [
> {
> "Signer" : {
> "Account" : "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
> "SigningPubKey" : "02B3EC4E5DD96029A647CFA20DA07FE1F85296505552CCAC114087E66B46BD77DF",
> "TxnSignature" : "30450221009C195DBBF7967E223D8626CA19CF02073667F2B22E206727BFE848FF42BEAC8A022048C323B0BED19A988BDBEFA974B6DE8AA9DCAE250AA82BBD1221787032A864E5"
> }
> }
> ],
> "SigningPubKey" : "",
> "TransactionType" : "TrustSet",
> "hash" : "A94A6417D1A7AAB059822B894E13D322ED3712F7212CE9257801F96DE6C3F6AE"
> }'
Loading: "/etc/opt/ripple/rippled.cfg"
Connecting to 127.0.0.1:5005
{
"result" : {
"status" : "success",
"tx_blob" : "1200142200040000240000000263D5038D7EA4C680000000000000000000000000005553440000000000B5F762798A53D543A014CAF8B297CFF8F2F937E868400000000000753073008114A3780F5CB5A44D366520FC44055E8ED44D9A2270F3E010732102B3EC4E5DD96029A647CFA20DA07FE1F85296505552CCAC114087E66B46BD77DF744730450221009C195DBBF7967E223D8626CA19CF02073667F2B22E206727BFE848FF42BEAC8A022048C323B0BED19A988BDBEFA974B6DE8AA9DCAE250AA82BBD1221787032A864E58114204288D2E47F8EF6C99BCC457966320D12409711E1E0107321028FFB276505F9AC3F57E8D5242B386A597EF6C40A7999F37F1948636FD484E25B744630440220680BBD745004E9CFB6B13A137F505FB92298AD309071D16C7B982825188FD1AE022004200B1F7E4A6A84BB0E4FC09E1E3BA2B66EBD32F0E6D121A34BA3B04AD99BC181147908A7F0EDD48EA896C3580A399F0EE78611C8E3E1F1",
"tx_json" : {
"Account" : "rEuLyBCvcw4CFmzv8RepSiAoNgF8tTGJQC",
"Fee" : "30000",
"Flags" : 262144,
"LimitAmount" : {
"currency" : "USD",
"issuer" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"value" : "100"
},
"Sequence" : 2,
"Signers" : [
{
"Signer" : {
"Account" : "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
"SigningPubKey" : "02B3EC4E5DD96029A647CFA20DA07FE1F85296505552CCAC114087E66B46BD77DF",
"TxnSignature" : "30450221009C195DBBF7967E223D8626CA19CF02073667F2B22E206727BFE848FF42BEAC8A022048C323B0BED19A988BDBEFA974B6DE8AA9DCAE250AA82BBD1221787032A864E5"
}
},
{
"Signer" : {
"Account" : "rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v",
"SigningPubKey" : "028FFB276505F9AC3F57E8D5242B386A597EF6C40A7999F37F1948636FD484E25B",
"TxnSignature" : "30440220680BBD745004E9CFB6B13A137F505FB92298AD309071D16C7B982825188FD1AE022004200B1F7E4A6A84BB0E4FC09E1E3BA2B66EBD32F0E6D121A34BA3B04AD99BC1"
}
}
],
"SigningPubKey" : "",
"TransactionType" : "TrustSet",
"hash" : "BD636194C48FD7A100DE4C972336534C8E710FD008C0F3CF7BC5BF34DAF3C3E6"
}
}
}
Depending on the SignerList you configured, you may need to repeat this step several times to get signatures from all the necessary parties.
4. Combine signatures and submit
If you collected the signatures in serial, the tx_json
from the last sign_for
response has all the signatures assembled, so you can use that as the argument to the submit_multisigned method.
If you collected the signatures in parallel, you must manually construct a tx_json
object with all the signatures included. Take the Signers
arrays from all the sign_for
responses, and combine their contents into a single Signers
array that has each signature. Add the combined Signers
array to the original transaction JSON value, and use that as the argument to the submit_multisigned method.
$ rippled submit_multisigned '{
> "Account" : "rEuLyBCvcw4CFmzv8RepSiAoNgF8tTGJQC",
> "Fee" : "30000",
> "Flags" : 262144,
> "LimitAmount" : {
> "currency" : "USD",
> "issuer" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
> "value" : "100"
> },
> "Sequence" : 2,
> "Signers" : [
> {
> "Signer" : {
> "Account" : "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
> "SigningPubKey" : "02B3EC4E5DD96029A647CFA20DA07FE1F85296505552CCAC114087E66B46BD77DF",
> "TxnSignature" : "30450221009C195DBBF7967E223D8626CA19CF02073667F2B22E206727BFE848FF42BEAC8A022048C323B0BED19A988BDBEFA974B6DE8AA9DCAE250AA82BBD1221787032A864E5"
> }
> },
> {
> "Signer" : {
> "Account" : "rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v",
> "SigningPubKey" : "028FFB276505F9AC3F57E8D5242B386A597EF6C40A7999F37F1948636FD484E25B",
> "TxnSignature" : "30440220680BBD745004E9CFB6B13A137F505FB92298AD309071D16C7B982825188FD1AE022004200B1F7E4A6A84BB0E4FC09E1E3BA2B66EBD32F0E6D121A34BA3B04AD99BC1"
> }
> }
> ],
> "SigningPubKey" : "",
> "TransactionType" : "TrustSet",
> "hash" : "BD636194C48FD7A100DE4C972336534C8E710FD008C0F3CF7BC5BF34DAF3C3E6"
> }'
Loading: "/etc/opt/ripple/rippled.cfg"
Connecting to 127.0.0.1:5005
{
"result": {
"engine_result": "tesSUCCESS",
"engine_result_code": 0,
"engine_result_message": "The transaction was applied. Only final in a validated ledger.",
"status": "success",
"tx_blob": "1200142200040000240000000263D5038D7EA4C680000000000000000000000000005553440000000000B5F762798A53D543A014CAF8B297CFF8F2F937E868400000000000753073008114A3780F5CB5A44D366520FC44055E8ED44D9A2270F3E010732102B3EC4E5DD96029A647CFA20DA07FE1F85296505552CCAC114087E66B46BD77DF744730450221009C195DBBF7967E223D8626CA19CF02073667F2B22E206727BFE848FF42BEAC8A022048C323B0BED19A988BDBEFA974B6DE8AA9DCAE250AA82BBD1221787032A864E58114204288D2E47F8EF6C99BCC457966320D12409711E1E0107321028FFB276505F9AC3F57E8D5242B386A597EF6C40A7999F37F1948636FD484E25B744630440220680BBD745004E9CFB6B13A137F505FB92298AD309071D16C7B982825188FD1AE022004200B1F7E4A6A84BB0E4FC09E1E3BA2B66EBD32F0E6D121A34BA3B04AD99BC181147908A7F0EDD48EA896C3580A399F0EE78611C8E3E1F1",
"tx_json": {
"Account": "rEuLyBCvcw4CFmzv8RepSiAoNgF8tTGJQC",
"Fee": "30000",
"Flags": 262144,
"LimitAmount": {
"currency": "USD",
"issuer": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"value": "100"
},
"Sequence": 2,
"Signers": [{
"Signer": {
"Account": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
"SigningPubKey": "02B3EC4E5DD96029A647CFA20DA07FE1F85296505552CCAC114087E66B46BD77DF",
"TxnSignature": "30450221009C195DBBF7967E223D8626CA19CF02073667F2B22E206727BFE848FF42BEAC8A022048C323B0BED19A988BDBEFA974B6DE8AA9DCAE250AA82BBD1221787032A864E5"
}
}, {
"Signer": {
"Account": "rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v",
"SigningPubKey": "028FFB276505F9AC3F57E8D5242B386A597EF6C40A7999F37F1948636FD484E25B",
"TxnSignature": "30440220680BBD745004E9CFB6B13A137F505FB92298AD309071D16C7B982825188FD1AE022004200B1F7E4A6A84BB0E4FC09E1E3BA2B66EBD32F0E6D121A34BA3B04AD99BC1"
}
}],
"SigningPubKey": "",
"TransactionType": "TrustSet",
"hash": "BD636194C48FD7A100DE4C972336534C8E710FD008C0F3CF7BC5BF34DAF3C3E6"
}
}
}
Take note of the hash
value from the response so you can check the results of the transaction later. (In this case, the hash is BD636194C48FD7A100DE4C972336534C8E710FD008C0F3CF7BC5BF34DAF3C3E6
.)
5. Close the ledger
If you are using the live network, you can wait 4-7 seconds for the ledger to close automatically.
If you're running rippled
in stand-alone mode, use the ledger_accept method to manually close the ledger:
$ rippled ledger_accept
Loading: "/etc/opt/ripple/rippled.cfg"
Connecting to 127.0.0.1:5005
{
"result" : {
"ledger_current_index" : 7,
"status" : "success"
}
}
6. Confirm transaction results
Use the hash value from the response to the submit_multisigned
command to look up the transaction using the tx method. In particular, check that the TransactionResult
is the string tesSUCCESS
.
On the live network, you must also confirm that the validated
field is set to the boolean true
. If the field is not true
, you might need to wait longer for the consensus process to finish; or your transaction may be unable to be included in a ledger for some reason.
In stand-alone mode, the server automatically considers a ledger to be validated
if it has been manually closed.
$ rippled tx BD636194C48FD7A100DE4C972336534C8E710FD008C0F3CF7BC5BF34DAF3C3E6
Loading: "/etc/opt/ripple/rippled.cfg"
Connecting to 127.0.0.1:5005
{
"result": {
"Account": "rEuLyBCvcw4CFmzv8RepSiAoNgF8tTGJQC",
"Fee": "30000",
"Flags": 262144,
"LimitAmount": {
"currency": "USD",
"issuer": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"value": "100"
},
"Sequence": 2,
"Signers": [{
"Signer": {
"Account": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
"SigningPubKey": "02B3EC4E5DD96029A647CFA20DA07FE1F85296505552CCAC114087E66B46BD77DF",
"TxnSignature": "30450221009C195DBBF7967E223D8626CA19CF02073667F2B22E206727BFE848FF42BEAC8A022048C323B0BED19A988BDBEFA974B6DE8AA9DCAE250AA82BBD1221787032A864E5"
}
}, {
"Signer": {
"Account": "rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v",
"SigningPubKey": "028FFB276505F9AC3F57E8D5242B386A597EF6C40A7999F37F1948636FD484E25B",
"TxnSignature": "30440220680BBD745004E9CFB6B13A137F505FB92298AD309071D16C7B982825188FD1AE022004200B1F7E4A6A84BB0E4FC09E1E3BA2B66EBD32F0E6D121A34BA3B04AD99BC1"
}
}],
"SigningPubKey": "",
"TransactionType": "TrustSet",
"date": 512172510,
"hash": "BD636194C48FD7A100DE4C972336534C8E710FD008C0F3CF7BC5BF34DAF3C3E6",
"inLedger": 6,
"ledger_index": 6,
"meta": {
"AffectedNodes": [{
"ModifiedNode": {
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8",
"PreviousTxnID": "B7E1D33DB7DEA3BB65BFAB2C80E02125F47FCCF6C957A7FDECD915B3EBE0C1DD",
"PreviousTxnLgrSeq": 4
}
}, {
"CreatedNode": {
"LedgerEntryType": "RippleState",
"LedgerIndex": "93E317B32022977C77810A2C558FBB28E30E744C68E73720622B797F957EC5FA",
"NewFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0"
},
"Flags": 2162688,
"HighLimit": {
"currency": "USD",
"issuer": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"value": "0"
},
"LowLimit": {
"currency": "USD",
"issuer": "rEuLyBCvcw4CFmzv8RepSiAoNgF8tTGJQC",
"value": "100"
}
}
}
}, {
"ModifiedNode": {
"FinalFields": {
"Account": "rEuLyBCvcw4CFmzv8RepSiAoNgF8tTGJQC",
"Balance": "999960000",
"Flags": 0,
"OwnerCount": 6,
"Sequence": 3
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "A6B1BA6F2D70813100908EA84ABB7783695050312735E2C3665259F388804EA0",
"PreviousFields": {
"Balance": "999990000",
"OwnerCount": 5,
"Sequence": 2
},
"PreviousTxnID": "8FDC18960455C196A8C4DE0D24799209A21F4A17E32102B5162BD79466B90222",
"PreviousTxnLgrSeq": 5
}
}, {
"ModifiedNode": {
"FinalFields": {
"Flags": 0,
"Owner": "rEuLyBCvcw4CFmzv8RepSiAoNgF8tTGJQC",
"RootIndex": "C2728175908D82FB1DE6676F203D8D3C056995A9FA9B369EF326523F1C65A1DE"
},
"LedgerEntryType": "DirectoryNode",
"LedgerIndex": "C2728175908D82FB1DE6676F203D8D3C056995A9FA9B369EF326523F1C65A1DE"
}
}, {
"CreatedNode": {
"LedgerEntryType": "DirectoryNode",
"LedgerIndex": "D8120FC732737A2CF2E9968FDF3797A43B457F2A81AA06D2653171A1EA635204",
"NewFields": {
"Owner": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"RootIndex": "D8120FC732737A2CF2E9968FDF3797A43B457F2A81AA06D2653171A1EA635204"
}
}
}],
"TransactionIndex": 0,
"TransactionResult": "tesSUCCESS"
},
"status": "success",
"validated": true
}
}