mirror of
https://github.com/Xahau/xahau.js.git
synced 2026-04-29 15:37:50 +00:00
Merge branch 'main' into sidechain-2.5
This commit is contained in:
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -2,7 +2,11 @@
|
||||
"editor.tabSize": 2,
|
||||
"cSpell.words": [
|
||||
"hostid",
|
||||
"Multisigned",
|
||||
"keypair",
|
||||
"keypairs",
|
||||
"multisign",
|
||||
"multisigned",
|
||||
"multisigning",
|
||||
"preauthorization",
|
||||
"secp256k1",
|
||||
"Setf",
|
||||
|
||||
@@ -74,6 +74,7 @@ It goes through:
|
||||
|
||||
If you're using xrpl.js with React or Deno, you'll need to do a couple extra steps to set it up:
|
||||
|
||||
- [Using xrpl.js with a CDN](./UNIQUE_SETUPS.md#using-xrpljs-from-a-cdn)
|
||||
- [Using xrpl.js with `create-react-app`](./UNIQUE_SETUPS.md#using-xrpljs-with-create-react-app)
|
||||
- [Using xrpl.js with `React Native`](./UNIQUE_SETUPS.md#using-xrpljs-with-react-native)
|
||||
- [Using xrpl.js with `Vite React`](./UNIQUE_SETUPS.md#using-xrpljs-with-vite-react)
|
||||
|
||||
@@ -2,6 +2,15 @@
|
||||
|
||||
For when you need to do more than just install `xrpl.js` for it to work (especially for React projects in the browser).
|
||||
|
||||
### Using xrpl.js from a CDN
|
||||
|
||||
You can avoid setting up your build system to handle `xrpl.js` by using a cdn version that is prebuilt for the browser.
|
||||
|
||||
- unpkg `<script src="https://unpkg.com/xrpl@2.3.0/build/xrpl-latest-min.js"></script>`
|
||||
- jsdelivr `<script src="https://cdn.jsdelivr.net/npm/xrpl@2.3.0/build/xrpl-latest-min.js"></script>`
|
||||
|
||||
Ensure that the full path is provided so the browser can find the sourcemaps.
|
||||
|
||||
### Using xrpl.js with `create-react-app`
|
||||
|
||||
To use `xrpl.js` with React, you need to install shims for core NodeJS modules. Starting with version 5, Webpack stopped including shims by default, so you must modify your Webpack configuration to add the shims you need. Either you can eject your config and modify it, or you can use a library such as `react-app-rewired`. The example below uses `react-app-rewired`.
|
||||
|
||||
1809
package-lock.json
generated
1809
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@
|
||||
"dependencies": {
|
||||
"assert": "^2.0.0",
|
||||
"big-integer": "^1.6.48",
|
||||
"buffer": "5.6.0",
|
||||
"buffer": "6.0.3",
|
||||
"create-hash": "^1.2.0",
|
||||
"decimal.js": "^10.2.0",
|
||||
"ripple-address-codec": "^4.2.5"
|
||||
|
||||
@@ -10,6 +10,10 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr
|
||||
### Fixed
|
||||
* Fixed `ServerState.transitions` typing, it is now a string instead of a number. (Only used in return from `server_state` request)
|
||||
* Added `destination_amount` to `PathOption` which is returned as part of a `path_find` request
|
||||
* Removed the `decode(encode(tx)) == tx` check from the wallet signing process
|
||||
|
||||
### Removed
|
||||
* RPCs and utils related to the old sidechain design
|
||||
|
||||
## 2.7.0 (2023-03-08)
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
"karma-webpack": "^5.0.0",
|
||||
"node-polyfill-webpack-plugin": "^2.0.1",
|
||||
"react": "^18.2.0",
|
||||
"typedoc": "^0.23.24"
|
||||
"typedoc": "^0.24.6"
|
||||
},
|
||||
"resolutions": {
|
||||
"elliptic": "^6.5.4"
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* eslint-disable max-lines -- There are lots of equivalent constructors which make sense to have here. */
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { fromSeed } from 'bip32'
|
||||
import { mnemonicToSeedSync, validateMnemonic } from 'bip39'
|
||||
import isEqual from 'lodash/isEqual'
|
||||
import omitBy from 'lodash/omitBy'
|
||||
import {
|
||||
classicAddressToXAddress,
|
||||
@@ -25,11 +23,8 @@ import {
|
||||
} from 'ripple-keypairs'
|
||||
|
||||
import ECDSA from '../ECDSA'
|
||||
import { ValidationError, XrplError } from '../errors'
|
||||
import { IssuedCurrencyAmount } from '../models/common'
|
||||
import { ValidationError } from '../errors'
|
||||
import { Transaction, validate } from '../models/transactions'
|
||||
import { isIssuedCurrency } from '../models/transactions/common'
|
||||
import { isHex } from '../models/utils'
|
||||
import { ensureClassicAddress } from '../sugar/utils'
|
||||
import { hashSignedTx } from '../utils/hashes/hashLedger'
|
||||
|
||||
@@ -368,7 +363,6 @@ class Wallet {
|
||||
}
|
||||
|
||||
const serialized = encode(txToSignAndEncode)
|
||||
this.checkTxSerialization(serialized, tx)
|
||||
return {
|
||||
tx_blob: serialized,
|
||||
hash: hashSignedTx(serialized),
|
||||
@@ -401,124 +395,6 @@ class Wallet {
|
||||
public getXAddress(tag: number | false = false, isTestnet = false): string {
|
||||
return classicAddressToXAddress(this.classicAddress, tag, isTestnet)
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a serialized transaction, remove the fields that are added during the signing process,
|
||||
* and verify that it matches the transaction prior to signing. This gives the user a sanity check
|
||||
* to ensure that what they try to encode matches the message that will be recieved by rippled.
|
||||
*
|
||||
* @param serialized - A signed and serialized transaction.
|
||||
* @param tx - The transaction prior to signing.
|
||||
* @throws A ValidationError if the transaction does not have a TxnSignature/Signers property, or if
|
||||
* the serialized Transaction desn't match the original transaction.
|
||||
* @throws XrplError if the transaction includes an issued currency which is equivalent to XRP ignoring case.
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this, max-lines-per-function -- Helper for organization purposes
|
||||
private checkTxSerialization(serialized: string, tx: Transaction): void {
|
||||
// Decode the serialized transaction:
|
||||
const decoded = decode(serialized)
|
||||
const txCopy = { ...tx }
|
||||
|
||||
/*
|
||||
* And ensure it is equal to the original tx, except:
|
||||
* - It must have a TxnSignature or Signers (multisign).
|
||||
*/
|
||||
if (!decoded.TxnSignature && !decoded.Signers) {
|
||||
throw new ValidationError(
|
||||
'Serialized transaction must have a TxnSignature or Signers property',
|
||||
)
|
||||
}
|
||||
// - We know that the original tx did not have TxnSignature, so we should delete it:
|
||||
delete decoded.TxnSignature
|
||||
// - We know that the original tx did not have Signers, so if it exists, we should delete it:
|
||||
delete decoded.Signers
|
||||
|
||||
/*
|
||||
* - If SigningPubKey was not in the original tx, then we should delete it.
|
||||
* But if it was in the original tx, then we should ensure that it has not been changed.
|
||||
*/
|
||||
if (!tx.SigningPubKey) {
|
||||
delete decoded.SigningPubKey
|
||||
}
|
||||
|
||||
/*
|
||||
* - Memos have exclusively hex data which should ignore case.
|
||||
* Since decode goes to upper case, we set all tx memos to be uppercase for the comparison.
|
||||
*/
|
||||
txCopy.Memos?.map((memo) => {
|
||||
const memoCopy = { ...memo }
|
||||
if (memo.Memo.MemoData) {
|
||||
if (!isHex(memo.Memo.MemoData)) {
|
||||
throw new ValidationError('MemoData field must be a hex value')
|
||||
}
|
||||
memoCopy.Memo.MemoData = memo.Memo.MemoData.toUpperCase()
|
||||
}
|
||||
|
||||
if (memo.Memo.MemoType) {
|
||||
if (!isHex(memo.Memo.MemoType)) {
|
||||
throw new ValidationError('MemoType field must be a hex value')
|
||||
}
|
||||
memoCopy.Memo.MemoType = memo.Memo.MemoType.toUpperCase()
|
||||
}
|
||||
|
||||
if (memo.Memo.MemoFormat) {
|
||||
if (!isHex(memo.Memo.MemoFormat)) {
|
||||
throw new ValidationError('MemoFormat field must be a hex value')
|
||||
}
|
||||
memoCopy.Memo.MemoFormat = memo.Memo.MemoFormat.toUpperCase()
|
||||
}
|
||||
|
||||
return memo
|
||||
})
|
||||
|
||||
if (txCopy.TransactionType === 'NFTokenMint' && txCopy.URI) {
|
||||
txCopy.URI = txCopy.URI.toUpperCase()
|
||||
}
|
||||
|
||||
/* eslint-disable @typescript-eslint/consistent-type-assertions -- We check at runtime that this is safe */
|
||||
Object.keys(txCopy).forEach((key) => {
|
||||
const standard_currency_code_len = 3
|
||||
if (txCopy[key] && isIssuedCurrency(txCopy[key])) {
|
||||
const decodedAmount = decoded[key] as unknown as IssuedCurrencyAmount
|
||||
const decodedCurrency = decodedAmount.currency
|
||||
const txCurrency = (txCopy[key] as IssuedCurrencyAmount).currency
|
||||
|
||||
if (
|
||||
txCurrency.length === standard_currency_code_len &&
|
||||
txCurrency.toUpperCase() === 'XRP'
|
||||
) {
|
||||
throw new XrplError(
|
||||
`Trying to sign an issued currency with a similar standard code to XRP (received '${txCurrency}'). XRP is not an issued currency.`,
|
||||
)
|
||||
}
|
||||
|
||||
// Standardize the format of currency codes to the 40 byte hex string for comparison
|
||||
const amount = txCopy[key] as IssuedCurrencyAmount
|
||||
if (amount.currency.length !== decodedCurrency.length) {
|
||||
/* eslint-disable-next-line max-depth -- Easier to read with two if-statements */
|
||||
if (decodedCurrency.length === standard_currency_code_len) {
|
||||
decodedAmount.currency = isoToHex(decodedCurrency)
|
||||
} else {
|
||||
/* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- We need to update txCopy directly */
|
||||
txCopy[key].currency = isoToHex(txCopy[key].currency)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
/* eslint-enable @typescript-eslint/consistent-type-assertions -- Done with dynamic checking */
|
||||
|
||||
if (!isEqual(decoded, txCopy)) {
|
||||
const data = {
|
||||
decoded,
|
||||
tx,
|
||||
}
|
||||
const error = new ValidationError(
|
||||
'Serialized transaction does not match original txJSON. See error.data',
|
||||
data,
|
||||
)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -567,20 +443,4 @@ function removeTrailingZeros(tx: Transaction): void {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an ISO code to a hex string representation
|
||||
*
|
||||
* @param iso - A 3 letter standard currency code
|
||||
*/
|
||||
/* eslint-disable @typescript-eslint/no-magic-numbers -- Magic numbers are from rippleds of currency code encoding */
|
||||
function isoToHex(iso: string): string {
|
||||
const bytes = Buffer.alloc(20)
|
||||
if (iso !== 'XRP') {
|
||||
const isoBytes = iso.split('').map((chr) => chr.charCodeAt(0))
|
||||
bytes.set(isoBytes, 12)
|
||||
}
|
||||
return bytes.toString('hex').toUpperCase()
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/no-magic-numbers -- Only needed in this function */
|
||||
|
||||
export default Wallet
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
import { BaseRequest, BaseResponse } from './baseMethod'
|
||||
|
||||
/**
|
||||
* The `federator_info` command asks the federator for information
|
||||
* about the door account and other bridge-related information. This
|
||||
* method only exists on sidechain federators. Expects a response in
|
||||
* the form of a {@link FederatorInfoResponse}.
|
||||
*
|
||||
* @category Requests
|
||||
*/
|
||||
export interface FederatorInfoRequest extends BaseRequest {
|
||||
command: 'federator_info'
|
||||
}
|
||||
|
||||
/**
|
||||
* Response expected from a {@link FederatorInfoRequest}.
|
||||
*
|
||||
* @category Responses
|
||||
*/
|
||||
export interface FederatorInfoResponse extends BaseResponse {
|
||||
result: {
|
||||
info: {
|
||||
mainchain: {
|
||||
door_status: {
|
||||
initialized: boolean
|
||||
status: 'open' | 'opening' | 'closed' | 'closing'
|
||||
}
|
||||
last_transaction_sent_seq: number
|
||||
listener_info: {
|
||||
state: 'syncing' | 'normal'
|
||||
}
|
||||
pending_transactions: Array<{
|
||||
amount: string
|
||||
destination_account: string
|
||||
signatures: Array<{
|
||||
public_key: string
|
||||
seq: number
|
||||
}>
|
||||
}>
|
||||
sequence: number
|
||||
tickets: {
|
||||
initialized: boolean
|
||||
tickets: Array<{
|
||||
status: 'taken' | 'available'
|
||||
ticket_seq: number
|
||||
}>
|
||||
}
|
||||
}
|
||||
public_key: string
|
||||
sidechain: {
|
||||
door_status: {
|
||||
initialized: boolean
|
||||
status: 'open' | 'opening' | 'closed' | 'closing'
|
||||
}
|
||||
last_transaction_sent_seq: number
|
||||
listener_info: {
|
||||
state: 'syncing' | 'normal'
|
||||
}
|
||||
pending_transactions: Array<{
|
||||
amount: string
|
||||
destination_account: string
|
||||
signatures: Array<{
|
||||
public_key: string
|
||||
seq: number
|
||||
}>
|
||||
}>
|
||||
sequence: number
|
||||
tickets: {
|
||||
initialized: boolean
|
||||
tickets: Array<{
|
||||
status: 'taken' | 'available'
|
||||
ticket_seq: number
|
||||
}>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import {
|
||||
DepositAuthorizedRequest,
|
||||
DepositAuthorizedResponse,
|
||||
} from './depositAuthorized'
|
||||
import { FederatorInfoRequest, FederatorInfoResponse } from './federatorInfo'
|
||||
import { FeeRequest, FeeResponse } from './fee'
|
||||
import {
|
||||
GatewayBalancesRequest,
|
||||
@@ -121,8 +120,6 @@ type Request =
|
||||
// NFT methods
|
||||
| NFTBuyOffersRequest
|
||||
| NFTSellOffersRequest
|
||||
// sidechain methods
|
||||
| FederatorInfoRequest
|
||||
|
||||
/**
|
||||
* @category Responses
|
||||
@@ -171,8 +168,6 @@ type Response =
|
||||
// NFT methods
|
||||
| NFTBuyOffersResponse
|
||||
| NFTSellOffersResponse
|
||||
// sidechain methods
|
||||
| FederatorInfoResponse
|
||||
|
||||
export {
|
||||
Request,
|
||||
@@ -268,7 +263,4 @@ export {
|
||||
NFTBuyOffersResponse,
|
||||
NFTSellOffersRequest,
|
||||
NFTSellOffersResponse,
|
||||
// sidechain methods
|
||||
FederatorInfoRequest,
|
||||
FederatorInfoResponse,
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
/* eslint-disable max-lines-per-function -- need to work with a lot of Tx verifications */
|
||||
|
||||
import { ValidationError } from '../../errors'
|
||||
import { IssuedCurrencyAmount, Memo } from '../common'
|
||||
import { isHex } from '../utils'
|
||||
import { setTransactionFlagsToNumber } from '../utils/flags'
|
||||
|
||||
import { AccountDelete, validateAccountDelete } from './accountDelete'
|
||||
@@ -9,6 +11,7 @@ import { AccountSet, validateAccountSet } from './accountSet'
|
||||
import { CheckCancel, validateCheckCancel } from './checkCancel'
|
||||
import { CheckCash, validateCheckCash } from './checkCash'
|
||||
import { CheckCreate, validateCheckCreate } from './checkCreate'
|
||||
import { isIssuedCurrency } from './common'
|
||||
import { DepositPreauth, validateDepositPreauth } from './depositPreauth'
|
||||
import { EscrowCancel, validateEscrowCancel } from './escrowCancel'
|
||||
import { EscrowCreate, validateEscrowCreate } from './escrowCreate'
|
||||
@@ -135,6 +138,56 @@ export function validate(transaction: Record<string, unknown>): void {
|
||||
if (typeof tx.TransactionType !== 'string') {
|
||||
throw new ValidationError("Object's `TransactionType` is not a string")
|
||||
}
|
||||
|
||||
/*
|
||||
* - Memos have exclusively hex data.
|
||||
*/
|
||||
if (tx.Memos != null && typeof tx.Memos !== 'object') {
|
||||
throw new ValidationError('Memo must be array')
|
||||
}
|
||||
if (tx.Memos != null) {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- needed here
|
||||
;(tx.Memos as Array<Memo | null>).forEach((memo) => {
|
||||
if (memo?.Memo == null) {
|
||||
throw new ValidationError('Memo data must be in a `Memo` field')
|
||||
}
|
||||
if (memo.Memo.MemoData) {
|
||||
if (!isHex(memo.Memo.MemoData)) {
|
||||
throw new ValidationError('MemoData field must be a hex value')
|
||||
}
|
||||
}
|
||||
|
||||
if (memo.Memo.MemoType) {
|
||||
if (!isHex(memo.Memo.MemoType)) {
|
||||
throw new ValidationError('MemoType field must be a hex value')
|
||||
}
|
||||
}
|
||||
|
||||
if (memo.Memo.MemoFormat) {
|
||||
if (!isHex(memo.Memo.MemoFormat)) {
|
||||
throw new ValidationError('MemoFormat field must be a hex value')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Object.keys(tx).forEach((key) => {
|
||||
const standard_currency_code_len = 3
|
||||
if (tx[key] && isIssuedCurrency(tx[key])) {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- needed
|
||||
const txCurrency = (tx[key] as IssuedCurrencyAmount).currency
|
||||
|
||||
if (
|
||||
txCurrency.length === standard_currency_code_len &&
|
||||
txCurrency.toUpperCase() === 'XRP'
|
||||
) {
|
||||
throw new ValidationError(
|
||||
`Cannot have an issued currency with a similar standard code to XRP (received '${txCurrency}'). XRP is not an issued currency.`,
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- okay here
|
||||
setTransactionFlagsToNumber(tx as unknown as Transaction)
|
||||
switch (tx.TransactionType) {
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import { XrplError } from '../errors'
|
||||
import { Payment } from '../models'
|
||||
import { Memo } from '../models/common'
|
||||
|
||||
import { convertStringToHex } from './stringConversion'
|
||||
|
||||
/**
|
||||
* Creates a cross-chain payment transaction.
|
||||
*
|
||||
* @param payment - The initial payment transaction. If the transaction is
|
||||
* signed, then it will need to be re-signed. There must be no more than 2
|
||||
* memos, since one memo is used for the sidechain destination account. The
|
||||
* destination must be the sidechain's door account.
|
||||
* @param destAccount - the destination account on the sidechain.
|
||||
* @returns A cross-chain payment transaction, where the mainchain door account
|
||||
* is the `Destination` and the destination account on the sidechain is encoded
|
||||
* in the memos.
|
||||
* @throws XrplError - if there are more than 2 memos.
|
||||
* @category Utilities
|
||||
*/
|
||||
export default function createCrossChainPayment(
|
||||
payment: Payment,
|
||||
destAccount: string,
|
||||
): Payment {
|
||||
const destAccountHex = convertStringToHex(destAccount)
|
||||
const destAccountMemo: Memo = { Memo: { MemoData: destAccountHex } }
|
||||
|
||||
const memos = payment.Memos ?? []
|
||||
if (memos.length > 2) {
|
||||
throw new XrplError(
|
||||
'Cannot have more than 2 memos in a cross-chain transaction.',
|
||||
)
|
||||
}
|
||||
const newMemos = [destAccountMemo, ...memos]
|
||||
|
||||
const newPayment = { ...payment, Memos: newMemos }
|
||||
delete newPayment.TxnSignature
|
||||
|
||||
return newPayment
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import { Response } from '../models/methods'
|
||||
import { PaymentChannelClaim } from '../models/transactions/paymentChannelClaim'
|
||||
import { Transaction } from '../models/transactions/transaction'
|
||||
|
||||
import createCrossChainPayment from './createCrossChainPayment'
|
||||
import { deriveKeypair, deriveAddress, deriveXAddress } from './derive'
|
||||
import getBalanceChanges from './getBalanceChanges'
|
||||
import getNFTokenID from './getNFTokenID'
|
||||
@@ -220,6 +219,5 @@ export {
|
||||
encodeForSigning,
|
||||
encodeForSigningClaim,
|
||||
getNFTokenID,
|
||||
createCrossChainPayment,
|
||||
parseNFTokenID,
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ describe('TrustSet', function () {
|
||||
TransactionType: 'TrustSet',
|
||||
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
LimitAmount: {
|
||||
currency: 'XRP',
|
||||
currency: 'USD',
|
||||
issuer: 'rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX',
|
||||
value: '4329.23',
|
||||
},
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { createCrossChainPayment, convertStringToHex, Payment } from '../../src'
|
||||
|
||||
describe('createCrossChainPayment', function () {
|
||||
it('successful xchain payment creation', function () {
|
||||
const payment: Payment = {
|
||||
TransactionType: 'Payment',
|
||||
Account: 'rRandom',
|
||||
Destination: 'rRandom2',
|
||||
Amount: '3489303',
|
||||
}
|
||||
const sidechainAccount = 'rSidechain'
|
||||
|
||||
const expectedPayment = {
|
||||
...payment,
|
||||
Memos: [
|
||||
{
|
||||
Memo: {
|
||||
MemoData: convertStringToHex(sidechainAccount),
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const resultPayment = createCrossChainPayment(payment, sidechainAccount)
|
||||
assert.deepEqual(resultPayment, expectedPayment)
|
||||
|
||||
// ensure that the original object wasn't modified
|
||||
assert.notDeepEqual(resultPayment, payment)
|
||||
})
|
||||
|
||||
it('successful xchain payment creation with memo', function () {
|
||||
const memo = {
|
||||
Memo: {
|
||||
MemoData: 'deadbeef',
|
||||
},
|
||||
}
|
||||
const payment: Payment = {
|
||||
TransactionType: 'Payment',
|
||||
Account: 'rRandom',
|
||||
Destination: 'rRandom2',
|
||||
Amount: '3489303',
|
||||
Memos: [memo],
|
||||
}
|
||||
const sidechainAccount = 'rSidechain'
|
||||
|
||||
const expectedPayment = {
|
||||
...payment,
|
||||
Memos: [
|
||||
{
|
||||
Memo: {
|
||||
MemoData: convertStringToHex(sidechainAccount),
|
||||
},
|
||||
},
|
||||
memo,
|
||||
],
|
||||
}
|
||||
|
||||
const resultPayment = createCrossChainPayment(payment, sidechainAccount)
|
||||
assert.deepEqual(resultPayment, expectedPayment)
|
||||
|
||||
// ensure that the original object wasn't modified
|
||||
assert.notDeepEqual(resultPayment, payment)
|
||||
})
|
||||
|
||||
it('removes TxnSignature', function () {
|
||||
const payment: Payment = {
|
||||
TransactionType: 'Payment',
|
||||
Account: 'rRandom',
|
||||
Destination: 'rRandom2',
|
||||
Amount: '3489303',
|
||||
TxnSignature: 'asodfiuaosdfuaosd',
|
||||
}
|
||||
const sidechainAccount = 'rSidechain'
|
||||
|
||||
const expectedPayment = {
|
||||
...payment,
|
||||
Memos: [
|
||||
{
|
||||
Memo: {
|
||||
MemoData: convertStringToHex(sidechainAccount),
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
delete expectedPayment.TxnSignature
|
||||
|
||||
const resultPayment = createCrossChainPayment(payment, sidechainAccount)
|
||||
assert.deepEqual(resultPayment, expectedPayment)
|
||||
|
||||
// ensure that the original object wasn't modified
|
||||
assert.notDeepEqual(resultPayment, payment)
|
||||
})
|
||||
|
||||
it('fails with 3 memos', function () {
|
||||
const payment: Payment = {
|
||||
TransactionType: 'Payment',
|
||||
Account: 'rRandom',
|
||||
Destination: 'rRandom2',
|
||||
Amount: '3489303',
|
||||
Memos: [
|
||||
{
|
||||
Memo: {
|
||||
MemoData: '2934723843ace',
|
||||
},
|
||||
},
|
||||
{
|
||||
Memo: {
|
||||
MemoData: '2934723843ace',
|
||||
},
|
||||
},
|
||||
{
|
||||
Memo: {
|
||||
MemoData: '2934723843ace',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
assert.throws(() => {
|
||||
createCrossChainPayment(payment, 'rSidechain')
|
||||
}, /Cannot have more than 2 memos/u)
|
||||
})
|
||||
})
|
||||
@@ -763,7 +763,7 @@ describe('Wallet', function () {
|
||||
}
|
||||
assert.throws(() => {
|
||||
wallet.sign(payment)
|
||||
}, /^Trying to sign an issued currency with a similar standard code to XRP \(received 'xrp'\)\. XRP is not an issued currency\./u)
|
||||
}, /^Cannot have an issued currency with a similar standard code to XRP \(received 'xrp'\)\. XRP is not an issued currency\./u)
|
||||
})
|
||||
|
||||
it('sign does NOT throw when a payment contains an issued currency like xrp in hex string format', async function () {
|
||||
|
||||
Reference in New Issue
Block a user