XRPL Manual Multi Signing in vscode

This is the place to discuss your developments on the xrpledger.
Post Reply
CoderGeeK
Posts: 9
Joined: Sat Aug 24, 2024 6:31 pm

XRPL Manual Multi Signing in vscode

Post by CoderGeeK »

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

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()
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

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()
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)

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()
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

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()
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

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()
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

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()
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

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()
write node submit-payment.js to submit the transaction. You have now sent an asset manually with multisigning.
Post Reply