test: add integration tests for sidechain transactions (#2301)

* add XChainCreateBridge integration test

* add XChainCreateClaimID integration test

* add XChainCommit integration test

* add XChainAccountCreateCommit integration test

* simplify tests

* add XChainModifyBridge integration test

* add XChainAddAccountCreateAttestation integration test

* add XChainAddClaimAttestation integration test

* improve SignerListSet integration test

* rename variable to match

* add XChainClaim integration test

* clean up

* add IOU attestation test

* fix integration tests issues

* minor refactors

* fix bug

* [WIP] switch to one bridge for all integration tests

* clean up

* fix tests

* fix + clean up tests
This commit is contained in:
Mayukha Vadari
2023-10-25 10:08:58 -04:00
committed by GitHub
parent a11924b8fc
commit 68beac73d1
16 changed files with 966 additions and 37 deletions

View File

@@ -67,7 +67,10 @@ class XChainBridge extends SerializedType {
return value
}
if (isXChainBridgeObject(value)) {
if (!isXChainBridgeObject(value)) {
throw new Error('Invalid type to construct an XChainBridge')
}
const bytes: Array<Buffer> = []
this.TYPE_ORDER.forEach((item) => {
const { name, type } = item
@@ -80,9 +83,6 @@ class XChainBridge extends SerializedType {
return new XChainBridge(Buffer.concat(bytes))
}
throw new Error('Invalid type to construct an XChainBridge')
}
/**
* Read an XChainBridge from a BinaryParser
*

View File

@@ -22,13 +22,6 @@ export default interface Bridge extends BaseLedgerEntry, HasPreviousTxnID {
*/
SignatureReward: Amount
/**
* The minimum amount, in XRP, required for an {@link XChainAccountCreateCommit}
* transaction. If this isn't present, the {@link XChainAccountCreateCommit}
* transaction will fail. This field can only be present on XRP-XRP bridges.
*/
MinAccountCreateAmount?: string
/**
* The door accounts and assets of the bridge this object correlates to.
*/
@@ -58,6 +51,13 @@ export default interface Bridge extends BaseLedgerEntry, HasPreviousTxnID {
*/
XChainAccountClaimCount: string
/**
* The minimum amount, in XRP, required for an {@link XChainAccountCreateCommit}
* transaction. If this isn't present, the {@link XChainAccountCreateCommit}
* transaction will fail. This field can only be present on XRP-XRP bridges.
*/
MinAccountCreateAmount?: string
/**
* A bit-map of boolean flags. No flags are defined for Bridges, so this value
* is always 0.

View File

@@ -14,7 +14,7 @@ import {
* The XChainAccountCreateCommit transaction creates a new account on one of the
* chains a bridge connects, which serves as the bridge entrance for that chain.
*
* Warning: This transaction should only be executed if the witness attestations
* WARNING: This transaction should only be executed if the witness attestations
* will be reliably delivered to the destination chain. If the signatures aren't
* delivered, then account creation will be blocked until attestations are received.
* This can be used maliciously; to disable this transaction on XRP-XRP bridges,

View File

@@ -21,7 +21,7 @@ async function generate_faucet_wallet_and_fund_again(
faucetPath,
usageContext: 'integration-test',
})
assert.notEqual(wallet, undefined)
assert.notStrictEqual(wallet, undefined)
assert(isValidClassicAddress(wallet.classicAddress))
assert(isValidXAddress(wallet.getXAddress()))
@@ -103,7 +103,7 @@ describe('fundWallet', function () {
usageContext: 'integration-test',
})
assert.notEqual(wallet, undefined)
assert.notStrictEqual(wallet, undefined)
assert(isValidClassicAddress(wallet.classicAddress))
assert(isValidXAddress(wallet.getXAddress()))
@@ -137,7 +137,7 @@ describe('fundWallet', function () {
usageContext: 'integration-test',
})
assert.equal(balance, '2000')
assert.notEqual(wallet, undefined)
assert.notStrictEqual(wallet, undefined)
assert(isValidClassicAddress(wallet.classicAddress))
assert(isValidXAddress(wallet.getXAddress()))

View File

@@ -19,6 +19,14 @@ export * from './transactions/paymentChannelCreate.test'
export * from './transactions/paymentChannelFund.test'
export * from './transactions/signerListSet.test'
export * from './transactions/trustSet.test'
export * from './transactions/xchainAccountCreateCommit.test'
export * from './transactions/xchainAddAccountCreateAttestation.test'
export * from './transactions/xchainAddClaimAttestation.test'
export * from './transactions/xchainClaim.test'
export * from './transactions/xchainCreateBridge.test'
export * from './transactions/xchainCreateClaimID.test'
export * from './transactions/xchainCommit.test'
export * from './transactions/xchainModifyBridge.test'
// Requests
export * from './requests/accountChannels.test'

View File

@@ -1,7 +1,26 @@
import { Client, Wallet } from '../../src'
import { assert } from 'chai'
import {
Client,
SignerListSet,
Wallet,
XChainBridge,
XChainCreateBridge,
} from '../../src'
import serverUrl from './serverUrl'
import { fundAccount } from './utils'
import {
GENESIS_ACCOUNT,
fundAccount,
generateFundedWallet,
testTransaction,
} from './utils'
interface TestBridge {
xchainBridge: XChainBridge
witness: Wallet
signatureReward: string
}
export interface XrplIntegrationTestContext {
client: Client
@@ -32,15 +51,86 @@ async function connectWithRetry(client: Client, tries = 0): Promise<void> {
export async function setupClient(
server = serverUrl,
): Promise<XrplIntegrationTestContext> {
const context: XrplIntegrationTestContext = {
client: new Client(server, { timeout: 200000 }),
wallet: Wallet.generate(),
}
return connectWithRetry(context.client).then(async () => {
await fundAccount(context.client, context.wallet, {
const client = new Client(server, { timeout: 200000 })
const wallet = Wallet.generate()
return connectWithRetry(client).then(async () => {
await fundAccount(client, wallet, {
count: 20,
delayMs: 1000,
})
const context: XrplIntegrationTestContext = {
client,
wallet,
}
return context
})
}
export async function setupBridge(client: Client): Promise<TestBridge> {
const doorAccount = await generateFundedWallet(client)
const signatureReward = '200'
const xchainBridge: XChainBridge = {
LockingChainDoor: doorAccount.classicAddress,
LockingChainIssue: { currency: 'XRP' },
IssuingChainDoor: GENESIS_ACCOUNT,
IssuingChainIssue: { currency: 'XRP' },
}
const setupTx: XChainCreateBridge = {
TransactionType: 'XChainCreateBridge',
Account: doorAccount.classicAddress,
XChainBridge: xchainBridge,
SignatureReward: signatureReward,
MinAccountCreateAmount: '10000000',
}
await testTransaction(client, setupTx, doorAccount)
// confirm that the transaction actually went through
const accountObjectsResponse = await client.request({
command: 'account_objects',
account: doorAccount.classicAddress,
type: 'bridge',
})
assert.lengthOf(
accountObjectsResponse.result.account_objects,
1,
'Should be exactly one bridge owned by the account',
)
const witnessWallet = await generateFundedWallet(client)
const signerTx: SignerListSet = {
TransactionType: 'SignerListSet',
Account: doorAccount.classicAddress,
SignerEntries: [
{
SignerEntry: {
Account: witnessWallet.classicAddress,
SignerWeight: 1,
},
},
],
SignerQuorum: 1,
}
await testTransaction(client, signerTx, doorAccount)
const signerAccountInfoResponse = await client.request({
command: 'account_info',
account: doorAccount.classicAddress,
signer_lists: true,
})
const signerListInfo =
signerAccountInfoResponse.result.account_data.signer_lists?.[0]
assert.deepEqual(
signerListInfo?.SignerEntries,
signerTx.SignerEntries,
'SignerEntries were not set properly',
)
assert.equal(
signerListInfo?.SignerQuorum,
signerTx.SignerQuorum,
'SignerQuorum was not set properly',
)
return { xchainBridge, witness: witnessWallet, signatureReward }
}

View File

@@ -1,3 +1,5 @@
import { assert } from 'chai'
import { SignerListSet } from '../../../src'
import serverUrl from '../serverUrl'
import {
@@ -42,6 +44,24 @@ describe('SignerListSet', function () {
SignerQuorum: 2,
}
await testTransaction(testContext.client, tx, testContext.wallet)
const accountInfoResponse = await testContext.client.request({
command: 'account_info',
account: testContext.wallet.classicAddress,
signer_lists: true,
})
const signerListInfo =
accountInfoResponse.result.account_data.signer_lists?.[0]
assert.deepEqual(
signerListInfo?.SignerEntries,
tx.SignerEntries,
'SignerEntries were not set properly',
)
assert.equal(
signerListInfo?.SignerQuorum,
tx.SignerQuorum,
'SignerQuorum was not set properly',
)
},
TIMEOUT,
)

View File

@@ -0,0 +1,64 @@
import { assert } from 'chai'
import { XChainAccountCreateCommit, Wallet } from '../../../src'
import serverUrl from '../serverUrl'
import {
setupClient,
teardownClient,
type XrplIntegrationTestContext,
setupBridge,
} from '../setup'
import { generateFundedWallet, getXRPBalance, testTransaction } from '../utils'
// how long before each test case times out
const TIMEOUT = 20000
describe('XChainAccountCreateCommit', function () {
let testContext: XrplIntegrationTestContext
beforeEach(async () => {
testContext = await setupClient(serverUrl)
})
afterEach(async () => teardownClient(testContext))
it(
'base',
async () => {
const { xchainBridge, signatureReward } = await setupBridge(
testContext.client,
)
const initialBalance = Number(
await getXRPBalance(testContext.client, xchainBridge.LockingChainDoor),
)
// actually test XChainAccountCreateCommit
const wallet2 = await generateFundedWallet(testContext.client)
const destination = Wallet.generate()
const amount = 10000000
const tx: XChainAccountCreateCommit = {
TransactionType: 'XChainAccountCreateCommit',
Account: wallet2.classicAddress,
XChainBridge: xchainBridge,
Amount: amount.toString(),
SignatureReward: signatureReward,
Destination: destination.classicAddress,
}
await testTransaction(testContext.client, tx, wallet2)
const accountInfoResponse2 = await testContext.client.request({
command: 'account_info',
account: xchainBridge.LockingChainDoor,
})
const finalBalance = Number(
accountInfoResponse2.result.account_data.Balance,
)
assert.equal(
finalBalance,
initialBalance + amount + Number(signatureReward),
"The bridge door's balance should go up by the amount committed",
)
},
TIMEOUT,
)
})

View File

@@ -0,0 +1,76 @@
import { encode } from 'ripple-binary-codec'
import { sign } from 'ripple-keypairs'
import {
Wallet,
XChainAddAccountCreateAttestation,
xrpToDrops,
} from '../../../src'
import serverUrl from '../serverUrl'
import {
setupBridge,
setupClient,
teardownClient,
type XrplIntegrationTestContext,
} from '../setup'
import { testTransaction } from '../utils'
// how long before each test case times out
const TIMEOUT = 20000
describe('XChainCreateBridge', function () {
let testContext: XrplIntegrationTestContext
beforeEach(async () => {
testContext = await setupClient(serverUrl)
})
afterEach(async () => teardownClient(testContext))
it(
'base',
async () => {
const { xchainBridge, witness, signatureReward } = await setupBridge(
testContext.client,
)
const destination = Wallet.generate()
const otherChainSource = Wallet.generate()
const attestationToSign = {
XChainBridge: xchainBridge,
OtherChainSource: otherChainSource.classicAddress,
Amount: xrpToDrops(300),
AttestationRewardAccount: witness.classicAddress,
WasLockingChainSend: 0,
XChainAccountCreateCount: 1,
Destination: destination.classicAddress,
SignatureReward: signatureReward,
}
const encodedAttestation = encode(attestationToSign)
const attestationSignature = sign(encodedAttestation, witness.privateKey)
const tx: XChainAddAccountCreateAttestation = {
TransactionType: 'XChainAddAccountCreateAttestation',
Account: testContext.wallet.classicAddress,
XChainBridge: xchainBridge,
OtherChainSource: otherChainSource.classicAddress,
Amount: xrpToDrops(300),
WasLockingChainSend: 0,
XChainAccountCreateCount: 1,
Destination: destination.classicAddress,
SignatureReward: signatureReward,
PublicKey: witness.publicKey,
Signature: attestationSignature,
AttestationRewardAccount: witness.classicAddress,
AttestationSignerAccount: witness.classicAddress,
}
await testTransaction(testContext.client, tx, testContext.wallet)
// should not throw
await testContext.client.request({
command: 'account_info',
account: destination.classicAddress,
})
},
TIMEOUT,
)
})

View File

@@ -0,0 +1,274 @@
/* eslint-disable max-statements -- necessary because transfers require a lot of steps */
import { assert } from 'chai'
import { encode } from 'ripple-binary-codec'
import { sign } from 'ripple-keypairs'
import {
AccountSet,
AccountSetAsfFlags,
IssuedCurrency,
IssuedCurrencyAmount,
SignerListSet,
TrustSet,
Wallet,
XChainAddClaimAttestation,
XChainBridge,
XChainCreateBridge,
XChainCreateClaimID,
xrpToDrops,
} from '../../../src'
import serverUrl from '../serverUrl'
import {
setupBridge,
setupClient,
teardownClient,
type XrplIntegrationTestContext,
} from '../setup'
import {
generateFundedWallet,
getIOUBalance,
getXRPBalance,
testTransaction,
} from '../utils'
// how long before each test case times out
const TIMEOUT = 20000
describe('XChainCreateBridge', function () {
let testContext: XrplIntegrationTestContext
beforeEach(async () => {
testContext = await setupClient(serverUrl)
})
afterEach(async () => teardownClient(testContext))
it(
'base',
async () => {
const { xchainBridge, witness, signatureReward } = await setupBridge(
testContext.client,
)
const otherChainSource = Wallet.generate()
const amount = xrpToDrops(10)
const claimIdTx: XChainCreateClaimID = {
TransactionType: 'XChainCreateClaimID',
Account: testContext.wallet.classicAddress,
XChainBridge: xchainBridge,
SignatureReward: signatureReward,
OtherChainSource: otherChainSource.classicAddress,
}
await testTransaction(testContext.client, claimIdTx, testContext.wallet)
const initialBalance = Number(
await getXRPBalance(testContext.client, testContext.wallet),
)
const attestationToSign = {
XChainBridge: xchainBridge,
OtherChainSource: otherChainSource.classicAddress,
Amount: amount,
AttestationRewardAccount: witness.classicAddress,
WasLockingChainSend: 0,
XChainClaimID: 1,
Destination: testContext.wallet.classicAddress,
}
const encodedAttestation = encode(attestationToSign)
const attestationSignature = sign(encodedAttestation, witness.privateKey)
const tx: XChainAddClaimAttestation = {
TransactionType: 'XChainAddClaimAttestation',
Account: witness.classicAddress,
XChainBridge: xchainBridge,
OtherChainSource: otherChainSource.classicAddress,
Amount: amount,
WasLockingChainSend: 0,
XChainClaimID: 1,
Destination: testContext.wallet.classicAddress,
PublicKey: witness.publicKey,
Signature: attestationSignature,
AttestationRewardAccount: witness.classicAddress,
AttestationSignerAccount: witness.classicAddress,
}
await testTransaction(testContext.client, tx, witness)
const finalBalance = Number(
await getXRPBalance(testContext.client, testContext.wallet),
)
assert.equal(
finalBalance,
initialBalance + Number(amount) - Number(signatureReward),
'The destination balance should go up by the amount transferred',
)
},
TIMEOUT,
)
it(
'IOU',
async () => {
const witness = await generateFundedWallet(testContext.client)
// we are on the "issuing chain" for this test
const lockingDoor = Wallet.generate()
const issuer = Wallet.generate()
// set default rippling
const defaultRipplingTx: AccountSet = {
TransactionType: 'AccountSet',
Account: testContext.wallet.classicAddress,
SetFlag: AccountSetAsfFlags.asfDefaultRipple,
}
await testTransaction(
testContext.client,
defaultRipplingTx,
testContext.wallet,
)
const destination = await generateFundedWallet(testContext.client)
const trustlineTx: TrustSet = {
TransactionType: 'TrustSet',
Account: destination.classicAddress,
LimitAmount: {
currency: 'USD',
issuer: testContext.wallet.classicAddress,
value: '1000000000',
},
}
await testTransaction(testContext.client, trustlineTx, destination)
const signatureReward = '200'
const xchainBridge: XChainBridge = {
LockingChainDoor: lockingDoor.classicAddress,
LockingChainIssue: {
currency: 'USD',
issuer: issuer.classicAddress,
},
IssuingChainDoor: testContext.wallet.classicAddress,
IssuingChainIssue: {
currency: 'USD',
issuer: testContext.wallet.classicAddress,
},
}
const setupTx: XChainCreateBridge = {
TransactionType: 'XChainCreateBridge',
Account: testContext.wallet.classicAddress,
XChainBridge: xchainBridge,
SignatureReward: signatureReward,
}
await testTransaction(testContext.client, setupTx, testContext.wallet)
// confirm that the transaction actually went through
const accountObjectsResponse = await testContext.client.request({
command: 'account_objects',
account: testContext.wallet.classicAddress,
type: 'bridge',
})
assert.lengthOf(
accountObjectsResponse.result.account_objects,
1,
'Should be exactly one bridge owned by the account',
)
const signerTx: SignerListSet = {
TransactionType: 'SignerListSet',
Account: testContext.wallet.classicAddress,
SignerEntries: [
{
SignerEntry: {
Account: witness.classicAddress,
SignerWeight: 1,
},
},
],
SignerQuorum: 1,
}
await testTransaction(testContext.client, signerTx, testContext.wallet)
const signerAccountInfoResponse = await testContext.client.request({
command: 'account_info',
account: testContext.wallet.classicAddress,
signer_lists: true,
})
const signerListInfo =
signerAccountInfoResponse.result.account_data.signer_lists?.[0]
assert.deepEqual(
signerListInfo?.SignerEntries,
signerTx.SignerEntries,
'SignerEntries were not set properly',
)
assert.equal(
signerListInfo?.SignerQuorum,
signerTx.SignerQuorum,
'SignerQuorum was not set properly',
)
const otherChainSource = Wallet.generate()
const amount: IssuedCurrencyAmount = {
currency: 'USD',
issuer: issuer.classicAddress,
value: '10',
}
const claimIdTx: XChainCreateClaimID = {
TransactionType: 'XChainCreateClaimID',
Account: destination.classicAddress,
XChainBridge: xchainBridge,
SignatureReward: signatureReward,
OtherChainSource: otherChainSource.classicAddress,
}
await testTransaction(testContext.client, claimIdTx, destination)
const initialBalance = Number(
await getIOUBalance(
testContext.client,
destination,
xchainBridge.IssuingChainIssue as IssuedCurrency,
),
)
const attestationToSign = {
XChainBridge: xchainBridge,
OtherChainSource: otherChainSource.classicAddress,
Amount: amount,
AttestationRewardAccount: witness.classicAddress,
WasLockingChainSend: 1,
XChainClaimID: 1,
Destination: destination.classicAddress,
}
const encodedAttestation = encode(attestationToSign)
const attestationSignature = sign(encodedAttestation, witness.privateKey)
const tx: XChainAddClaimAttestation = {
TransactionType: 'XChainAddClaimAttestation',
Account: witness.classicAddress,
XChainBridge: xchainBridge,
OtherChainSource: otherChainSource.classicAddress,
Amount: amount,
WasLockingChainSend: 1,
XChainClaimID: 1,
Destination: destination.classicAddress,
PublicKey: witness.publicKey,
Signature: attestationSignature,
AttestationRewardAccount: witness.classicAddress,
AttestationSignerAccount: witness.classicAddress,
}
await testTransaction(testContext.client, tx, witness)
const finalBalance = Number(
await getIOUBalance(
testContext.client,
destination,
xchainBridge.IssuingChainIssue as IssuedCurrency,
),
)
assert.equal(
finalBalance,
initialBalance + Number(amount.value),
'The destination balance should go up by the amount transferred',
)
},
TIMEOUT,
)
})

View File

@@ -0,0 +1,112 @@
import { assert } from 'chai'
import { encode } from 'ripple-binary-codec'
import { sign } from 'ripple-keypairs'
import {
Wallet,
XChainAddClaimAttestation,
XChainClaim,
XChainCreateClaimID,
xrpToDrops,
} from '../../../src'
import serverUrl from '../serverUrl'
import {
setupBridge,
setupClient,
teardownClient,
type XrplIntegrationTestContext,
} from '../setup'
import { generateFundedWallet, getXRPBalance, testTransaction } from '../utils'
// how long before each test case times out
const TIMEOUT = 20000
describe('XChainCreateBridge', function () {
let testContext: XrplIntegrationTestContext
beforeEach(async () => {
testContext = await setupClient(serverUrl)
})
afterEach(async () => teardownClient(testContext))
it(
'base',
async () => {
const { xchainBridge, witness, signatureReward } = await setupBridge(
testContext.client,
)
const destination = await generateFundedWallet(testContext.client)
const otherChainSource = Wallet.generate()
const amount = xrpToDrops(10)
const claimIdTx: XChainCreateClaimID = {
TransactionType: 'XChainCreateClaimID',
Account: destination.classicAddress,
XChainBridge: xchainBridge,
SignatureReward: signatureReward,
OtherChainSource: otherChainSource.classicAddress,
}
await testTransaction(testContext.client, claimIdTx, destination)
const initialBalance = Number(
await getXRPBalance(testContext.client, destination),
)
const attestationToSign = {
XChainBridge: xchainBridge,
OtherChainSource: otherChainSource.classicAddress,
Amount: amount,
AttestationRewardAccount: witness.classicAddress,
WasLockingChainSend: 0,
XChainClaimID: 1,
}
const encodedAttestation = encode(attestationToSign)
const attestationSignature = sign(encodedAttestation, witness.privateKey)
const claimTx: XChainAddClaimAttestation = {
TransactionType: 'XChainAddClaimAttestation',
Account: witness.classicAddress,
XChainBridge: xchainBridge,
OtherChainSource: otherChainSource.classicAddress,
Amount: amount,
WasLockingChainSend: 0,
XChainClaimID: 1,
PublicKey: witness.publicKey,
Signature: attestationSignature,
AttestationRewardAccount: witness.classicAddress,
AttestationSignerAccount: witness.classicAddress,
}
await testTransaction(testContext.client, claimTx, witness)
const intermediateBalance = Number(
await getXRPBalance(testContext.client, destination),
)
assert.equal(
initialBalance,
intermediateBalance,
"The destination's balance should not change yet",
)
const tx: XChainClaim = {
TransactionType: 'XChainClaim',
Account: destination.classicAddress,
XChainBridge: xchainBridge,
Destination: destination.classicAddress,
XChainClaimID: 1,
Amount: amount,
}
await testTransaction(testContext.client, tx, destination)
const finalBalance = Number(
await getXRPBalance(testContext.client, destination),
)
assert.equal(
finalBalance,
initialBalance + Number(amount) - Number(signatureReward) - 12,
"The destination's balance should not change yet",
)
},
TIMEOUT,
)
})

View File

@@ -0,0 +1,61 @@
import { assert } from 'chai'
import { XChainCommit } from '../../../src'
import serverUrl from '../serverUrl'
import {
setupBridge,
setupClient,
teardownClient,
type XrplIntegrationTestContext,
} from '../setup'
import { generateFundedWallet, getXRPBalance, testTransaction } from '../utils'
// how long before each test case times out
const TIMEOUT = 20000
describe('XChainCommit', function () {
let testContext: XrplIntegrationTestContext
beforeEach(async () => {
testContext = await setupClient(serverUrl)
})
afterEach(async () => teardownClient(testContext))
it(
'base',
async () => {
const { xchainBridge } = await setupBridge(testContext.client)
const initialBalance = Number(
await getXRPBalance(testContext.client, xchainBridge.LockingChainDoor),
)
// actually test XChainCommit
const wallet2 = await generateFundedWallet(testContext.client)
const amount = 10000000
const tx: XChainCommit = {
TransactionType: 'XChainCommit',
Account: wallet2.classicAddress,
XChainBridge: xchainBridge,
XChainClaimID: 1,
Amount: amount.toString(),
}
await testTransaction(testContext.client, tx, wallet2)
const accountInfoResponse2 = await testContext.client.request({
command: 'account_info',
account: xchainBridge.LockingChainDoor,
})
const finalBalance = Number(
accountInfoResponse2.result.account_data.Balance,
)
assert.equal(
initialBalance + amount,
finalBalance,
"The bridge door's balance should go up by the amount committed",
)
},
TIMEOUT,
)
})

View File

@@ -0,0 +1,55 @@
import { assert } from 'chai'
import { XChainCreateBridge } from '../../../src'
import serverUrl from '../serverUrl'
import {
setupClient,
teardownClient,
type XrplIntegrationTestContext,
} from '../setup'
import { GENESIS_ACCOUNT, testTransaction } from '../utils'
// how long before each test case times out
const TIMEOUT = 20000
describe('XChainCreateBridge', function () {
let testContext: XrplIntegrationTestContext
beforeEach(async () => {
testContext = await setupClient(serverUrl)
})
afterEach(async () => teardownClient(testContext))
it(
'base',
async () => {
const tx: XChainCreateBridge = {
TransactionType: 'XChainCreateBridge',
Account: testContext.wallet.classicAddress,
XChainBridge: {
LockingChainDoor: testContext.wallet.classicAddress,
LockingChainIssue: { currency: 'XRP' },
IssuingChainDoor: GENESIS_ACCOUNT,
IssuingChainIssue: { currency: 'XRP' },
},
SignatureReward: '200',
MinAccountCreateAmount: '10000000',
}
await testTransaction(testContext.client, tx, testContext.wallet)
// confirm that the transaction actually went through
const accountObjectsResponse = await testContext.client.request({
command: 'account_objects',
account: testContext.wallet.classicAddress,
type: 'bridge',
})
assert.lengthOf(
accountObjectsResponse.result.account_objects,
1,
'Should be exactly one bridge owned by the account',
)
},
TIMEOUT,
)
})

View File

@@ -0,0 +1,57 @@
import { assert } from 'chai'
import { XChainCreateClaimID, Wallet } from '../../../src'
import serverUrl from '../serverUrl'
import {
setupBridge,
setupClient,
teardownClient,
type XrplIntegrationTestContext,
} from '../setup'
import { generateFundedWallet, testTransaction } from '../utils'
// how long before each test case times out
const TIMEOUT = 20000
describe('XChainCreateClaimID', function () {
let testContext: XrplIntegrationTestContext
beforeEach(async () => {
testContext = await setupClient(serverUrl)
})
afterEach(async () => teardownClient(testContext))
it(
'base',
async () => {
const { xchainBridge, signatureReward } = await setupBridge(
testContext.client,
)
// actually test XChainCreateClaimID
const wallet2 = await generateFundedWallet(testContext.client)
const otherChainSource = Wallet.generate()
const tx: XChainCreateClaimID = {
TransactionType: 'XChainCreateClaimID',
Account: wallet2.classicAddress,
XChainBridge: xchainBridge,
SignatureReward: signatureReward,
OtherChainSource: otherChainSource.classicAddress,
}
await testTransaction(testContext.client, tx, wallet2)
const accountObjectsResponse2 = await testContext.client.request({
command: 'account_objects',
account: wallet2.classicAddress,
type: 'xchain_owned_claim_id',
})
assert.lengthOf(
accountObjectsResponse2.result.account_objects,
1,
'Should be exactly one claim ID owned by the account',
)
},
TIMEOUT,
)
})

View File

@@ -0,0 +1,95 @@
import { assert } from 'chai'
import { XChainCreateBridge, XChainModifyBridge } from '../../../src'
import { Bridge } from '../../../src/models/ledger'
import serverUrl from '../serverUrl'
import {
setupClient,
teardownClient,
type XrplIntegrationTestContext,
} from '../setup'
import { GENESIS_ACCOUNT, testTransaction } from '../utils'
// how long before each test case times out
const TIMEOUT = 20000
describe('XChainCreateBridge', function () {
let testContext: XrplIntegrationTestContext
beforeEach(async () => {
testContext = await setupClient(serverUrl)
})
afterEach(async () => teardownClient(testContext))
it(
'base',
async () => {
const setupTx: XChainCreateBridge = {
TransactionType: 'XChainCreateBridge',
Account: testContext.wallet.classicAddress,
XChainBridge: {
LockingChainDoor: testContext.wallet.classicAddress,
LockingChainIssue: { currency: 'XRP' },
IssuingChainDoor: GENESIS_ACCOUNT,
IssuingChainIssue: { currency: 'XRP' },
},
SignatureReward: '200',
MinAccountCreateAmount: '10000000',
}
await testTransaction(testContext.client, setupTx, testContext.wallet)
// confirm that the transaction actually went through
const accountObjectsResponse = await testContext.client.request({
command: 'account_objects',
account: testContext.wallet.classicAddress,
type: 'bridge',
})
assert.lengthOf(
accountObjectsResponse.result.account_objects,
1,
'Should be exactly one bridge owned by the account',
)
const initialBridge = accountObjectsResponse.result
.account_objects[0] as unknown as Bridge
assert.equal(
initialBridge.SignatureReward,
'200',
'Signature reward is incorrect',
)
const tx: XChainModifyBridge = {
TransactionType: 'XChainModifyBridge',
Account: testContext.wallet.classicAddress,
XChainBridge: {
LockingChainDoor: testContext.wallet.classicAddress,
LockingChainIssue: { currency: 'XRP' },
IssuingChainDoor: GENESIS_ACCOUNT,
IssuingChainIssue: { currency: 'XRP' },
},
SignatureReward: '300',
}
await testTransaction(testContext.client, tx, testContext.wallet)
// confirm that the transaction actually went through
const accountObjectsResponse2 = await testContext.client.request({
command: 'account_objects',
account: testContext.wallet.classicAddress,
type: 'bridge',
})
assert.lengthOf(
accountObjectsResponse2.result.account_objects,
1,
'Should be exactly one bridge owned by the account',
)
const finalBridge = accountObjectsResponse2.result
.account_objects[0] as unknown as Bridge
assert.equal(
finalBridge.SignatureReward,
'300',
'Signature reward was not modified',
)
},
TIMEOUT,
)
})

View File

@@ -10,12 +10,14 @@ import {
type SubmitResponse,
TimeoutError,
NotConnectedError,
AccountLinesRequest,
IssuedCurrency,
} from '../../src'
import { Payment, Transaction } from '../../src/models/transactions'
import { hashSignedTx } from '../../src/utils/hashes'
const masterAccount = 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'
const masterSecret = 'snoPBrXtMeMyMHUVTgbuqAfg1SUTb'
export const GENESIS_ACCOUNT = 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'
const GENESIS_SECRET = 'snoPBrXtMeMyMHUVTgbuqAfg1SUTb'
export async function sendLedgerAccept(client: Client): Promise<unknown> {
return client.connection.request({ command: 'ledger_accept' })
@@ -141,12 +143,12 @@ export async function fundAccount(
): Promise<SubmitResponse> {
const payment: Payment = {
TransactionType: 'Payment',
Account: masterAccount,
Account: GENESIS_ACCOUNT,
Destination: wallet.classicAddress,
// 2 times the amount needed for a new account (20 XRP)
Amount: '400000000',
}
const wal = Wallet.fromSeed(masterSecret)
const wal = Wallet.fromSeed(GENESIS_SECRET)
const response = await submitTransaction({
client,
wallet: wal,
@@ -263,11 +265,13 @@ export async function testTransaction(
export async function getXRPBalance(
client: Client,
wallet: Wallet,
account: string | Wallet,
): Promise<string> {
const address: string =
typeof account === 'string' ? account : account.classicAddress
const request: AccountInfoRequest = {
command: 'account_info',
account: wallet.classicAddress,
account: address,
}
return (await client.request(request)).result.account_data.Balance
}
@@ -338,3 +342,16 @@ export async function waitForAndForceProgressLedgerTime(
throw new Error(`Ledger time not reached after ${retries} retries.`)
}
export async function getIOUBalance(
client: Client,
wallet: Wallet,
currency: IssuedCurrency,
): Promise<string> {
const request: AccountLinesRequest = {
command: 'account_lines',
account: wallet.classicAddress,
peer: currency.issuer,
}
return (await client.request(request)).result.lines[0].balance
}