XRPL Manual Multi Signing in vscode
Posted: Thu Oct 02, 2025 12:44 pm
Create 4 wallets. One wallet will be the master wallet which has 3 multisigners.
The weight is 1 per sign and weight needed is 3, meaning all signers have to sign to execute a transaction.
Vscode is needed with npm in this example. This video shows you how to install vscode and npm: https://www.youtube.com/watch?v=Xit4miSByOw
Install the xrpl package with npm i xrpl@latest
To set up the wallet itself, create this file:
multisig.js
Run this code by writing node multisig.js
You can still use your wallet after this, to make sure you can't, you need to disable your masterkey. That is a smart thing to do once you go live.
Now let me show you two examples, one is showing how to add a trustline, the other one is showing how to send a payment.
To set a trustline, first create the file
set-trustline-multisign-prepare.js
When you got the file, write node set-trustline-multisign-prepare.js, this will create a file called prepared_tx.json which will be used for signing. It has a last ledger sequence that is fairly long, so we got a few minutes of time to sign and send afterwards.
Create three files now (set-trustline-sign-1.js set-trustline-sign-2.js and set-trustline-sign-3.js) These files are all identical, but they will each have their own secret seed (signer one two and three)
Once you have prepared the set trustline procedure, you need to multi sign it.
Do so by typing
node set-trustline-sign-1.js
node set-trustline-sign-2.js
node set-trustline-sign-3.js
These will each create a file, signer1-3_blob.json. The blobs contains signatures that are valid until the last ledger sequence has passed by.
We will now submit the blobs to the xrpledger.
submit-trustline-set.js
Write node submit-trustline-set.js, and if everything worked properly, you will now see that your wallet got a multisign transaction in xrpl explorers.
Now, lets prepare a payment.
payment-prepare.js
Write node payment-prepare.js to prepare the payment to sign (prepared_payment.json)
Create 3 files, set-payment-sign-1.js, set-payment-sign-2.js and set-payment-sign-3.js
write
node set-payment-sign-1.js
node set-payment-sign-2.js
node set-payment-sign-3.js
You will then have your blobs, after that we will just submit the payment.
submit-payment.js
write node submit-payment.js to submit the transaction. You have now sent an asset manually with multisigning.
The weight is 1 per sign and weight needed is 3, meaning all signers have to sign to execute a transaction.
Vscode is needed with npm in this example. This video shows you how to install vscode and npm: https://www.youtube.com/watch?v=Xit4miSByOw
Install the xrpl package with npm i xrpl@latest
To set up the wallet itself, create this file:
multisig.js
Code: Select all
const xrpl = require("xrpl")
async function main() {
const client = new xrpl.Client("wss://s.altnet.rippletest.net:51233") //use whatever network you use here
await client.connect()
const masterSeed = "masterseedhere" //start with s
const masterWallet = xrpl.Wallet.fromSeed(masterSeed)
console.log("Master Wallet Address:", masterWallet.address)
const signer1 = xrpl.Wallet.fromSeed("signerseed1") //starts with s
const signer2 = xrpl.Wallet.fromSeed("signerseed2") //starts with s
const signer3 = xrpl.Wallet.fromSeed("signerseed3") //starts with s
console.log("Signer1:", signer1.address)
console.log("Signer2:", signer2.address)
console.log("Signer3:", signer3.address)
const signerListTx = {
TransactionType: "SignerListSet",
Account: masterWallet.address,
SignerQuorum: 3,
SignerEntries: [
{ SignerEntry: { Account: signer1.address, SignerWeight: 1 } },
{ SignerEntry: { Account: signer2.address, SignerWeight: 1 } },
{ SignerEntry: { Account: signer3.address, SignerWeight: 1 } },
],
}
const prepared = await client.autofill(signerListTx)
const signed = masterWallet.sign(prepared)
const result = await client.submitAndWait(signed.tx_blob)
console.log("Raw result:", JSON.stringify(result, null, 2))
console.log("Transaction result:", result.result.engine_result)
await client.disconnect()
}
main()
You can still use your wallet after this, to make sure you can't, you need to disable your masterkey. That is a smart thing to do once you go live.
Now let me show you two examples, one is showing how to add a trustline, the other one is showing how to send a payment.
To set a trustline, first create the file
set-trustline-multisign-prepare.js
Code: Select all
const fs = require("fs")
const xrpl = require("xrpl")
async function main() {
const client = new xrpl.Client("wss://s.altnet.rippletest.net:51233")
await client.connect()
const master = xrpl.Wallet.fromSeed("masterseed here")
const trustSetTx = {
TransactionType: "TrustSet",
Account: master.address,
LimitAmount: {
currency: "524C555344000000000000000000000000000000", //in this example set a random testnet asset
issuer: "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", //in this example set a random testnet asset
value: "1000000000"
}
}
const prepared = await client.autofill(trustSetTx, { fee_mult_max: 4 })
prepared.Fee = (parseInt(prepared.Fee, 10) * 20).toString()
prepared.LastLedgerSequence = prepared.LastLedgerSequence + 100
fs.writeFileSync("prepared_tx.json", JSON.stringify(prepared, null, 2))
console.log("Prepared TX saved to prepared_tx.json")
await client.disconnect()
}
main()
Create three files now (set-trustline-sign-1.js set-trustline-sign-2.js and set-trustline-sign-3.js) These files are all identical, but they will each have their own secret seed (signer one two and three)
Code: Select all
const fs = require("fs")
const xrpl = require("xrpl")
async function main() {
const prepared = JSON.parse(fs.readFileSync("prepared_tx.json"))
const signer1 = xrpl.Wallet.fromSeed("the signers secret seeds") //add the secret seed for each signer
const signed = signer1.sign(prepared, true)
fs.writeFileSync("signer1_blob.json", JSON.stringify(signed, null, 2))
console.log("signer1_blob.json written with tx_blob")
}
main()
Do so by typing
node set-trustline-sign-1.js
node set-trustline-sign-2.js
node set-trustline-sign-3.js
These will each create a file, signer1-3_blob.json. The blobs contains signatures that are valid until the last ledger sequence has passed by.
We will now submit the blobs to the xrpledger.
submit-trustline-set.js
Code: Select all
const fs = require("fs")
const xrpl = require("xrpl")
async function main() {
const client = new xrpl.Client("wss://s.altnet.rippletest.net:51233")
await client.connect()
const sig1 = JSON.parse(fs.readFileSync("signer1_blob.json"))
const sig2 = JSON.parse(fs.readFileSync("signer2_blob.json"))
const sig3 = JSON.parse(fs.readFileSync("signer3_blob.json"))
const blobs = [sig1.tx_blob, sig2.tx_blob, sig3.tx_blob]
const multisigned = xrpl.multisign(blobs)
console.log("Multisigned blob:", multisigned)
const result = await client.submitAndWait(multisigned)
console.log("Raw submit result:", JSON.stringify(result, null, 2))
if (result.result?.tx_json?.hash) {
const txHash = result.result.tx_json.hash
const txResponse = await client.request({
command: "tx",
transaction: txHash
})
console.log("Transaction lookup:", JSON.stringify(txResponse, null, 2))
}
await client.disconnect()
}
main()
Now, lets prepare a payment.
payment-prepare.js
Code: Select all
const fs = require("fs")
const xrpl = require("xrpl")
async function main() {
const client = new xrpl.Client("wss://s.altnet.rippletest.net:51233")
await client.connect()
const sender = xrpl.Wallet.fromSeed("the master seed") // multisigned wallet
const paymentTx = {
TransactionType: "Payment",
Account: sender.address,
Destination: "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", //a random receiver
//Amount: "1000000" // If you use it for xrp, use it this way (counted in drops in this particular example, that is not always the thing).
Amount: {
currency: "524C555344000000000000000000000000000000", // a currency we got a trustline for
issuer: "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", //a currency we got a trustline for
value: "1" // when sending other currencies and not xrp, they are not counted in drops, this is 1 unit of the currency being sent
}
}
const prepared = await client.autofill(paymentTx, { fee_mult_max: 4 })
prepared.Fee = (parseInt(prepared.Fee, 10) * 20).toString()
prepared.LastLedgerSequence = prepared.LastLedgerSequence + 100
fs.writeFileSync("prepared_payment.json", JSON.stringify(prepared, null, 2))
console.log("Prepared payment saved to prepared_payment.json")
await client.disconnect()
}
main()
Create 3 files, set-payment-sign-1.js, set-payment-sign-2.js and set-payment-sign-3.js
Code: Select all
const fs = require("fs")
const xrpl = require("xrpl")
async function main() {
const prepared = JSON.parse(fs.readFileSync("prepared_payment.json"))
const signer1 = xrpl.Wallet.fromSeed("signer seed") //add the signer seeds here
const signed = signer1.sign(prepared, true)
fs.writeFileSync("signer1_payment.json", JSON.stringify(signed, null, 2))
console.log("signer1_payment.json written with tx_blob")
}
main()
node set-payment-sign-1.js
node set-payment-sign-2.js
node set-payment-sign-3.js
You will then have your blobs, after that we will just submit the payment.
submit-payment.js
Code: Select all
const fs = require("fs")
const xrpl = require("xrpl")
async function main() {
const client = new xrpl.Client("wss://s.altnet.rippletest.net:51233")
await client.connect()
const sig1 = JSON.parse(fs.readFileSync("signer1_payment.json"))
const sig2 = JSON.parse(fs.readFileSync("signer2_payment.json"))
const sig3 = JSON.parse(fs.readFileSync("signer3_payment.json"))
const multisigned = xrpl.multisign([sig1.tx_blob, sig2.tx_blob, sig3.tx_blob])
console.log("Multisigned blob:", multisigned)
const result = await client.submitAndWait(multisigned)
console.log("Payment result:", JSON.stringify(result, null, 2))
await client.disconnect()
}
main()