Set Up an XRP-XRP Bridge
(Requires the XChainBridge amendment )
Setting up an XRP-XRP bridge enables you to move XRP between chains. The set up requires using the genesis account on the issuing chain as a door account to submit attestations and create transaction submission accounts for witnesses.
Note: The code samples on this page illustrate how a bridge was set up between Devnet and Sidechain-Devnet, using a supported client library to query and submit transactions. This bridge is already created, so the process can't be reproduced on these networks.
Prerequisites
- The issuing chain is set up and active. Validators must be running and successfully closing ledgers.
- The witnesses' accounts on the locking chain are funded, so they can submit transactions.
- A door account for the bridge exists on the locking chain.
Steps
1. Connect to the locking chain (Devnet) and issuing chain (Sidechain-Devnet).
const xrpl = require('xrpl')
const WS_URL_lockingchain = 'wss://s.devnet.rippletest.net:51233/' // Locking chain
const WS_URL_issuingchain = 'wss://sidechain-net2.devnet.rippletest.net:51233/' // Issuing chain
// Define the XChainBridge
const xchainbridge = {
"LockingChainDoor": "rnQAXXWoFNN6PEqwqsdTngCtFPCrmfuqFJ", // Locking chain door account
"LockingChainIssue": {
"currency": "XRP"
},
"IssuingChainDoor": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", // Use the genesis address hardcoded in rippled
"IssuingChainIssue": {
"currency": "XRP"
}
}
async function main() {
// Define the network clients.
const client_lockingchain = new xrpl.Client(WS_URL_lockingchain)
await client_lockingchain.connect()
const client_issuingchain = new xrpl.Client(WS_URL_issuingchain)
await client_issuingchain.connect()
// ... custom code goes here
// Disconnect when done (If you omit this, Node.js won't end the process)
await client_lockingchain.disconnect()
await client_issuingchain.disconnect()
}
main()
2. Submit an XChainCreateBridge
transaction from the door account on the locking chain.
const wallet_lockingchain = xrpl.Wallet.fromSeed('s████████████████████████████') // Locking chain door account
const xchaincreatebridge_lockingchain = await client_lockingchain.submitAndWait({
"TransactionType": "XChainCreateBridge",
"Account": wallet_lockingchain.address,
"XChainBridge": xchainbridge,
"SignatureReward": 200,
"MinAccountCreateAmount": 1000000 // This value should at least be equal to the account reserve on the issuing chain.
}, {autofill: true, wallet: wallet_lockingchain})
3. Submit a SignerListSet
transaction from the door account on the locking chain.
const signerlistset_lockingchain = await client_lockingchain.submitAndWait({
"TransactionType": "SignerListSet",
"Account": wallet_lockingchain.address,
"Fee": "12",
"SignerQuorum": 2,
// Use the witness servers' submitting accounts on the locking chain.
"SignerEntries": [
{
"SignerEntry": {
"Account": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
"SignerWeight": 1
}
},
{
"SignerEntry": {
"Account": "rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v",
"SignerWeight": 1
}
}
]
}, {autofill: true, wallet: wallet_lockingchain})
4. Disable the master key on the locking chain's door account with an AccountSet
transaction.
const disablekey_lockingchain = await client_lockingchain.submitAndWait({
"TransactionType": "AccountSet",
"Account": wallet_lockingchain.address,
"SetFlag": 4
}, {autofill: true, wallet: wallet_lockingchain})
5. Submit an XChainCreateBridge
transaction from the genesis account on the issuing chain.
const wallet_issuingchain = xrpl.Wallet.fromSeed('snoPBrXtMeMyMHUVTgbuqAfg1SUTb') // Use the genesis secret hardcoded in rippled.
const xchaincreatebridge_issuingchain = await client_issuingchain.submitAndWait({
"TransactionType": "XChainCreateBridge",
"Account": wallet_issuingchain.address,
"XChainBridge": xchainbridge,
"SignatureReward": 200,
"MinAccountCreateAmount": 1000000
}, {autofill: true, wallet: wallet_issuingchain})
6. Submit XChainAccountCreateCommit
transactions from the witnesses' locking chain accounts to create corresponding accounts on the issuing chain.
const wallet_witness_1 = xrpl.Wallet.fromSeed('s████████████████████████████') // Witness server 1 from `SignerListSet`: rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW
const wallet_witness_2 = xrpl.Wallet.fromSeed('s████████████████████████████') // Witness server 2 from `SignerListSet`: rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v
const xchainaccountcreatecommit_witness_1 = await client_lockingchain.submitAndWait({
"TransactionType": "XChainAccountCreateCommit",
"Account": wallet_witness_1.address,
"Destination": "rD323VyRjgzzhY4bFpo44rmyh2neB5d8Mo", // The account to create and fund for witness 1 on the issuing chain.
"TransactionType": "XChainAccountCreateCommit",
"Amount": "20000000",
"SignatureReward": "100",
"XChainBridge": xchainbridge
}, {autofill: true, wallet: wallet_witness_1})
const xchainaccountcreatecommit_witness_2 = await client_lockingchain.submitAndWait({
"TransactionType": "XChainAccountCreateCommit",
"Account": wallet_witness_2.address,
"Destination": "rJMfWNVbyjcCtds8kpoEjEbYQ41J5B6MUd", // The account to create and fund for witness 2 on the issuing chain.
"TransactionType": "XChainAccountCreateCommit",
"Amount": "20000000",
"SignatureReward": "100",
"XChainBridge": xchainbridged
}, {autofill: true, wallet: wallet_witness_1})
7. Submit attestations for each XChainAccountCreateCommit
transaction.
Use the XChainAddAccountCreateAttestation
transaction to submit each attestation on the issuing chain. Sign these transactions with the genesis account on the issuing chain.
// Witness 1 attestation
const xchainaddaccountcreateattestation_witness_1 = await client_issuingchain.submitAndWait({
"TransactionType": "XChainAddAccountCreateAttestation",
"Account": wallet_issuingchain.address,
"OtherChainSource": wallet_witness_1.address,
"Destination": "rD323VyRjgzzhY4bFpo44rmyh2neB5d8Mo",
"Amount": "2000000000",
"PublicKey": wallet_witness_1.publicKey,
"Signature": xchainaccountcreatecommit_witness_1.result.TxnSignature,
"WasLockingChainSend": 1,
"AttestationRewardAccount": "rD323VyRjgzzhY4bFpo44rmyh2neB5d8Mo",
"AttestationSignerAccount": wallet_witness_1.address,
"XChainAccountCreateCount": "1",
"SignatureReward": "204",
"XChainBridge": xchainbridge,
"Fee": "20"
}, {autofill: true, wallet: wallet_issuingchain})
// Witness 2 attestation
const xchainaddaccountcreateattestation_witness_2 = await client_issuingchain.submitAndWait({
"TransactionType": "XChainAddAccountCreateAttestation",
"Account": wallet_issuingchain.address,
"OtherChainSource": wallet_witness_2.address,
"Destination": "rJMfWNVbyjcCtds8kpoEjEbYQ41J5B6MUd",
"Amount": "2000000000",
"PublicKey": wallet_witness_2.publicKey,
"Signature": xchainaccountcreatecommit_witness_2.result.TxnSignature,
"WasLockingChainSend": 1,
"AttestationRewardAccount": "rJMfWNVbyjcCtds8kpoEjEbYQ41J5B6MUd",
"AttestationSignerAccount": wallet_witness_2.address,
"XChainAccountCreateCount": "1",
"SignatureReward": "204",
"XChainBridge": xchainbridge,
"Fee": "20"
}, {autofill: true, wallet: wallet_issuingchain})
8. Submit a SignerListSet
transaction from the genesis account on the issuing chain.
const signerlistset_issuingchain = await client_issuingchain.submitAndWait({
"TransactionType": "SignerListSet",
"Account": wallet_issuingchain.address,
"Fee": "12",
"SignerQuorum": 2,
// Use the witness servers' submitting accounts on the issuing chain created in step 7
"SignerEntries": [
{
"SignerEntry": {
"Account": "rD323VyRjgzzhY4bFpo44rmyh2neB5d8Mo",
"SignerWeight": 1
}
},
{
"SignerEntry": {
"Account": "rJMfWNVbyjcCtds8kpoEjEbYQ41J5B6MUd",
"SignerWeight": 1
}
}
]
}, {autofill: true, wallet: wallet_issuingchain})
9. Disable the master key on the issuing chain's genesis account with an AccountSet
transaction.
const disablekey_issuingchain = await client_issuingchain.submitAndWait({
"TransactionType": "AccountSet",
"Account": wallet_issuingchain.address,
"SetFlag": 4
}, {autofill: true, wallet: wallet_issuingchain})