# 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](/es-es/docs/tutorials/how-tos/manage-account-settings/set-up-multi-signing) for your address. - Multi-signing must be available. Multi-signing has been enabled by an [**Amendment**](/es-es/docs/concepts/networks-and-servers/amendments) 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](/es-es/docs/concepts/transactions/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](/es-es/docs/concepts/transactions/transaction-cost) increases in that time. Here's an example transaction ready to be multi-signed: JSON ```json { "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.) Javascript const accountSet: AccountSet = { TransactionType: 'AccountSet', Account: walletMaster.classicAddress, Domain: convertStringToHex('example.com'), } const accountSetTx = await client.autofill(accountSet, 2) console.log('AccountSet transaction is ready to be multisigned:') console.log(accountSetTx) Python account_set_tx = AccountSet( account=master_wallet.address, domain=str_to_hex("example.com") ) autofilled_account_set_tx = autofill(account_set_tx, client, len(signer_entries)) print("AccountSet transaction is ready to be multisigned") print(autofilled_account_set_tx) ## 2. Get one signature Use the [sign_for method](/docs/references/http-websocket-apis/admin-api-methods/signing-methods/sign_for) 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 '{ > "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](/es-es/docs/infrastructure/testing-and-auditing/start-a-new-genesis-ledger-in-stand-alone-mode#settings-in-new-genesis-ledgers). ## 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 the `Signers` array. * In serial: Use the `sign_for` command with the `tx_json` value from the previous `sign_for` response. Each response adds a new signature to the existing `Signers` 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 '{ > "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](/docs/references/http-websocket-apis/public-api-methods/transaction-methods/submit_multisigned). 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](/docs/references/http-websocket-apis/public-api-methods/transaction-methods/submit_multisigned). Commandline ``` $ 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`.) Javascript const { tx_blob: tx_blob1 } = wallet1.sign(accountSetTx, true) const { tx_blob: tx_blob2 } = wallet2.sign(accountSetTx, true) const multisignedTx = multisign([tx_blob1, tx_blob2]) console.log("Successfully multisigned the transaction") console.log(multisignedTx) const submitResponse = await client.submit(multisignedTx) Python tx_1 = sign(autofilled_account_set_tx, signer_wallet_1, multisign=True) tx_2 = sign(autofilled_account_set_tx, signer_wallet_2, multisign=True) multisigned_tx = multisign(autofilled_account_set_tx, [tx_1, tx_2]) print("Successfully multisigned the transaction") print(multisigned_tx) multisigned_tx_response = client.request(SubmitMultisigned(tx_json=multisigned_tx)) ## 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](/docs/references/http-websocket-apis/admin-api-methods/server-control-methods/ledger_accept) 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](/docs/references/http-websocket-apis/public-api-methods/transaction-methods/tx). 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. Commandline ``` $ 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 } } ``` Javascript if (submitResponse.result.engine_result === 'tesSUCCESS') { console.log('The multisigned transaction was accepted by the ledger:') console.log(submitResponse) if (submitResponse.result.tx_json.Signers) { console.log( `The transaction had ${submitResponse.result.tx_json.Signers.length} signatures`, ) } } else { console.log( "The multisigned transaction was rejected by rippled. Here's the response from rippled:", ) console.log(submitResponse) } Python if multisigned_tx_response.result["engine_result"] == "tesSUCCESS": print("The multisigned transaction was accepted by the ledger:") print(multisigned_tx_response) if multisigned_tx_response.result["tx_json"]["Signers"]: print( "The transaction had " f"{len(multisigned_tx_response.result['tx_json']['Signers'])} signatures" ) else: print( "The multisigned transaction was rejected by rippled." "Here's the response from rippled:" ) print(multisigned_tx_response)