mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-20 20:25:48 +00:00
feat: add support for current sidechain design (#2039)
* Update definitions.json * add new st types * add tests * add XChainClaim tx * add XChainCommit tx * add XChainCreateBridge tx * add XChainCreateClaimID tx * update definitions.json * rename Bridge -> XChainBridge in binary codec, fix tests * rename Bridge -> XChainBridge in models * add codec support for XChainAddAttestation * add XChainAddAttestation model * undo debugging change * fix linting issues * update definitions.json for new rippled code, add new tests/update old tests * add/update models * update history * update binary-codec * add XChainModifyBridge model * update RPCs * update to latest rippled * more fixes * fix definitions.json * fix spacing * update definitions.json to avoid conflict with amm * update definitions.json to resolve amm conflicts * audit code * more updates * update rpcs * switch to beta version * add destination tag to XChainClaim * rename IssuedCurrency -> Issue to match rippled * update Issue form * fix account object filters * fix issue from typing * fix LedgerEntry types * fix attestation destination type * Update definitions.json * rename XChainAddAttestation -> XChainAddAttestationBatch * add XChainAddClaimAttestation * add XChainAddAccountCreateAttestation * remove XChainAddAttestationBatch * update definitions * fix attestation txns * fix attestation object * add validate for new txs * add Bridge ledger object * add XChainOwnedClaimID ledger object * add XChainOwnedCreateAccountClaimID ledger object * update account_objects * update models to latest rippled * fix minor issues * fix bridge ledger_entry * add XChainModifyBridge flag * Update definitions.json * add rbc tests for the new txs * update validateXChainModifyBridge * add validate methods to other xchain txs * fix isXChainBridge * fix isIssue typing * fix model types * update changelog * switch prepare to prepublishOnly * add docs * fix AccountObjectsType filter * export common types * fix account_objects filter * update LedgerEntry * add sidechain faucet info * add snippet * improve snippet * fix spacing issues * update ledger_entry * remove AMMDelete tests for now * Update definitions.json * fix unit tests * convert createValidate script to JS * remove unneeded linter ignores * respond to comments * more snippet fixes * make validate functions more readable * add getXChainClaimID method to parse metadata * re-add linter rules * clean up common * fix getXChainClaimID test * return undefined for failed tx * test: add model tests for new sidechain transactions (#2059) * add XChainAddAttestation tests, fix model * add XChainClaim model tests * add XChainCommit model tests, fix typo * add XChainCreateBridge model tests * add XChainCreateClaimID model tests * add XChainModifyBridge tests * update to most recent version of code * remove XChainAddAttestationBatch tests * add more validation tests * switch createValidateTests to JS
This commit is contained in:
8
.vscode/settings.json
vendored
8
.vscode/settings.json
vendored
@@ -1,6 +1,9 @@
|
||||
{
|
||||
"editor.tabSize": 2,
|
||||
"cSpell.words": [
|
||||
"altnet",
|
||||
"Autofills",
|
||||
"Clawback",
|
||||
"hostid",
|
||||
"keypair",
|
||||
"keypairs",
|
||||
@@ -8,8 +11,11 @@
|
||||
"multisigned",
|
||||
"multisigning",
|
||||
"preauthorization",
|
||||
"rippletest",
|
||||
"secp256k1",
|
||||
"Setf"
|
||||
"Setf",
|
||||
"Sidechains",
|
||||
"xchain"
|
||||
],
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# ripple-binary-codec Release History
|
||||
|
||||
## Unreleased
|
||||
### Added
|
||||
- Support for the XChainBridge amendment.
|
||||
|
||||
## 1.9.0 (2023-08-24)
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"UInt384": 22,
|
||||
"UInt512": 23,
|
||||
"Issue": 24,
|
||||
"XChainBridge": 25,
|
||||
"Transaction": 10001,
|
||||
"LedgerEntry": 10002,
|
||||
"Validation": 10003,
|
||||
@@ -35,8 +36,11 @@
|
||||
"Ticket": 84,
|
||||
"SignerList": 83,
|
||||
"Offer": 111,
|
||||
"Bridge": 105,
|
||||
"LedgerHashes": 104,
|
||||
"Amendments": 102,
|
||||
"XChainOwnedClaimID": 113,
|
||||
"XChainOwnedCreateAccountClaimID": 116,
|
||||
"FeeSettings": 115,
|
||||
"Escrow": 117,
|
||||
"PayChannel": 120,
|
||||
@@ -233,6 +237,16 @@
|
||||
"type": "UInt8"
|
||||
}
|
||||
],
|
||||
[
|
||||
"WasLockingChainSend",
|
||||
{
|
||||
"nth": 19,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "UInt8"
|
||||
}
|
||||
],
|
||||
[
|
||||
"LedgerEntryType",
|
||||
{
|
||||
@@ -983,6 +997,36 @@
|
||||
"type": "UInt64"
|
||||
}
|
||||
],
|
||||
[
|
||||
"XChainClaimID",
|
||||
{
|
||||
"nth": 20,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "UInt64"
|
||||
}
|
||||
],
|
||||
[
|
||||
"XChainAccountCreateCount",
|
||||
{
|
||||
"nth": 21,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "UInt64"
|
||||
}
|
||||
],
|
||||
[
|
||||
"XChainAccountClaimCount",
|
||||
{
|
||||
"nth": 22,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "UInt64"
|
||||
}
|
||||
],
|
||||
[
|
||||
"EmailHash",
|
||||
{
|
||||
@@ -1583,6 +1627,26 @@
|
||||
"type": "Amount"
|
||||
}
|
||||
],
|
||||
[
|
||||
"SignatureReward",
|
||||
{
|
||||
"nth": 29,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "Amount"
|
||||
}
|
||||
],
|
||||
[
|
||||
"MinAccountCreateAmount",
|
||||
{
|
||||
"nth": 30,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "Amount"
|
||||
}
|
||||
],
|
||||
[
|
||||
"LPTokenBalance",
|
||||
{
|
||||
@@ -1933,6 +1997,66 @@
|
||||
"type": "AccountID"
|
||||
}
|
||||
],
|
||||
[
|
||||
"OtherChainSource",
|
||||
{
|
||||
"nth": 18,
|
||||
"isVLEncoded": true,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "AccountID"
|
||||
}
|
||||
],
|
||||
[
|
||||
"OtherChainDestination",
|
||||
{
|
||||
"nth": 19,
|
||||
"isVLEncoded": true,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "AccountID"
|
||||
}
|
||||
],
|
||||
[
|
||||
"AttestationSignerAccount",
|
||||
{
|
||||
"nth": 20,
|
||||
"isVLEncoded": true,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "AccountID"
|
||||
}
|
||||
],
|
||||
[
|
||||
"AttestationRewardAccount",
|
||||
{
|
||||
"nth": 21,
|
||||
"isVLEncoded": true,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "AccountID"
|
||||
}
|
||||
],
|
||||
[
|
||||
"LockingChainDoor",
|
||||
{
|
||||
"nth": 22,
|
||||
"isVLEncoded": true,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "AccountID"
|
||||
}
|
||||
],
|
||||
[
|
||||
"IssuingChainDoor",
|
||||
{
|
||||
"nth": 23,
|
||||
"isVLEncoded": true,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "AccountID"
|
||||
}
|
||||
],
|
||||
[
|
||||
"Indexes",
|
||||
{
|
||||
@@ -1983,6 +2107,26 @@
|
||||
"type": "PathSet"
|
||||
}
|
||||
],
|
||||
[
|
||||
"LockingChainIssue",
|
||||
{
|
||||
"nth": 1,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "Issue"
|
||||
}
|
||||
],
|
||||
[
|
||||
"IssuingChainIssue",
|
||||
{
|
||||
"nth": 2,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "Issue"
|
||||
}
|
||||
],
|
||||
[
|
||||
"Asset",
|
||||
{
|
||||
@@ -2003,6 +2147,16 @@
|
||||
"type": "Issue"
|
||||
}
|
||||
],
|
||||
[
|
||||
"XChainBridge",
|
||||
{
|
||||
"nth": 1,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "XChainBridge"
|
||||
}
|
||||
],
|
||||
[
|
||||
"TransactionMetaData",
|
||||
{
|
||||
@@ -2243,6 +2397,46 @@
|
||||
"type": "STObject"
|
||||
}
|
||||
],
|
||||
[
|
||||
"XChainClaimProofSig",
|
||||
{
|
||||
"nth": 28,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "STObject"
|
||||
}
|
||||
],
|
||||
[
|
||||
"XChainCreateAccountProofSig",
|
||||
{
|
||||
"nth": 29,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "STObject"
|
||||
}
|
||||
],
|
||||
[
|
||||
"XChainClaimAttestationCollectionElement",
|
||||
{
|
||||
"nth": 30,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "STObject"
|
||||
}
|
||||
],
|
||||
[
|
||||
"XChainCreateAccountAttestationCollectionElement",
|
||||
{
|
||||
"nth": 31,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "STObject"
|
||||
}
|
||||
],
|
||||
[
|
||||
"Signers",
|
||||
{
|
||||
@@ -2393,6 +2587,26 @@
|
||||
"type": "STArray"
|
||||
}
|
||||
],
|
||||
[
|
||||
"XChainClaimAttestations",
|
||||
{
|
||||
"nth": 21,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "STArray"
|
||||
}
|
||||
],
|
||||
[
|
||||
"XChainCreateAccountAttestations",
|
||||
{
|
||||
"nth": 22,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "STArray"
|
||||
}
|
||||
],
|
||||
[
|
||||
"AuthAccounts",
|
||||
{
|
||||
@@ -2461,6 +2675,12 @@
|
||||
"temSEQ_AND_TICKET": -263,
|
||||
"temBAD_NFTOKEN_TRANSFER_FEE": -262,
|
||||
"temBAD_AMM_TOKENS": -261,
|
||||
"temXCHAIN_EQUAL_DOOR_ACCOUNTS": -260,
|
||||
"temXCHAIN_BAD_PROOF": -259,
|
||||
"temXCHAIN_BRIDGE_BAD_ISSUES": -258,
|
||||
"temXCHAIN_BRIDGE_NONDOOR_OWNER": -257,
|
||||
"temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT": -256,
|
||||
"temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT": -255,
|
||||
|
||||
"tefFAILURE": -199,
|
||||
"tefALREADY": -198,
|
||||
@@ -2497,6 +2717,7 @@
|
||||
"terQUEUED": -89,
|
||||
"terPRE_TICKET": -88,
|
||||
"terNO_AMM": -87,
|
||||
"terSUBMITTED": -86,
|
||||
|
||||
"tesSUCCESS": 0,
|
||||
|
||||
@@ -2538,6 +2759,7 @@
|
||||
"tecKILLED": 150,
|
||||
"tecHAS_OBLIGATIONS": 151,
|
||||
"tecTOO_SOON": 152,
|
||||
"tecHOOK_ERROR": 153,
|
||||
"tecMAX_SEQUENCE_REACHED": 154,
|
||||
"tecNO_SUITABLE_NFTOKEN_PAGE": 155,
|
||||
"tecNFTOKEN_BUY_SELL_MISMATCH": 156,
|
||||
@@ -2553,7 +2775,24 @@
|
||||
"tecAMM_EMPTY": 166,
|
||||
"tecAMM_NOT_EMPTY": 167,
|
||||
"tecAMM_ACCOUNT": 168,
|
||||
"tecINCOMPLETE": 169
|
||||
"tecINCOMPLETE": 169,
|
||||
"tecXCHAIN_BAD_TRANSFER_ISSUE": 170,
|
||||
"tecXCHAIN_NO_CLAIM_ID": 171,
|
||||
"tecXCHAIN_BAD_CLAIM_ID": 172,
|
||||
"tecXCHAIN_CLAIM_NO_QUORUM": 173,
|
||||
"tecXCHAIN_PROOF_UNKNOWN_KEY": 174,
|
||||
"tecXCHAIN_CREATE_ACCOUNT_NONXRP_ISSUE": 175,
|
||||
"tecXCHAIN_WRONG_CHAIN": 176,
|
||||
"tecXCHAIN_REWARD_MISMATCH": 177,
|
||||
"tecXCHAIN_NO_SIGNERS_LIST": 178,
|
||||
"tecXCHAIN_SENDING_ACCOUNT_MISMATCH": 179,
|
||||
"tecXCHAIN_INSUFF_CREATE_AMOUNT": 180,
|
||||
"tecXCHAIN_ACCOUNT_CREATE_PAST": 181,
|
||||
"tecXCHAIN_ACCOUNT_CREATE_TOO_MANY": 182,
|
||||
"tecXCHAIN_PAYMENT_FAILED": 183,
|
||||
"tecXCHAIN_SELF_COMMIT": 184,
|
||||
"tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR": 185,
|
||||
"tecXCHAIN_CREATE_ACCOUNT_DISABLED": 186
|
||||
},
|
||||
"TRANSACTION_TYPES": {
|
||||
"Invalid": -1,
|
||||
@@ -2592,6 +2831,14 @@
|
||||
"AMMVote": 38,
|
||||
"AMMBid": 39,
|
||||
"AMMDelete": 40,
|
||||
"XChainCreateClaimID": 41,
|
||||
"XChainCommit": 42,
|
||||
"XChainClaim": 43,
|
||||
"XChainAccountCreateCommit": 44,
|
||||
"XChainAddClaimAttestation": 45,
|
||||
"XChainAddAccountCreateAttestation": 46,
|
||||
"XChainModifyBridge": 47,
|
||||
"XChainCreateBridge": 48,
|
||||
"EnableAmendment": 100,
|
||||
"SetFee": 101,
|
||||
"UNLModify": 102
|
||||
|
||||
@@ -14,6 +14,7 @@ import { UInt32 } from './uint-32'
|
||||
import { UInt64 } from './uint-64'
|
||||
import { UInt8 } from './uint-8'
|
||||
import { Vector256 } from './vector-256'
|
||||
import { XChainBridge } from './xchain-bridge'
|
||||
import { type SerializedType } from './serialized-type'
|
||||
import { DEFAULT_DEFINITIONS } from '../enums'
|
||||
|
||||
@@ -34,6 +35,7 @@ const coreTypes: Record<string, typeof SerializedType> = {
|
||||
UInt32,
|
||||
UInt64,
|
||||
Vector256,
|
||||
XChainBridge,
|
||||
}
|
||||
|
||||
// Ensures that the DEFAULT_DEFINITIONS object connects these types to fields for serializing/deserializing
|
||||
|
||||
128
packages/ripple-binary-codec/src/types/xchain-bridge.ts
Normal file
128
packages/ripple-binary-codec/src/types/xchain-bridge.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { BinaryParser } from '../serdes/binary-parser'
|
||||
|
||||
import { AccountID } from './account-id'
|
||||
import { JsonObject, SerializedType } from './serialized-type'
|
||||
import { Buffer } from 'buffer/'
|
||||
import { Issue, IssueObject } from './issue'
|
||||
|
||||
/**
|
||||
* Interface for JSON objects that represent cross-chain bridges
|
||||
*/
|
||||
interface XChainBridgeObject extends JsonObject {
|
||||
LockingChainDoor: string
|
||||
LockingChainIssue: IssueObject | string
|
||||
IssuingChainDoor: string
|
||||
IssuingChainIssue: IssueObject | string
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard for XChainBridgeObject
|
||||
*/
|
||||
function isXChainBridgeObject(arg): arg is XChainBridgeObject {
|
||||
const keys = Object.keys(arg).sort()
|
||||
return (
|
||||
keys.length === 4 &&
|
||||
keys[0] === 'IssuingChainDoor' &&
|
||||
keys[1] === 'IssuingChainIssue' &&
|
||||
keys[2] === 'LockingChainDoor' &&
|
||||
keys[3] === 'LockingChainIssue'
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for serializing/deserializing XChainBridges
|
||||
*/
|
||||
class XChainBridge extends SerializedType {
|
||||
static readonly ZERO_XCHAIN_BRIDGE: XChainBridge = new XChainBridge(
|
||||
Buffer.concat([
|
||||
Buffer.from([0x14]),
|
||||
Buffer.alloc(40),
|
||||
Buffer.from([0x14]),
|
||||
Buffer.alloc(40),
|
||||
]),
|
||||
)
|
||||
|
||||
static readonly TYPE_ORDER: { name: string; type: typeof SerializedType }[] =
|
||||
[
|
||||
{ name: 'LockingChainDoor', type: AccountID },
|
||||
{ name: 'LockingChainIssue', type: Issue },
|
||||
{ name: 'IssuingChainDoor', type: AccountID },
|
||||
{ name: 'IssuingChainIssue', type: Issue },
|
||||
]
|
||||
|
||||
constructor(bytes: Buffer) {
|
||||
super(bytes ?? XChainBridge.ZERO_XCHAIN_BRIDGE.bytes)
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a cross-chain bridge from a JSON
|
||||
*
|
||||
* @param value XChainBridge or JSON to parse into an XChainBridge
|
||||
* @returns An XChainBridge object
|
||||
*/
|
||||
static from<T extends XChainBridge | XChainBridgeObject>(
|
||||
value: T,
|
||||
): XChainBridge {
|
||||
if (value instanceof XChainBridge) {
|
||||
return value
|
||||
}
|
||||
|
||||
if (isXChainBridgeObject(value)) {
|
||||
const bytes: Array<Buffer> = []
|
||||
this.TYPE_ORDER.forEach((item) => {
|
||||
const { name, type } = item
|
||||
if (type === AccountID) {
|
||||
bytes.push(Buffer.from([0x14]))
|
||||
}
|
||||
const object = type.from(value[name])
|
||||
bytes.push(object.toBytes())
|
||||
})
|
||||
return new XChainBridge(Buffer.concat(bytes))
|
||||
}
|
||||
|
||||
throw new Error('Invalid type to construct an XChainBridge')
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an XChainBridge from a BinaryParser
|
||||
*
|
||||
* @param parser BinaryParser to read the XChainBridge from
|
||||
* @returns An XChainBridge object
|
||||
*/
|
||||
static fromParser(parser: BinaryParser): XChainBridge {
|
||||
const bytes: Array<Buffer> = []
|
||||
|
||||
this.TYPE_ORDER.forEach((item) => {
|
||||
const { type } = item
|
||||
if (type === AccountID) {
|
||||
parser.skip(1)
|
||||
bytes.push(Buffer.from([0x14]))
|
||||
}
|
||||
const object = type.fromParser(parser)
|
||||
bytes.push(object.toBytes())
|
||||
})
|
||||
|
||||
return new XChainBridge(Buffer.concat(bytes))
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JSON representation of this XChainBridge
|
||||
*
|
||||
* @returns the JSON interpretation of this.bytes
|
||||
*/
|
||||
toJSON(): XChainBridgeObject {
|
||||
const parser = new BinaryParser(this.toString())
|
||||
const json = {}
|
||||
XChainBridge.TYPE_ORDER.forEach((item) => {
|
||||
const { name, type } = item
|
||||
if (type === AccountID) {
|
||||
parser.skip(1)
|
||||
}
|
||||
const object = type.fromParser(parser).toJSON()
|
||||
json[name] = object
|
||||
})
|
||||
return json as XChainBridgeObject
|
||||
}
|
||||
}
|
||||
|
||||
export { XChainBridge, XChainBridgeObject }
|
||||
@@ -4435,7 +4435,8 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"transactions": [{
|
||||
"transactions": [
|
||||
{
|
||||
"binary": "1200002200000000240000003E6140000002540BE40068400000000000000A7321034AADB09CFF4A4804073701EC53C3510CDC95917C2BB0150FB742D0C66E6CEE9E74473045022022EB32AECEF7C644C891C19F87966DF9C62B1F34BABA6BE774325E4BB8E2DD62022100A51437898C28C2B297112DF8131F2BB39EA5FE613487DDD611525F17962646398114550FC62003E785DC231A1058A05E56E3F09CF4E68314D4CC8AB5B21D86A82C3E9E8D0ECF2404B77FECBA",
|
||||
"json": {
|
||||
"Account": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
@@ -4449,6 +4450,191 @@
|
||||
"Sequence": 62
|
||||
}
|
||||
},
|
||||
{
|
||||
"binary": "1200302200000000240000000168400000000000000A601D40000000000003E8601E400000000000271073210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020744630440220101BCA4B5B5A37C6F44480F9A34752C9AA8B2CDF5AD47E3CB424DEDC21C06DB702206EEB257E82A89B1F46A0A2C7F070B0BD181D980FF86FE4269E369F6FC7A270918114B5F762798A53D543A014CAF8B297CFF8F2F937E8011914AF80285F637EE4AF3C20378F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F09CF4E60000000000000000000000000000000000000000",
|
||||
"json": {
|
||||
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"XChainBridge": {
|
||||
"LockingChainDoor": "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL",
|
||||
"LockingChainIssue": {"currency": "XRP"},
|
||||
"IssuingChainDoor": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"IssuingChainIssue": {"currency": "XRP"}
|
||||
},
|
||||
"Fee": "10",
|
||||
"Flags": 0,
|
||||
"MinAccountCreateAmount": "10000",
|
||||
"Sequence": 1,
|
||||
"SignatureReward": "1000",
|
||||
"SigningPubKey": "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
|
||||
"TransactionType": "XChainCreateBridge",
|
||||
"TxnSignature": "30440220101BCA4B5B5A37C6F44480F9A34752C9AA8B2CDF5AD47E3CB424DEDC21C06DB702206EEB257E82A89B1F46A0A2C7F070B0BD181D980FF86FE4269E369F6FC7A27091"
|
||||
}
|
||||
},
|
||||
{
|
||||
"binary": "12002F2200000000240000000168400000000000000A601D40000000000003E8601E400000000000271073210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD02074473045022100D2CABC1B0E0635A8EE2E6554F6D474C49BC292C995C5C9F83179F4A60634B04C02205D1DB569D9593136F2FBEA7140010C8F46794D653AFDBEA8D30B8750BA4805E58114B5F762798A53D543A014CAF8B297CFF8F2F937E8011914AF80285F637EE4AF3C20378F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F09CF4E60000000000000000000000000000000000000000",
|
||||
"json": {
|
||||
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"XChainBridge": {
|
||||
"LockingChainDoor": "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL",
|
||||
"LockingChainIssue": {"currency": "XRP"},
|
||||
"IssuingChainDoor": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"IssuingChainIssue": {"currency": "XRP"}
|
||||
},
|
||||
"Fee": "10",
|
||||
"Flags": 0,
|
||||
"MinAccountCreateAmount": "10000",
|
||||
"Sequence": 1,
|
||||
"SignatureReward": "1000",
|
||||
"SigningPubKey": "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
|
||||
"TransactionType": "XChainModifyBridge",
|
||||
"TxnSignature": "3045022100D2CABC1B0E0635A8EE2E6554F6D474C49BC292C995C5C9F83179F4A60634B04C02205D1DB569D9593136F2FBEA7140010C8F46794D653AFDBEA8D30B8750BA4805E5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"binary": "1200292280000000240000000168400000000000000A601D400000000000271073210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020744630440220247B20A1B9C48E21A374CB9B3E1FE2A7C528151868DF8D307E9FBE15237E531A02207C20C092DDCC525E583EF4AB7CB91E862A6DED19426997D3F0A2C84E2BE8C5DD8114B5F762798A53D543A014CAF8B297CFF8F2F937E8801214AF80285F637EE4AF3C20378F9DFB12511ACB8D27011914AF80285F637EE4AF3C20378F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F09CF4E60000000000000000000000000000000000000000",
|
||||
"json": {
|
||||
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"XChainBridge": {
|
||||
"LockingChainDoor": "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL",
|
||||
"LockingChainIssue": {"currency": "XRP"},
|
||||
"IssuingChainDoor": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"IssuingChainIssue": {"currency": "XRP"}
|
||||
},
|
||||
"Fee": "10",
|
||||
"Flags": 2147483648,
|
||||
"OtherChainSource": "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL",
|
||||
"Sequence": 1,
|
||||
"SignatureReward": "10000",
|
||||
"SigningPubKey": "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
|
||||
"TransactionType": "XChainCreateClaimID",
|
||||
"TxnSignature": "30440220247B20A1B9C48E21A374CB9B3E1FE2A7C528151868DF8D307E9FBE15237E531A02207C20C092DDCC525E583EF4AB7CB91E862A6DED19426997D3F0A2C84E2BE8C5DD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"binary": "12002A228000000024000000013014000000000000000161400000000000271068400000000000000A73210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD02074453043021F177323F0D93612C82A4393A99B23905A7E675753FD80C52997AFAB13F5F9D002203BFFAF457E90BDA65AABE8F8762BD96162FAD98A0C030CCD69B06EE9B12BBFFE8114B5F762798A53D543A014CAF8B297CFF8F2F937E8011914AF80285F637EE4AF3C20378F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F09CF4E60000000000000000000000000000000000000000",
|
||||
"json": {
|
||||
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"Amount": "10000",
|
||||
"XChainBridge": {
|
||||
"LockingChainDoor": "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL",
|
||||
"LockingChainIssue": {"currency": "XRP"},
|
||||
"IssuingChainDoor": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"IssuingChainIssue": {"currency": "XRP"}
|
||||
},
|
||||
"Fee": "10",
|
||||
"Flags": 2147483648,
|
||||
"Sequence": 1,
|
||||
"SigningPubKey": "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
|
||||
"TransactionType": "XChainCommit",
|
||||
"TxnSignature": "3043021F177323F0D93612C82A4393A99B23905A7E675753FD80C52997AFAB13F5F9D002203BFFAF457E90BDA65AABE8F8762BD96162FAD98A0C030CCD69B06EE9B12BBFFE",
|
||||
"XChainClaimID": "0000000000000001"
|
||||
}
|
||||
},
|
||||
{
|
||||
"binary": "12002B228000000024000000013014000000000000000161400000000000271068400000000000000A73210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020744630440220445F7469FDA401787D9EE8A9B6E24DFF81E94F4C09FD311D2C0A58FCC02C684A022029E2EF34A5EA35F50D5BB57AC6320AD3AE12C13C8D1379B255A486D72CED142E8114B5F762798A53D543A014CAF8B297CFF8F2F937E88314550FC62003E785DC231A1058A05E56E3F09CF4E6011914AF80285F637EE4AF3C20378F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F09CF4E60000000000000000000000000000000000000000",
|
||||
"json": {
|
||||
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"Amount": "10000",
|
||||
"XChainBridge": {
|
||||
"LockingChainDoor": "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL",
|
||||
"LockingChainIssue": {"currency": "XRP"},
|
||||
"IssuingChainDoor": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"IssuingChainIssue": {"currency": "XRP"}
|
||||
},
|
||||
"Destination": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"Fee": "10",
|
||||
"Flags": 2147483648,
|
||||
"Sequence": 1,
|
||||
"SigningPubKey": "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
|
||||
"TransactionType": "XChainClaim",
|
||||
"TxnSignature": "30440220445F7469FDA401787D9EE8A9B6E24DFF81E94F4C09FD311D2C0A58FCC02C684A022029E2EF34A5EA35F50D5BB57AC6320AD3AE12C13C8D1379B255A486D72CED142E",
|
||||
"XChainClaimID": "0000000000000001"
|
||||
}
|
||||
},
|
||||
{
|
||||
"binary": "12002C228000000024000000016140000000000F424068400000000000000A601D400000000000271073210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD0207446304402202984DDE7F0B566F081F7953D7212BF031ACBF8860FE114102E9512C4C8768C77022070113F4630B1DC3045E4A98DDD648CEBC31B12774F7B44A1B8123CD2C9F5CF188114B5F762798A53D543A014CAF8B297CFF8F2F937E88314AF80285F637EE4AF3C20378F9DFB12511ACB8D27011914AF80285F637EE4AF3C20378F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F09CF4E60000000000000000000000000000000000000000",
|
||||
"json": {
|
||||
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"XChainBridge": {
|
||||
"LockingChainDoor": "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL",
|
||||
"LockingChainIssue": {"currency": "XRP"},
|
||||
"IssuingChainDoor": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"IssuingChainIssue": {"currency": "XRP"}
|
||||
},
|
||||
"Amount": "1000000",
|
||||
"Fee": "10",
|
||||
"Flags": 2147483648,
|
||||
"Destination": "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL",
|
||||
"Sequence": 1,
|
||||
"SignatureReward": "10000",
|
||||
"SigningPubKey": "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
|
||||
"TransactionType": "XChainAccountCreateCommit",
|
||||
"TxnSignature": "304402202984DDE7F0B566F081F7953D7212BF031ACBF8860FE114102E9512C4C8768C77022070113F4630B1DC3045E4A98DDD648CEBC31B12774F7B44A1B8123CD2C9F5CF18"
|
||||
}
|
||||
},
|
||||
{
|
||||
"binary": "12002E2400000005201B0000000D30150000000000000006614000000000989680684000000000000014601D40000000000000647121ED1F4A024ACFEBDB6C7AA88DEDE3364E060487EA31B14CC9E0D610D152B31AADC27321EDF54108BA2E0A0D3DC2AE3897F8BE0EFE776AE8D0F9FB0D0B9D64233084A8DDD1744003E74AEF1F585F156786429D2FC87A89E5C6B5A56D68BFC9A6A329F3AC67CBF2B6958283C663A4522278CA162C69B23CF75149AF022B410EA0508C16F42058007640EEFCFA3DC2AB4AB7C4D2EBBC168CB621A11B82BABD86534DFC8EFA72439A49662D744073CD848E7A587A95B35162CDF9A69BB237E72C9537A987F5B8C394F30D81145E7A3E3D7200A794FA801C66CE3775B6416EE4128314C15F113E49BCC4B9FFF43CD0366C23ACD82F75638012143FD9ED9A79DEA67CB5D585111FEF0A29203FA0408014145E7A3E3D7200A794FA801C66CE3775B6416EE4128015145E7A3E3D7200A794FA801C66CE3775B6416EE4120010130101191486F0B1126CE1205E59FDFDD2661A9FB7505CA70F000000000000000000000000000000000000000014B5F762798A53D543A014CAF8B297CFF8F2F937E80000000000000000000000000000000000000000",
|
||||
"json": {
|
||||
"Account": "r9cYxdjQsoXAEz3qQJc961SNLaXRkWXCvT",
|
||||
"Amount": "10000000",
|
||||
"AttestationRewardAccount": "r9cYxdjQsoXAEz3qQJc961SNLaXRkWXCvT",
|
||||
"AttestationSignerAccount": "r9cYxdjQsoXAEz3qQJc961SNLaXRkWXCvT",
|
||||
"Destination": "rJdTJRJZ6GXCCRaamHJgEqVzB7Zy4557Pi",
|
||||
"Fee": "20",
|
||||
"LastLedgerSequence": 13,
|
||||
"OtherChainSource": "raFcdz1g8LWJDJWJE2ZKLRGdmUmsTyxaym",
|
||||
"PublicKey": "ED1F4A024ACFEBDB6C7AA88DEDE3364E060487EA31B14CC9E0D610D152B31AADC2",
|
||||
"Sequence": 5,
|
||||
"Signature": "EEFCFA3DC2AB4AB7C4D2EBBC168CB621A11B82BABD86534DFC8EFA72439A49662D744073CD848E7A587A95B35162CDF9A69BB237E72C9537A987F5B8C394F30D",
|
||||
"SignatureReward": "100",
|
||||
"SigningPubKey": "EDF54108BA2E0A0D3DC2AE3897F8BE0EFE776AE8D0F9FB0D0B9D64233084A8DDD1",
|
||||
"TransactionType": "XChainAddAccountCreateAttestation",
|
||||
"TxnSignature": "03E74AEF1F585F156786429D2FC87A89E5C6B5A56D68BFC9A6A329F3AC67CBF2B6958283C663A4522278CA162C69B23CF75149AF022B410EA0508C16F4205800",
|
||||
"WasLockingChainSend": 1,
|
||||
"XChainAccountCreateCount": "0000000000000006",
|
||||
"XChainBridge": {
|
||||
"IssuingChainDoor": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"IssuingChainIssue": {
|
||||
"currency": "XRP"
|
||||
},
|
||||
"LockingChainDoor": "rDJVtEuDKr4rj1B3qtW7R5TVWdXV2DY7Qg",
|
||||
"LockingChainIssue": {
|
||||
"currency": "XRP"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"binary": "12002D2400000009201B00000013301400000000000000016140000000009896806840000000000000147121ED7541DEC700470F54276C90C333A13CDBB5D341FD43C60CEA12170F6D6D4E11367321ED0406B134786FE0751717226657F7BF8AFE96442C05D28ACEC66FB64852BA604C7440D0423649E48A44F181262CF5FC08A68E7FA5CD9E55843E4F09014B76E602574741E8553383A4B43CABD194BB96713647FC0B885BE248E4FFA068FA3E6994CF0476407C175050B08000AD35EEB2D87E16CD3F95A0AEEBF2A049474275153D9D4DD44528FE99AA50E71660A15B0B768E1B90E609BBD5DC7AFAFD45D9705D72D40EA10C81141F30A4D728AB98B0950EC3B9815E6C8D43A7D5598314C15F113E49BCC4B9FFF43CD0366C23ACD82F75638012143FD9ED9A79DEA67CB5D585111FEF0A29203FA0408014141F30A4D728AB98B0950EC3B9815E6C8D43A7D5598015141F30A4D728AB98B0950EC3B9815E6C8D43A7D5590010130101191486F0B1126CE1205E59FDFDD2661A9FB7505CA70F000000000000000000000000000000000000000014B5F762798A53D543A014CAF8B297CFF8F2F937E80000000000000000000000000000000000000000",
|
||||
"json": {
|
||||
"Account": "rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3",
|
||||
"Amount": "10000000",
|
||||
"AttestationRewardAccount": "rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3",
|
||||
"AttestationSignerAccount": "rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3",
|
||||
"Destination": "rJdTJRJZ6GXCCRaamHJgEqVzB7Zy4557Pi",
|
||||
"Fee": "20",
|
||||
"LastLedgerSequence": 19,
|
||||
"OtherChainSource": "raFcdz1g8LWJDJWJE2ZKLRGdmUmsTyxaym",
|
||||
"PublicKey": "ED7541DEC700470F54276C90C333A13CDBB5D341FD43C60CEA12170F6D6D4E1136",
|
||||
"Sequence": 9,
|
||||
"Signature": "7C175050B08000AD35EEB2D87E16CD3F95A0AEEBF2A049474275153D9D4DD44528FE99AA50E71660A15B0B768E1B90E609BBD5DC7AFAFD45D9705D72D40EA10C",
|
||||
"SigningPubKey": "ED0406B134786FE0751717226657F7BF8AFE96442C05D28ACEC66FB64852BA604C",
|
||||
"TransactionType": "XChainAddClaimAttestation",
|
||||
"TxnSignature": "D0423649E48A44F181262CF5FC08A68E7FA5CD9E55843E4F09014B76E602574741E8553383A4B43CABD194BB96713647FC0B885BE248E4FFA068FA3E6994CF04",
|
||||
"WasLockingChainSend": 1,
|
||||
"XChainBridge": {
|
||||
"IssuingChainDoor": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"IssuingChainIssue": {
|
||||
"currency": "XRP"
|
||||
},
|
||||
"LockingChainDoor": "rDJVtEuDKr4rj1B3qtW7R5TVWdXV2DY7Qg",
|
||||
"LockingChainIssue": {
|
||||
"currency": "XRP"
|
||||
}
|
||||
},
|
||||
"XChainClaimID": "0000000000000001"
|
||||
}
|
||||
},
|
||||
{
|
||||
"binary": "12002315000A2200000000240015DAE161400000000000271068400000000000000A6BD5838D7EA4C680000000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C7321ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B87440B3154D968314FCEB58001E1B0C3A4CFB33DF9FF6C73207E5EAEB9BD07E2747672168E1A2786D950495C38BD8DEE3391BF45F3008DD36F4B12E7C07D82CA5250E8114F92F27CC5EE2F2760278FE096D0CBE32BDD3653A",
|
||||
"json": {
|
||||
@@ -4655,7 +4841,8 @@
|
||||
"SigningPubKey": "ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8",
|
||||
"TxnSignature": "BC2F6E76969E3747E9BDE183C97573B086212F09D5387460E6EE2F32953E85EAEB9618FBBEF077276E30E59D619FCF7C7BDCDDDD9EB94D7CE1DD5CE9246B2107"
|
||||
}
|
||||
}],
|
||||
}
|
||||
],
|
||||
"ledgerData": [{
|
||||
"binary": "01E91435016340767BF1C4A3EACEB081770D8ADE216C85445DD6FB002C6B5A2930F2DECE006DA18150CB18F6DD33F6F0990754C962A7CCE62F332FF9C13939B03B864117F0BDA86B6E9B4F873B5C3E520634D343EF5D9D9A4246643D64DAD278BA95DC0EAC6EB5350CF970D521276CDE21276CE60A00",
|
||||
"json": {
|
||||
|
||||
@@ -84,7 +84,6 @@ module.exports = {
|
||||
'max-statements': 'off',
|
||||
// Snippets have logs on console to better understand the working.
|
||||
'no-console': 'off',
|
||||
'import/no-extraneous-dependencies': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -147,5 +146,17 @@ module.exports = {
|
||||
'import/no-unused-modules': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['tools/*.ts', 'tools/*.js'],
|
||||
rules: {
|
||||
'no-console': ['off'],
|
||||
'node/no-process-exit': ['off'],
|
||||
'@typescript-eslint/no-magic-numbers': ['off'],
|
||||
'max-lines-per-function': ['off'],
|
||||
'max-statements': ['off'],
|
||||
complexity: ['off'],
|
||||
'max-depth': ['warn', 3],
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xrpl-announce) for release announcements. We recommend that xrpl.js (ripple-lib) users stay up-to-date with the latest stable release.
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
* Added `ports` field to `ServerInfoResponse`
|
||||
* Support for the XChainBridge amendment.
|
||||
|
||||
### Fixed
|
||||
* Fix request model fields related to AMM
|
||||
|
||||
172
packages/xrpl/snippets/src/bridgeTransfer.ts
Normal file
172
packages/xrpl/snippets/src/bridgeTransfer.ts
Normal file
@@ -0,0 +1,172 @@
|
||||
/* eslint-disable max-depth -- needed for attestation checking */
|
||||
/* eslint-disable @typescript-eslint/consistent-type-assertions -- needed here */
|
||||
/* eslint-disable no-await-in-loop -- needed here */
|
||||
import {
|
||||
AccountObjectsRequest,
|
||||
LedgerEntry,
|
||||
Client,
|
||||
XChainAccountCreateCommit,
|
||||
XChainBridge,
|
||||
XChainCommit,
|
||||
XChainCreateClaimID,
|
||||
xrpToDrops,
|
||||
Wallet,
|
||||
getXChainClaimID,
|
||||
} from '../../src'
|
||||
|
||||
async function sleep(sec: number): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, sec * 1000)
|
||||
})
|
||||
}
|
||||
|
||||
const lockingClient = new Client(
|
||||
'wss://sidechain-net1.devnet.rippletest.net:51233',
|
||||
)
|
||||
const issuingClient = new Client(
|
||||
'wss://sidechain-net2.devnet.rippletest.net:51233',
|
||||
)
|
||||
const MAX_LEDGERS_WAITED = 5
|
||||
const LEDGER_CLOSE_TIME = 4
|
||||
|
||||
void bridgeTransfer()
|
||||
|
||||
async function bridgeTransfer(): Promise<void> {
|
||||
await lockingClient.connect()
|
||||
await issuingClient.connect()
|
||||
const lockingChainDoor = 'rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4'
|
||||
|
||||
const accountObjectsRequest: AccountObjectsRequest = {
|
||||
command: 'account_objects',
|
||||
account: lockingChainDoor,
|
||||
type: 'bridge',
|
||||
}
|
||||
const lockingAccountObjects = (
|
||||
await lockingClient.request(accountObjectsRequest)
|
||||
).result.account_objects
|
||||
// There will only be one here - a door account can only have one bridge per currency
|
||||
const bridgeData = lockingAccountObjects.filter(
|
||||
(obj) =>
|
||||
obj.LedgerEntryType === 'Bridge' &&
|
||||
obj.XChainBridge.LockingChainIssue.currency === 'XRP',
|
||||
)[0] as LedgerEntry.Bridge
|
||||
const bridge: XChainBridge = bridgeData.XChainBridge
|
||||
console.log(bridge)
|
||||
|
||||
console.log('Creating wallet on the locking chain via the faucet...')
|
||||
const { wallet: wallet1 } = await lockingClient.fundWallet()
|
||||
console.log(wallet1)
|
||||
const wallet2 = Wallet.generate()
|
||||
|
||||
console.log(
|
||||
`Creating ${wallet2.classicAddress} on the issuing chain via the bridge...`,
|
||||
)
|
||||
|
||||
const fundTx: XChainAccountCreateCommit = {
|
||||
TransactionType: 'XChainAccountCreateCommit',
|
||||
Account: wallet1.classicAddress,
|
||||
XChainBridge: bridge,
|
||||
SignatureReward: bridgeData.SignatureReward,
|
||||
Destination: wallet2.classicAddress,
|
||||
Amount: (
|
||||
parseInt(bridgeData.MinAccountCreateAmount as string, 10) * 2
|
||||
).toString(),
|
||||
}
|
||||
const fundResponse = await lockingClient.submitAndWait(fundTx, {
|
||||
wallet: wallet1,
|
||||
})
|
||||
console.log(fundResponse)
|
||||
|
||||
console.log(
|
||||
'Waiting for the attestation to go through... (usually 8-12 seconds)',
|
||||
)
|
||||
let ledgersWaited = 0
|
||||
let initialBalance = '0'
|
||||
while (ledgersWaited < MAX_LEDGERS_WAITED) {
|
||||
await sleep(LEDGER_CLOSE_TIME)
|
||||
try {
|
||||
initialBalance = await issuingClient.getXrpBalance(wallet2.classicAddress)
|
||||
console.log(
|
||||
`Wallet ${wallet2.classicAddress} has been funded with a balance of ${initialBalance} XRP`,
|
||||
)
|
||||
break
|
||||
} catch (_error) {
|
||||
ledgersWaited += 1
|
||||
if (ledgersWaited === MAX_LEDGERS_WAITED) {
|
||||
// This error should never be hit if the bridge is running
|
||||
throw Error('Destination account creation via the bridge failed.')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Transferring funds from ${wallet1.classicAddress} on the locking chain to ` +
|
||||
`${wallet2.classicAddress} on the issuing_chain...`,
|
||||
)
|
||||
|
||||
// Fetch the claim ID for the transfer
|
||||
console.log('Step 1: Fetching the claim ID for the transfer...')
|
||||
const claimIdTx: XChainCreateClaimID = {
|
||||
TransactionType: 'XChainCreateClaimID',
|
||||
Account: wallet2.classicAddress,
|
||||
XChainBridge: bridge,
|
||||
SignatureReward: bridgeData.SignatureReward,
|
||||
OtherChainSource: wallet1.classicAddress,
|
||||
}
|
||||
const claimIdResult = await issuingClient.submitAndWait(claimIdTx, {
|
||||
wallet: wallet2,
|
||||
})
|
||||
console.log(claimIdResult)
|
||||
|
||||
// Extract new claim ID from metadata
|
||||
const xchainClaimId = getXChainClaimID(claimIdResult.result.meta)
|
||||
if (xchainClaimId == null) {
|
||||
// This shouldn't trigger assuming the transaction succeeded
|
||||
throw Error('Could not extract XChainClaimID')
|
||||
}
|
||||
|
||||
console.log(`Claim ID for the transfer: ${xchainClaimId}`)
|
||||
|
||||
console.log(
|
||||
'Step 2: Locking the funds on the locking chain with an XChainCommit transaction...',
|
||||
)
|
||||
const commitTx: XChainCommit = {
|
||||
TransactionType: 'XChainCommit',
|
||||
Account: wallet1.classicAddress,
|
||||
Amount: xrpToDrops(1),
|
||||
XChainBridge: bridge,
|
||||
XChainClaimID: xchainClaimId,
|
||||
OtherChainDestination: wallet2.classicAddress,
|
||||
}
|
||||
const commitResult = await lockingClient.submitAndWait(commitTx, {
|
||||
wallet: wallet1,
|
||||
})
|
||||
console.log(commitResult)
|
||||
|
||||
console.log(
|
||||
'Waiting for the attestation to go through... (usually 8-12 seconds)',
|
||||
)
|
||||
ledgersWaited = 0
|
||||
while (ledgersWaited < MAX_LEDGERS_WAITED) {
|
||||
await sleep(LEDGER_CLOSE_TIME)
|
||||
const currentBalance = await issuingClient.getXrpBalance(
|
||||
wallet2.classicAddress,
|
||||
)
|
||||
console.log(initialBalance, currentBalance)
|
||||
if (parseFloat(currentBalance) > parseFloat(initialBalance)) {
|
||||
console.log('Transfer is complete')
|
||||
console.log(
|
||||
`New balance of ${wallet2.classicAddress} is ${currentBalance} XRP`,
|
||||
)
|
||||
break
|
||||
}
|
||||
|
||||
ledgersWaited += 1
|
||||
if (ledgersWaited === MAX_LEDGERS_WAITED) {
|
||||
throw Error('Bridge transfer failed.')
|
||||
}
|
||||
}
|
||||
|
||||
await lockingClient.disconnect()
|
||||
await issuingClient.disconnect()
|
||||
}
|
||||
@@ -2,7 +2,7 @@ export type LedgerIndex = number | ('validated' | 'closed' | 'current')
|
||||
|
||||
export interface XRP {
|
||||
currency: 'XRP'
|
||||
issuer: never
|
||||
issuer?: never
|
||||
}
|
||||
|
||||
export interface IssuedCurrency {
|
||||
@@ -148,3 +148,10 @@ export interface AuthAccount {
|
||||
Account: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface XChainBridge {
|
||||
LockingChainDoor: string
|
||||
LockingChainIssue: Currency
|
||||
IssuingChainDoor: string
|
||||
IssuingChainIssue: Currency
|
||||
}
|
||||
|
||||
84
packages/xrpl/src/models/ledger/Bridge.ts
Normal file
84
packages/xrpl/src/models/ledger/Bridge.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { Amount, XChainBridge } from '../common'
|
||||
|
||||
import BaseLedgerEntry from './BaseLedgerEntry'
|
||||
|
||||
/**
|
||||
* A Bridge objects represents a cross-chain bridge and includes information about
|
||||
* the door accounts, assets, signature rewards, and the minimum account create
|
||||
* amount.
|
||||
*
|
||||
* @category Ledger Entries
|
||||
*/
|
||||
export default interface Bridge extends BaseLedgerEntry {
|
||||
LedgerEntryType: 'Bridge'
|
||||
|
||||
/** The door account that owns the bridge. */
|
||||
Account: string
|
||||
|
||||
/**
|
||||
* The total amount, in XRP, to be rewarded for providing a signature for
|
||||
* cross-chain transfer or for signing for the cross-chain reward. This amount
|
||||
* will be split among the signers.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
XChainBridge: XChainBridge
|
||||
|
||||
/**
|
||||
* The value of the next XChainClaimID to be created.
|
||||
*/
|
||||
XChainClaimID: string
|
||||
|
||||
/**
|
||||
* A counter used to order the execution of account create transactions. It is
|
||||
* incremented every time a successful {@link XChainAccountCreateCommit}
|
||||
* transaction is run for the source chain.
|
||||
*/
|
||||
XChainAccountCreateCount: string
|
||||
|
||||
/**
|
||||
* A counter used to order the execution of account create transactions. It is
|
||||
* incremented every time a {@link XChainAccountCreateCommit} transaction is
|
||||
* "claimed" on the destination chain. When the "claim" transaction is run on
|
||||
* the destination chain, the XChainAccountClaimCount must match the value that
|
||||
* the XChainAccountCreateCount had at the time the XChainAccountClaimCount was
|
||||
* run on the source chain. This orders the claims so that they run in the same
|
||||
* order that the XChainAccountCreateCommit transactions ran on the source chain,
|
||||
* to prevent transaction replay.
|
||||
*/
|
||||
XChainAccountClaimCount: string
|
||||
|
||||
/**
|
||||
* A bit-map of boolean flags. No flags are defined for Bridges, so this value
|
||||
* is always 0.
|
||||
*/
|
||||
Flags: 0
|
||||
|
||||
/**
|
||||
* A hint indicating which page of the sender's owner directory links to this
|
||||
* object, in case the directory consists of multiple pages.
|
||||
*/
|
||||
OwnerNode: string
|
||||
|
||||
/**
|
||||
* The identifying hash of the transaction that most recently modified this
|
||||
* object.
|
||||
*/
|
||||
PreviousTxnID: string
|
||||
|
||||
/**
|
||||
* The index of the ledger that contains the transaction that most recently
|
||||
* modified this object.
|
||||
*/
|
||||
PreviousTxnLgrSeq: number
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import AccountRoot from './AccountRoot'
|
||||
import Amendments from './Amendments'
|
||||
import AMM from './AMM'
|
||||
import Bridge from './Bridge'
|
||||
import Check from './Check'
|
||||
import DepositPreauth from './DepositPreauth'
|
||||
import DirectoryNode from './DirectoryNode'
|
||||
@@ -13,11 +14,14 @@ import PayChannel from './PayChannel'
|
||||
import RippleState from './RippleState'
|
||||
import SignerList from './SignerList'
|
||||
import Ticket from './Ticket'
|
||||
import XChainOwnedClaimID from './XChainOwnedClaimID'
|
||||
import XChainOwnedCreateAccountClaimID from './XChainOwnedCreateAccountClaimID'
|
||||
|
||||
type LedgerEntry =
|
||||
| AccountRoot
|
||||
| Amendments
|
||||
| AMM
|
||||
| Bridge
|
||||
| Check
|
||||
| DepositPreauth
|
||||
| DirectoryNode
|
||||
@@ -30,5 +34,7 @@ type LedgerEntry =
|
||||
| RippleState
|
||||
| SignerList
|
||||
| Ticket
|
||||
| XChainOwnedClaimID
|
||||
| XChainOwnedCreateAccountClaimID
|
||||
|
||||
export default LedgerEntry
|
||||
|
||||
89
packages/xrpl/src/models/ledger/XChainOwnedClaimID.ts
Normal file
89
packages/xrpl/src/models/ledger/XChainOwnedClaimID.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Amount } from 'ripple-binary-codec/dist/types'
|
||||
|
||||
import { XChainBridge } from '../common'
|
||||
|
||||
import BaseLedgerEntry from './BaseLedgerEntry'
|
||||
|
||||
/**
|
||||
* An XChainOwnedClaimID object represents one cross-chain transfer of value
|
||||
* and includes information of the account on the source chain that locks or
|
||||
* burns the funds on the source chain.
|
||||
*
|
||||
* @category Ledger Entries
|
||||
*/
|
||||
export default interface XChainOwnedClaimID extends BaseLedgerEntry {
|
||||
LedgerEntryType: 'XChainOwnedClaimID'
|
||||
|
||||
/** The account that checked out this unique claim ID value. */
|
||||
Account: string
|
||||
|
||||
/**
|
||||
* The door accounts and assets of the bridge this object correlates to.
|
||||
*/
|
||||
XChainBridge: XChainBridge
|
||||
|
||||
/**
|
||||
* The unique sequence number for a cross-chain transfer.
|
||||
*/
|
||||
XChainClaimID: string
|
||||
|
||||
/**
|
||||
* The account that must send the corresponding {@link XChainCommit} on the
|
||||
* source chain. The destination may be specified in the {@link XChainCommit}
|
||||
* transaction, which means that if the OtherChainSource isn't specified,
|
||||
* another account can try to specify a different destination and steal the
|
||||
* funds. This also allows tracking only a single set of signatures, since we
|
||||
* know which account will send the {@link XChainCommit} transaction.
|
||||
*/
|
||||
OtherChainSource: string
|
||||
|
||||
/**
|
||||
* Attestations collected from the witness servers. This includes the parameters
|
||||
* needed to recreate the message that was signed, including the amount, which
|
||||
* chain (locking or issuing), optional destination, and reward account for that
|
||||
* signature.
|
||||
*/
|
||||
XChainClaimAttestations: Array<{
|
||||
// TODO: add docs
|
||||
XChainClaimProofSig: {
|
||||
Amount: Amount
|
||||
|
||||
AttestationRewardAccount: string
|
||||
|
||||
AttestationSignerAccount: string
|
||||
|
||||
Destination?: string
|
||||
|
||||
PublicKey: string
|
||||
|
||||
WasLockingChainSend: 0 | 1
|
||||
}
|
||||
}>
|
||||
|
||||
/**
|
||||
* The total amount to pay the witness servers for their signatures. It must be at
|
||||
* least the value of the SignatureReward in the {@link Bridge} ledger object.
|
||||
*/
|
||||
SignatureReward: string
|
||||
|
||||
/**
|
||||
* A bit-map of boolean flags. No flags are defined for XChainOwnedClaimIDs,
|
||||
* so this value is always 0.
|
||||
*/
|
||||
Flags: 0
|
||||
/**
|
||||
* A hint indicating which page of the sender's owner directory links to this
|
||||
* object, in case the directory consists of multiple pages.
|
||||
*/
|
||||
OwnerNode: string
|
||||
/**
|
||||
* The identifying hash of the transaction that most recently modified this
|
||||
* object.
|
||||
*/
|
||||
PreviousTxnID: string
|
||||
/**
|
||||
* The index of the ledger that contains the transaction that most recently
|
||||
* modified this object.
|
||||
*/
|
||||
PreviousTxnLgrSeq: number
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { XChainBridge } from '../common'
|
||||
|
||||
import BaseLedgerEntry from './BaseLedgerEntry'
|
||||
|
||||
/**
|
||||
* The XChainOwnedCreateAccountClaimID ledger object is used to collect attestations
|
||||
* for creating an account via a cross-chain transfer.
|
||||
*
|
||||
* @category Ledger Entries
|
||||
*/
|
||||
export default interface XChainOwnedCreateAccountClaimID
|
||||
extends BaseLedgerEntry {
|
||||
LedgerEntryType: 'XChainOwnedCreateAccountClaimID'
|
||||
|
||||
/** The account that owns this object. */
|
||||
Account: string
|
||||
|
||||
/**
|
||||
* The door accounts and assets of the bridge this object correlates to.
|
||||
*/
|
||||
XChainBridge: XChainBridge
|
||||
|
||||
/**
|
||||
* An integer that determines the order that accounts created through
|
||||
* cross-chain transfers must be performed. Smaller numbers must execute
|
||||
* before larger numbers.
|
||||
*/
|
||||
XChainAccountCreateCount: number
|
||||
|
||||
/**
|
||||
* Attestations collected from the witness servers. This includes the parameters
|
||||
* needed to recreate the message that was signed, including the amount, destination,
|
||||
* signature reward amount, and reward account for that signature. With the
|
||||
* exception of the reward account, all signatures must sign the message created with
|
||||
* common parameters.
|
||||
*/
|
||||
XChainCreateAccountAttestations: Array<{
|
||||
// TODO: add docs
|
||||
XChainCreateAccountProofSig: {
|
||||
Amount: string
|
||||
|
||||
AttestationRewardAccount: string
|
||||
|
||||
AttestationSignerAccount: string
|
||||
|
||||
Destination: string
|
||||
|
||||
PublicKey: string
|
||||
|
||||
WasLockingChainSend: 0 | 1
|
||||
}
|
||||
}>
|
||||
|
||||
/**
|
||||
* A bit-map of boolean flags. No flags are defined for,
|
||||
* XChainOwnedCreateAccountClaimIDs, so this value is always 0.
|
||||
*/
|
||||
Flags: 0
|
||||
/**
|
||||
* A hint indicating which page of the sender's owner directory links to this
|
||||
* object, in case the directory consists of multiple pages.
|
||||
*/
|
||||
OwnerNode: string
|
||||
/**
|
||||
* The identifying hash of the transaction that most recently modified this
|
||||
* object.
|
||||
*/
|
||||
PreviousTxnID: string
|
||||
/**
|
||||
* The index of the ledger that contains the transaction that most recently
|
||||
* modified this object.
|
||||
*/
|
||||
PreviousTxnLgrSeq: number
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import AccountRoot, {
|
||||
} from './AccountRoot'
|
||||
import Amendments, { Majority, AMENDMENTS_ID } from './Amendments'
|
||||
import AMM, { VoteSlot } from './AMM'
|
||||
import Bridge from './Bridge'
|
||||
import Check from './Check'
|
||||
import DepositPreauth from './DepositPreauth'
|
||||
import DirectoryNode from './DirectoryNode'
|
||||
@@ -24,6 +25,8 @@ import PayChannel from './PayChannel'
|
||||
import RippleState, { RippleStateFlags } from './RippleState'
|
||||
import SignerList, { SignerListFlags } from './SignerList'
|
||||
import Ticket from './Ticket'
|
||||
import XChainOwnedClaimID from './XChainOwnedClaimID'
|
||||
import XChainOwnedCreateAccountClaimID from './XChainOwnedCreateAccountClaimID'
|
||||
|
||||
export {
|
||||
AccountRoot,
|
||||
@@ -32,6 +35,7 @@ export {
|
||||
AMENDMENTS_ID,
|
||||
Amendments,
|
||||
AMM,
|
||||
Bridge,
|
||||
Check,
|
||||
DepositPreauth,
|
||||
DirectoryNode,
|
||||
@@ -57,5 +61,7 @@ export {
|
||||
SignerList,
|
||||
SignerListFlags,
|
||||
Ticket,
|
||||
XChainOwnedClaimID,
|
||||
XChainOwnedCreateAccountClaimID,
|
||||
VoteSlot,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
AMM,
|
||||
Bridge,
|
||||
Check,
|
||||
DepositPreauth,
|
||||
Escrow,
|
||||
@@ -8,12 +9,15 @@ import {
|
||||
RippleState,
|
||||
SignerList,
|
||||
Ticket,
|
||||
XChainOwnedClaimID,
|
||||
XChainOwnedCreateAccountClaimID,
|
||||
} from '../ledger'
|
||||
|
||||
import { BaseRequest, BaseResponse, LookupByLedgerRequest } from './baseMethod'
|
||||
|
||||
export type AccountObjectType =
|
||||
| 'amm'
|
||||
| 'bridge'
|
||||
| 'check'
|
||||
| 'deposit_preauth'
|
||||
| 'escrow'
|
||||
@@ -23,6 +27,8 @@ export type AccountObjectType =
|
||||
| 'signer_list'
|
||||
| 'state'
|
||||
| 'ticket'
|
||||
| 'xchain_owned_create_account_claim_id'
|
||||
| 'xchain_owned_claim_id'
|
||||
|
||||
/**
|
||||
* The account_objects command returns the raw ledger format for all objects
|
||||
@@ -67,6 +73,7 @@ export interface AccountObjectsRequest
|
||||
*/
|
||||
export type AccountObject =
|
||||
| AMM
|
||||
| Bridge
|
||||
| Check
|
||||
| DepositPreauth
|
||||
| Escrow
|
||||
@@ -75,6 +82,8 @@ export type AccountObject =
|
||||
| SignerList
|
||||
| RippleState
|
||||
| Ticket
|
||||
| XChainOwnedClaimID
|
||||
| XChainOwnedCreateAccountClaimID
|
||||
|
||||
/**
|
||||
* Response expected from an {@link AccountObjectsRequest}.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Currency, XChainBridge } from '../common'
|
||||
import { LedgerEntry } from '../ledger'
|
||||
|
||||
import { BaseRequest, BaseResponse, LookupByLedgerRequest } from './baseMethod'
|
||||
@@ -152,6 +153,30 @@ export interface LedgerEntryRequest extends BaseRequest, LookupByLedgerRequest {
|
||||
* Must be the object ID of the NFToken page, as hexadecimal
|
||||
*/
|
||||
nft_page?: string
|
||||
|
||||
bridge_account?: string
|
||||
|
||||
bridge?: XChainBridge
|
||||
|
||||
xchain_owned_claim_id?:
|
||||
| {
|
||||
locking_chain_door: string
|
||||
locking_chain_issue: Currency
|
||||
issuing_chain_door: string
|
||||
issuing_chain_issue: Currency
|
||||
xchain_owned_claim_id: string | number
|
||||
}
|
||||
| string
|
||||
|
||||
xchain_owned_create_account_claim_id?:
|
||||
| {
|
||||
locking_chain_door: string
|
||||
locking_chain_issue: Currency
|
||||
issuing_chain_door: string
|
||||
issuing_chain_issue: Currency
|
||||
xchain_owned_create_account_claim_id: string | number
|
||||
}
|
||||
| string
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import { isString } from 'lodash'
|
||||
|
||||
import { Amount, XChainBridge } from '../common'
|
||||
|
||||
import {
|
||||
BaseTransaction,
|
||||
isAmount,
|
||||
isXChainBridge,
|
||||
validateBaseTransaction,
|
||||
validateRequiredField,
|
||||
} from './common'
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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,
|
||||
* the bridge's MinAccountCreateAmount shouldn't be present.
|
||||
*
|
||||
* @category Transaction Models
|
||||
*/
|
||||
export interface XChainAccountCreateCommit extends BaseTransaction {
|
||||
TransactionType: 'XChainAccountCreateCommit'
|
||||
|
||||
/**
|
||||
* The bridge to create accounts for.
|
||||
*/
|
||||
XChainBridge: XChainBridge
|
||||
|
||||
/**
|
||||
* The amount, in XRP, to be used to reward the witness servers for providing
|
||||
* signatures. This must match the amount on the {@link Bridge} ledger object.
|
||||
*/
|
||||
SignatureReward: Amount
|
||||
|
||||
/**
|
||||
* The destination account on the destination chain.
|
||||
*/
|
||||
Destination: string
|
||||
|
||||
/**
|
||||
* The amount, in XRP, to use for account creation. This must be greater than or
|
||||
* equal to the MinAccountCreateAmount specified in the {@link Bridge} ledger object.
|
||||
*/
|
||||
Amount: Amount
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the form and type of an XChainAccountCreateCommit at runtime.
|
||||
*
|
||||
* @param tx - An XChainAccountCreateCommit Transaction.
|
||||
* @throws When the XChainAccountCreateCommit is malformed.
|
||||
*/
|
||||
export function validateXChainAccountCreateCommit(
|
||||
tx: Record<string, unknown>,
|
||||
): void {
|
||||
validateBaseTransaction(tx)
|
||||
|
||||
validateRequiredField(tx, 'XChainBridge', isXChainBridge)
|
||||
|
||||
validateRequiredField(tx, 'SignatureReward', isAmount)
|
||||
|
||||
validateRequiredField(tx, 'Destination', isString)
|
||||
|
||||
validateRequiredField(tx, 'Amount', isAmount)
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
import { Amount, XChainBridge } from '../common'
|
||||
|
||||
import {
|
||||
BaseTransaction,
|
||||
isAmount,
|
||||
isNumber,
|
||||
isString,
|
||||
isXChainBridge,
|
||||
validateBaseTransaction,
|
||||
validateRequiredField,
|
||||
} from './common'
|
||||
|
||||
/**
|
||||
* The XChainAddAccountCreateAttestation transaction provides an attestation
|
||||
* from a witness server that a {@link XChainAccountCreateCommit} transaction
|
||||
* occurred on the other chain.
|
||||
*
|
||||
* @category Transaction Models
|
||||
*/
|
||||
export interface XChainAddAccountCreateAttestation extends BaseTransaction {
|
||||
TransactionType: 'XChainAddAccountCreateAttestation'
|
||||
|
||||
/**
|
||||
* The amount committed by the {@link XChainAccountCreateCommit} transaction
|
||||
* on the source chain.
|
||||
*/
|
||||
Amount: Amount
|
||||
|
||||
/**
|
||||
* The account that should receive this signer's share of the SignatureReward.
|
||||
*/
|
||||
AttestationRewardAccount: string
|
||||
|
||||
/**
|
||||
* The account on the door account's signer list that is signing the transaction.
|
||||
*/
|
||||
AttestationSignerAccount: string
|
||||
|
||||
/**
|
||||
* The destination account for the funds on the destination chain.
|
||||
*/
|
||||
Destination: string
|
||||
|
||||
/**
|
||||
* The account on the source chain that submitted the {@link XChainAccountCreateCommit}
|
||||
* transaction that triggered the event associated with the attestation.
|
||||
*/
|
||||
OtherChainSource: string
|
||||
|
||||
/**
|
||||
* The public key used to verify the signature.
|
||||
*/
|
||||
PublicKey: string
|
||||
|
||||
/**
|
||||
* The signature attesting to the event on the other chain.
|
||||
*/
|
||||
Signature: string
|
||||
|
||||
/**
|
||||
* The signature reward paid in the {@link XChainAccountCreateCommit} transaction.
|
||||
*/
|
||||
SignatureReward: Amount
|
||||
|
||||
/**
|
||||
* A boolean representing the chain where the event occurred.
|
||||
*/
|
||||
WasLockingChainSend: 0 | 1
|
||||
|
||||
/**
|
||||
* The counter that represents the order that the claims must be processed in.
|
||||
*/
|
||||
XChainAccountCreateCount: number | string
|
||||
|
||||
/**
|
||||
* The bridge associated with the attestation.
|
||||
*/
|
||||
XChainBridge: XChainBridge
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the form and type of an XChainAddAccountCreateAttestation at runtime.
|
||||
*
|
||||
* @param tx - An XChainAddAccountCreateAttestation Transaction.
|
||||
* @throws When the XChainAddAccountCreateAttestation is malformed.
|
||||
*/
|
||||
export function validateXChainAddAccountCreateAttestation(
|
||||
tx: Record<string, unknown>,
|
||||
): void {
|
||||
validateBaseTransaction(tx)
|
||||
|
||||
validateRequiredField(tx, 'Amount', isAmount)
|
||||
|
||||
validateRequiredField(tx, 'AttestationRewardAccount', isString)
|
||||
|
||||
validateRequiredField(tx, 'AttestationSignerAccount', isString)
|
||||
|
||||
validateRequiredField(tx, 'Destination', isString)
|
||||
|
||||
validateRequiredField(tx, 'OtherChainSource', isString)
|
||||
|
||||
validateRequiredField(tx, 'PublicKey', isString)
|
||||
|
||||
validateRequiredField(tx, 'Signature', isString)
|
||||
|
||||
validateRequiredField(tx, 'SignatureReward', isAmount)
|
||||
|
||||
validateRequiredField(
|
||||
tx,
|
||||
'WasLockingChainSend',
|
||||
(inp) => inp === 0 || inp === 1,
|
||||
)
|
||||
|
||||
validateRequiredField(
|
||||
tx,
|
||||
'XChainAccountCreateCount',
|
||||
(inp) => isNumber(inp) || isString(inp),
|
||||
)
|
||||
|
||||
validateRequiredField(tx, 'XChainBridge', isXChainBridge)
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
import { Amount, XChainBridge } from '../common'
|
||||
|
||||
import {
|
||||
BaseTransaction,
|
||||
isAmount,
|
||||
isNumber,
|
||||
isString,
|
||||
isXChainBridge,
|
||||
validateBaseTransaction,
|
||||
validateOptionalField,
|
||||
validateRequiredField,
|
||||
} from './common'
|
||||
|
||||
/**
|
||||
* The XChainAddClaimAttestation transaction provides proof from a witness server,
|
||||
* attesting to an {@link XChainCommit} transaction.
|
||||
*
|
||||
* @category Transaction Models
|
||||
*/
|
||||
export interface XChainAddClaimAttestation extends BaseTransaction {
|
||||
TransactionType: 'XChainAddClaimAttestation'
|
||||
|
||||
/**
|
||||
* The amount committed by the {@link XChainCommit} transaction on the source chain.
|
||||
*/
|
||||
Amount: Amount
|
||||
|
||||
/**
|
||||
* The account that should receive this signer's share of the SignatureReward.
|
||||
*/
|
||||
AttestationRewardAccount: string
|
||||
|
||||
/**
|
||||
* The account on the door account's signer list that is signing the transaction.
|
||||
*/
|
||||
AttestationSignerAccount: string
|
||||
|
||||
/**
|
||||
* The destination account for the funds on the destination chain (taken from
|
||||
* the {@link XChainCommit} transaction).
|
||||
*/
|
||||
Destination?: string
|
||||
|
||||
/**
|
||||
* The account on the source chain that submitted the {@link XChainCommit}
|
||||
* transaction that triggered the event associated with the attestation.
|
||||
*/
|
||||
OtherChainSource: string
|
||||
|
||||
/**
|
||||
* The public key used to verify the attestation signature.
|
||||
*/
|
||||
PublicKey: string
|
||||
|
||||
/**
|
||||
* The signature attesting to the event on the other chain.
|
||||
*/
|
||||
Signature: string
|
||||
|
||||
/**
|
||||
* A boolean representing the chain where the event occurred.
|
||||
*/
|
||||
WasLockingChainSend: 0 | 1
|
||||
|
||||
/**
|
||||
* The bridge to use to transfer funds.
|
||||
*/
|
||||
XChainBridge: XChainBridge
|
||||
|
||||
/**
|
||||
* The XChainClaimID associated with the transfer, which was included in the
|
||||
* {@link XChainCommit} transaction.
|
||||
*/
|
||||
XChainClaimID: number | string
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the form and type of an XChainAddClaimAttestation at runtime.
|
||||
*
|
||||
* @param tx - An XChainAddClaimAttestation Transaction.
|
||||
* @throws When the XChainAddClaimAttestation is malformed.
|
||||
*/
|
||||
export function validateXChainAddClaimAttestation(
|
||||
tx: Record<string, unknown>,
|
||||
): void {
|
||||
validateBaseTransaction(tx)
|
||||
|
||||
validateRequiredField(tx, 'Amount', isAmount)
|
||||
|
||||
validateRequiredField(tx, 'AttestationRewardAccount', isString)
|
||||
|
||||
validateRequiredField(tx, 'AttestationSignerAccount', isString)
|
||||
|
||||
validateOptionalField(tx, 'Destination', isString)
|
||||
|
||||
validateRequiredField(tx, 'OtherChainSource', isString)
|
||||
|
||||
validateRequiredField(tx, 'PublicKey', isString)
|
||||
|
||||
validateRequiredField(tx, 'Signature', isString)
|
||||
|
||||
validateRequiredField(
|
||||
tx,
|
||||
'WasLockingChainSend',
|
||||
(inp) => inp === 0 || inp === 1,
|
||||
)
|
||||
|
||||
validateRequiredField(tx, 'XChainBridge', isXChainBridge)
|
||||
|
||||
validateRequiredField(
|
||||
tx,
|
||||
'XChainClaimID',
|
||||
(inp) => isNumber(inp) || isString(inp),
|
||||
)
|
||||
}
|
||||
77
packages/xrpl/src/models/transactions/XChainClaim.ts
Normal file
77
packages/xrpl/src/models/transactions/XChainClaim.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { Amount, XChainBridge } from '../common'
|
||||
|
||||
import {
|
||||
BaseTransaction,
|
||||
isAmount,
|
||||
isNumber,
|
||||
isString,
|
||||
isXChainBridge,
|
||||
validateBaseTransaction,
|
||||
validateOptionalField,
|
||||
validateRequiredField,
|
||||
} from './common'
|
||||
|
||||
/**
|
||||
* The XChainClaim transaction completes a cross-chain transfer of value. It
|
||||
* allows a user to claim the value on the destination chain - the equivalent
|
||||
* of the value locked on the source chain.
|
||||
*
|
||||
* @category Transaction Models
|
||||
*/
|
||||
export interface XChainClaim extends BaseTransaction {
|
||||
TransactionType: 'XChainClaim'
|
||||
|
||||
/**
|
||||
* The bridge to use for the transfer.
|
||||
*/
|
||||
XChainBridge: XChainBridge
|
||||
|
||||
/**
|
||||
* The unique integer ID for the cross-chain transfer that was referenced in the
|
||||
* corresponding {@link XChainCommit} transaction.
|
||||
*/
|
||||
XChainClaimID: number | string
|
||||
|
||||
/**
|
||||
* The destination account on the destination chain. It must exist or the
|
||||
* transaction will fail. However, if the transaction fails in this case, the
|
||||
* sequence number and collected signatures won't be destroyed, and the
|
||||
* transaction can be rerun with a different destination.
|
||||
*/
|
||||
Destination: string
|
||||
|
||||
/**
|
||||
* An integer destination tag.
|
||||
*/
|
||||
DestinationTag?: number
|
||||
|
||||
/**
|
||||
* The amount to claim on the destination chain. This must match the amount
|
||||
* attested to on the attestations associated with this XChainClaimID.
|
||||
*/
|
||||
Amount: Amount
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the form and type of an XChainClaim at runtime.
|
||||
*
|
||||
* @param tx - An XChainClaim Transaction.
|
||||
* @throws When the XChainClaim is malformed.
|
||||
*/
|
||||
export function validateXChainClaim(tx: Record<string, unknown>): void {
|
||||
validateBaseTransaction(tx)
|
||||
|
||||
validateRequiredField(tx, 'XChainBridge', isXChainBridge)
|
||||
|
||||
validateRequiredField(
|
||||
tx,
|
||||
'XChainClaimID',
|
||||
(inp) => isNumber(inp) || isString(inp),
|
||||
)
|
||||
|
||||
validateRequiredField(tx, 'Destination', isString)
|
||||
|
||||
validateOptionalField(tx, 'DestinationTag', isNumber)
|
||||
|
||||
validateRequiredField(tx, 'Amount', isAmount)
|
||||
}
|
||||
74
packages/xrpl/src/models/transactions/XChainCommit.ts
Normal file
74
packages/xrpl/src/models/transactions/XChainCommit.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { Amount, XChainBridge } from '../common'
|
||||
|
||||
import {
|
||||
BaseTransaction,
|
||||
isAmount,
|
||||
isNumber,
|
||||
isString,
|
||||
isXChainBridge,
|
||||
validateBaseTransaction,
|
||||
validateOptionalField,
|
||||
validateRequiredField,
|
||||
} from './common'
|
||||
|
||||
/**
|
||||
* The XChainCommit is the second step in a cross-chain transfer. It puts assets
|
||||
* into trust on the locking chain so that they can be wrapped on the issuing
|
||||
* chain, or burns wrapped assets on the issuing chain so that they can be returned
|
||||
* on the locking chain.
|
||||
*
|
||||
* @category Transaction Models
|
||||
*/
|
||||
export interface XChainCommit extends BaseTransaction {
|
||||
TransactionType: 'XChainCommit'
|
||||
|
||||
/**
|
||||
* The bridge to use to transfer funds.
|
||||
*/
|
||||
XChainBridge: XChainBridge
|
||||
|
||||
/**
|
||||
* The unique integer ID for a cross-chain transfer. This must be acquired on
|
||||
* the destination chain (via a {@link XChainCreateClaimID} transaction) and
|
||||
* checked from a validated ledger before submitting this transaction. If an
|
||||
* incorrect sequence number is specified, the funds will be lost.
|
||||
*/
|
||||
XChainClaimID: number | string
|
||||
|
||||
/**
|
||||
* The destination account on the destination chain. If this is not specified,
|
||||
* the account that submitted the {@link XChainCreateClaimID} transaction on the
|
||||
* destination chain will need to submit a {@link XChainClaim} transaction to
|
||||
* claim the funds.
|
||||
*/
|
||||
OtherChainDestination?: string
|
||||
|
||||
/**
|
||||
* The asset to commit, and the quantity. This must match the door account's
|
||||
* LockingChainIssue (if on the locking chain) or the door account's
|
||||
* IssuingChainIssue (if on the issuing chain).
|
||||
*/
|
||||
Amount: Amount
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the form and type of an XChainCommit at runtime.
|
||||
*
|
||||
* @param tx - An XChainCommit Transaction.
|
||||
* @throws When the XChainCommit is malformed.
|
||||
*/
|
||||
export function validateXChainCommit(tx: Record<string, unknown>): void {
|
||||
validateBaseTransaction(tx)
|
||||
|
||||
validateRequiredField(tx, 'XChainBridge', isXChainBridge)
|
||||
|
||||
validateRequiredField(
|
||||
tx,
|
||||
'XChainClaimID',
|
||||
(inp) => isNumber(inp) || isString(inp),
|
||||
)
|
||||
|
||||
validateOptionalField(tx, 'OtherChainDestination', isString)
|
||||
|
||||
validateRequiredField(tx, 'Amount', isAmount)
|
||||
}
|
||||
56
packages/xrpl/src/models/transactions/XChainCreateBridge.ts
Normal file
56
packages/xrpl/src/models/transactions/XChainCreateBridge.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { Amount, XChainBridge } from '../common'
|
||||
|
||||
import {
|
||||
BaseTransaction,
|
||||
isAmount,
|
||||
isXChainBridge,
|
||||
validateBaseTransaction,
|
||||
validateOptionalField,
|
||||
validateRequiredField,
|
||||
} from './common'
|
||||
|
||||
/**
|
||||
* The XChainCreateBridge transaction creates a new {@link Bridge} ledger object
|
||||
* and defines a new cross-chain bridge entrance on the chain that the transaction
|
||||
* is submitted on. It includes information about door accounts and assets for the
|
||||
* bridge.
|
||||
*
|
||||
* @category Transaction Models
|
||||
*/
|
||||
export interface XChainCreateBridge extends BaseTransaction {
|
||||
TransactionType: 'XChainCreateBridge'
|
||||
|
||||
/**
|
||||
* The bridge (door accounts and assets) to create.
|
||||
*/
|
||||
XChainBridge: XChainBridge
|
||||
|
||||
/**
|
||||
* The total amount to pay the witness servers for their signatures. This amount
|
||||
* will be split among the signers.
|
||||
*/
|
||||
SignatureReward: Amount
|
||||
|
||||
/**
|
||||
* The minimum amount, in XRP, required for a {@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?: Amount
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the form and type of an XChainCreateBridge at runtime.
|
||||
*
|
||||
* @param tx - An XChainCreateBridge Transaction.
|
||||
* @throws When the XChainCreateBridge is malformed.
|
||||
*/
|
||||
export function validateXChainCreateBridge(tx: Record<string, unknown>): void {
|
||||
validateBaseTransaction(tx)
|
||||
|
||||
validateRequiredField(tx, 'XChainBridge', isXChainBridge)
|
||||
|
||||
validateRequiredField(tx, 'SignatureReward', isAmount)
|
||||
|
||||
validateOptionalField(tx, 'MinAccountCreateAmount', isAmount)
|
||||
}
|
||||
53
packages/xrpl/src/models/transactions/XChainCreateClaimID.ts
Normal file
53
packages/xrpl/src/models/transactions/XChainCreateClaimID.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { Amount, XChainBridge } from '../common'
|
||||
|
||||
import {
|
||||
BaseTransaction,
|
||||
isAmount,
|
||||
isString,
|
||||
isXChainBridge,
|
||||
validateBaseTransaction,
|
||||
validateRequiredField,
|
||||
} from './common'
|
||||
|
||||
/**
|
||||
* The XChainCreateClaimID transaction creates a new cross-chain claim ID that is
|
||||
* used for a cross-chain transfer. A cross-chain claim ID represents one
|
||||
* cross-chain transfer of value.
|
||||
*
|
||||
* @category Transaction Models
|
||||
*/
|
||||
export interface XChainCreateClaimID extends BaseTransaction {
|
||||
TransactionType: 'XChainCreateClaimID'
|
||||
|
||||
/**
|
||||
* The bridge to create the claim ID for.
|
||||
*/
|
||||
XChainBridge: XChainBridge
|
||||
|
||||
/**
|
||||
* The amount, in XRP, to reward the witness servers for providing signatures.
|
||||
* This must match the amount on the {@link Bridge} ledger object.
|
||||
*/
|
||||
SignatureReward: Amount
|
||||
|
||||
/**
|
||||
* The account that must send the {@link XChainCommit} transaction on the source chain.
|
||||
*/
|
||||
OtherChainSource: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the form and type of an XChainCreateClaimID at runtime.
|
||||
*
|
||||
* @param tx - An XChainCreateClaimID Transaction.
|
||||
* @throws When the XChainCreateClaimID is malformed.
|
||||
*/
|
||||
export function validateXChainCreateClaimID(tx: Record<string, unknown>): void {
|
||||
validateBaseTransaction(tx)
|
||||
|
||||
validateRequiredField(tx, 'XChainBridge', isXChainBridge)
|
||||
|
||||
validateRequiredField(tx, 'SignatureReward', isAmount)
|
||||
|
||||
validateRequiredField(tx, 'OtherChainSource', isString)
|
||||
}
|
||||
77
packages/xrpl/src/models/transactions/XChainModifyBridge.ts
Normal file
77
packages/xrpl/src/models/transactions/XChainModifyBridge.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { Amount, XChainBridge } from '../common'
|
||||
|
||||
import {
|
||||
BaseTransaction,
|
||||
GlobalFlags,
|
||||
isAmount,
|
||||
isXChainBridge,
|
||||
validateBaseTransaction,
|
||||
validateOptionalField,
|
||||
validateRequiredField,
|
||||
} from './common'
|
||||
|
||||
/**
|
||||
* Enum representing values of {@link XChainModifyBridge} transaction flags.
|
||||
*
|
||||
* @category Transaction Flags
|
||||
*/
|
||||
export enum XChainModifyBridgeFlags {
|
||||
/** Clears the MinAccountCreateAmount of the bridge. */
|
||||
tfClearAccountCreateAmount = 0x00010000,
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of flags to boolean values representing {@link XChainModifyBridge} transaction
|
||||
* flags.
|
||||
*
|
||||
* @category Transaction Flags
|
||||
*/
|
||||
export interface XChainModifyBridgeFlagsInterface extends GlobalFlags {
|
||||
/** Clears the MinAccountCreateAmount of the bridge. */
|
||||
tfClearAccountCreateAmount?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* The XChainModifyBridge transaction allows bridge managers to modify the parameters
|
||||
* of the bridge.
|
||||
*
|
||||
* @category Transaction Models
|
||||
*/
|
||||
export interface XChainModifyBridge extends BaseTransaction {
|
||||
TransactionType: 'XChainModifyBridge'
|
||||
|
||||
/**
|
||||
* The bridge to modify.
|
||||
*/
|
||||
XChainBridge: XChainBridge
|
||||
|
||||
/**
|
||||
* The signature reward split between the witnesses for submitting attestations.
|
||||
*/
|
||||
SignatureReward?: Amount
|
||||
|
||||
/**
|
||||
* The minimum amount, in XRP, required for a {@link XChainAccountCreateCommit}
|
||||
* transaction. If this is not present, the {@link XChainAccountCreateCommit}
|
||||
* transaction will fail. This field can only be present on XRP-XRP bridges.
|
||||
*/
|
||||
MinAccountCreateAmount?: Amount
|
||||
|
||||
Flags?: number | XChainModifyBridgeFlagsInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the form and type of an XChainModifyBridge at runtime.
|
||||
*
|
||||
* @param tx - An XChainModifyBridge Transaction.
|
||||
* @throws When the XChainModifyBridge is malformed.
|
||||
*/
|
||||
export function validateXChainModifyBridge(tx: Record<string, unknown>): void {
|
||||
validateBaseTransaction(tx)
|
||||
|
||||
validateRequiredField(tx, 'XChainBridge', isXChainBridge)
|
||||
|
||||
validateOptionalField(tx, 'SignatureReward', isAmount)
|
||||
|
||||
validateOptionalField(tx, 'MinAccountCreateAmount', isAmount)
|
||||
}
|
||||
@@ -1,9 +1,14 @@
|
||||
/* eslint-disable max-lines-per-function -- Necessary for validateBaseTransaction */
|
||||
/* eslint-disable max-statements -- Necessary for validateBaseTransaction */
|
||||
import { TRANSACTION_TYPES } from 'ripple-binary-codec'
|
||||
|
||||
import { ValidationError } from '../../errors'
|
||||
import { Amount, Currency, IssuedCurrencyAmount, Memo, Signer } from '../common'
|
||||
import {
|
||||
Amount,
|
||||
Currency,
|
||||
IssuedCurrencyAmount,
|
||||
Memo,
|
||||
Signer,
|
||||
XChainBridge,
|
||||
} from '../common'
|
||||
import { onlyHasFields } from '../utils'
|
||||
|
||||
const MEMO_SIZE = 3
|
||||
@@ -52,11 +57,32 @@ function isSigner(obj: unknown): boolean {
|
||||
const XRP_CURRENCY_SIZE = 1
|
||||
const ISSUE_SIZE = 2
|
||||
const ISSUED_CURRENCY_SIZE = 3
|
||||
const XCHAIN_BRIDGE_SIZE = 4
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return value !== null && typeof value === 'object'
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the form and type of a string at runtime.
|
||||
*
|
||||
* @param str - The object to check the form and type of.
|
||||
* @returns Whether the string is properly formed.
|
||||
*/
|
||||
export function isString(str: unknown): str is string {
|
||||
return typeof str === 'string'
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the form and type of a number at runtime.
|
||||
*
|
||||
* @param num - The object to check the form and type of.
|
||||
* @returns Whether the number is properly formed.
|
||||
*/
|
||||
export function isNumber(num: unknown): num is number {
|
||||
return typeof num === 'number'
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the form and type of an IssuedCurrency at runtime.
|
||||
*
|
||||
@@ -102,6 +128,73 @@ export function isAmount(amount: unknown): amount is Amount {
|
||||
return typeof amount === 'string' || isIssuedCurrency(amount)
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the form and type of an XChainBridge at runtime.
|
||||
*
|
||||
* @param input - The input to check the form and type of.
|
||||
* @returns Whether the XChainBridge is properly formed.
|
||||
*/
|
||||
export function isXChainBridge(input: unknown): input is XChainBridge {
|
||||
return (
|
||||
isRecord(input) &&
|
||||
Object.keys(input).length === XCHAIN_BRIDGE_SIZE &&
|
||||
typeof input.LockingChainDoor === 'string' &&
|
||||
isCurrency(input.LockingChainIssue) &&
|
||||
typeof input.IssuingChainDoor === 'string' &&
|
||||
isCurrency(input.IssuingChainIssue)
|
||||
)
|
||||
}
|
||||
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions -- tx.TransactionType is checked before any calls */
|
||||
|
||||
/**
|
||||
* Verify the form and type of a required type for a transaction at runtime.
|
||||
*
|
||||
* @param tx - The transaction input to check the form and type of.
|
||||
* @param paramName - The name of the transaction parameter.
|
||||
* @param checkValidity - The function to use to check the type.
|
||||
* @throws
|
||||
*/
|
||||
export function validateRequiredField(
|
||||
tx: Record<string, unknown>,
|
||||
paramName: string,
|
||||
checkValidity: (inp: unknown) => boolean,
|
||||
): void {
|
||||
if (tx[paramName] == null) {
|
||||
throw new ValidationError(
|
||||
`${tx.TransactionType}: missing field ${paramName}`,
|
||||
)
|
||||
}
|
||||
|
||||
if (!checkValidity(tx[paramName])) {
|
||||
throw new ValidationError(
|
||||
`${tx.TransactionType}: invalid field ${paramName}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the form and type of an optional type for a transaction at runtime.
|
||||
*
|
||||
* @param tx - The transaction input to check the form and type of.
|
||||
* @param paramName - The name of the transaction parameter.
|
||||
* @param checkValidity - The function to use to check the type.
|
||||
* @throws
|
||||
*/
|
||||
export function validateOptionalField(
|
||||
tx: Record<string, unknown>,
|
||||
paramName: string,
|
||||
checkValidity: (inp: unknown) => boolean,
|
||||
): void {
|
||||
if (tx[paramName] !== undefined && !checkValidity(tx[paramName])) {
|
||||
throw new ValidationError(
|
||||
`${tx.TransactionType}: invalid field ${paramName}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-enable @typescript-eslint/restrict-template-expressions -- checked before */
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface -- no global flags right now, so this is fine
|
||||
export interface GlobalFlags {}
|
||||
|
||||
@@ -190,14 +283,6 @@ export interface BaseTransaction {
|
||||
* @throws When the common param is malformed.
|
||||
*/
|
||||
export function validateBaseTransaction(common: Record<string, unknown>): void {
|
||||
if (common.Account === undefined) {
|
||||
throw new ValidationError('BaseTransaction: missing field Account')
|
||||
}
|
||||
|
||||
if (typeof common.Account !== 'string') {
|
||||
throw new ValidationError('BaseTransaction: Account not string')
|
||||
}
|
||||
|
||||
if (common.TransactionType === undefined) {
|
||||
throw new ValidationError('BaseTransaction: missing field TransactionType')
|
||||
}
|
||||
@@ -210,27 +295,15 @@ export function validateBaseTransaction(common: Record<string, unknown>): void {
|
||||
throw new ValidationError('BaseTransaction: Unknown TransactionType')
|
||||
}
|
||||
|
||||
if (common.Fee !== undefined && typeof common.Fee !== 'string') {
|
||||
throw new ValidationError('BaseTransaction: invalid Fee')
|
||||
}
|
||||
validateRequiredField(common, 'Account', isString)
|
||||
|
||||
if (common.Sequence !== undefined && typeof common.Sequence !== 'number') {
|
||||
throw new ValidationError('BaseTransaction: invalid Sequence')
|
||||
}
|
||||
validateOptionalField(common, 'Fee', isString)
|
||||
|
||||
if (
|
||||
common.AccountTxnID !== undefined &&
|
||||
typeof common.AccountTxnID !== 'string'
|
||||
) {
|
||||
throw new ValidationError('BaseTransaction: invalid AccountTxnID')
|
||||
}
|
||||
validateOptionalField(common, 'Sequence', isNumber)
|
||||
|
||||
if (
|
||||
common.LastLedgerSequence !== undefined &&
|
||||
typeof common.LastLedgerSequence !== 'number'
|
||||
) {
|
||||
throw new ValidationError('BaseTransaction: invalid LastLedgerSequence')
|
||||
}
|
||||
validateOptionalField(common, 'AccountTxnID', isString)
|
||||
|
||||
validateOptionalField(common, 'LastLedgerSequence', isNumber)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Only used by JS
|
||||
const memos = common.Memos as Array<{ Memo?: unknown }> | undefined
|
||||
@@ -248,33 +321,15 @@ export function validateBaseTransaction(common: Record<string, unknown>): void {
|
||||
throw new ValidationError('BaseTransaction: invalid Signers')
|
||||
}
|
||||
|
||||
if (common.SourceTag !== undefined && typeof common.SourceTag !== 'number') {
|
||||
throw new ValidationError('BaseTransaction: invalid SourceTag')
|
||||
}
|
||||
validateOptionalField(common, 'SourceTag', isNumber)
|
||||
|
||||
if (
|
||||
common.SigningPubKey !== undefined &&
|
||||
typeof common.SigningPubKey !== 'string'
|
||||
) {
|
||||
throw new ValidationError('BaseTransaction: invalid SigningPubKey')
|
||||
}
|
||||
validateOptionalField(common, 'SigningPubKey', isString)
|
||||
|
||||
if (
|
||||
common.TicketSequence !== undefined &&
|
||||
typeof common.TicketSequence !== 'number'
|
||||
) {
|
||||
throw new ValidationError('BaseTransaction: invalid TicketSequence')
|
||||
}
|
||||
validateOptionalField(common, 'TicketSequence', isNumber)
|
||||
|
||||
if (
|
||||
common.TxnSignature !== undefined &&
|
||||
typeof common.TxnSignature !== 'string'
|
||||
) {
|
||||
throw new ValidationError('BaseTransaction: invalid TxnSignature')
|
||||
}
|
||||
if (common.NetworkID !== undefined && typeof common.NetworkID !== 'number') {
|
||||
throw new ValidationError('BaseTransaction: invalid NetworkID')
|
||||
}
|
||||
validateOptionalField(common, 'TxnSignature', isString)
|
||||
|
||||
validateOptionalField(common, 'NetworkID', isNumber)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,6 +25,7 @@ export {
|
||||
export { CheckCancel } from './checkCancel'
|
||||
export { CheckCash } from './checkCash'
|
||||
export { CheckCreate } from './checkCreate'
|
||||
export { Clawback } from './clawback'
|
||||
export { DepositPreauth } from './depositPreauth'
|
||||
export { EscrowCancel } from './escrowCancel'
|
||||
export { EscrowCreate } from './escrowCreate'
|
||||
@@ -63,4 +64,15 @@ export { SignerListSet } from './signerListSet'
|
||||
export { TicketCreate } from './ticketCreate'
|
||||
export { TrustSetFlagsInterface, TrustSetFlags, TrustSet } from './trustSet'
|
||||
export { UNLModify } from './UNLModify'
|
||||
export { Clawback } from './clawback'
|
||||
export { XChainAddAccountCreateAttestation } from './XChainAddAccountCreateAttestation'
|
||||
export { XChainAddClaimAttestation } from './XChainAddClaimAttestation'
|
||||
export { XChainClaim } from './XChainClaim'
|
||||
export { XChainCommit } from './XChainCommit'
|
||||
export { XChainCreateBridge } from './XChainCreateBridge'
|
||||
export { XChainCreateClaimID } from './XChainCreateClaimID'
|
||||
export { XChainAccountCreateCommit } from './XChainAccountCreateCommit'
|
||||
export {
|
||||
XChainModifyBridge,
|
||||
XChainModifyBridgeFlags,
|
||||
XChainModifyBridgeFlagsInterface,
|
||||
} from './XChainModifyBridge'
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable max-lines -- need to work with a lot of transactions in a switch statement */
|
||||
/* eslint-disable max-lines-per-function -- need to work with a lot of Tx verifications */
|
||||
|
||||
import { ValidationError } from '../../errors'
|
||||
@@ -56,6 +57,32 @@ import { SetRegularKey, validateSetRegularKey } from './setRegularKey'
|
||||
import { SignerListSet, validateSignerListSet } from './signerListSet'
|
||||
import { TicketCreate, validateTicketCreate } from './ticketCreate'
|
||||
import { TrustSet, validateTrustSet } from './trustSet'
|
||||
import {
|
||||
XChainAccountCreateCommit,
|
||||
validateXChainAccountCreateCommit,
|
||||
} from './XChainAccountCreateCommit'
|
||||
import {
|
||||
XChainAddAccountCreateAttestation,
|
||||
validateXChainAddAccountCreateAttestation,
|
||||
} from './XChainAddAccountCreateAttestation'
|
||||
import {
|
||||
XChainAddClaimAttestation,
|
||||
validateXChainAddClaimAttestation,
|
||||
} from './XChainAddClaimAttestation'
|
||||
import { XChainClaim, validateXChainClaim } from './XChainClaim'
|
||||
import { XChainCommit, validateXChainCommit } from './XChainCommit'
|
||||
import {
|
||||
XChainCreateBridge,
|
||||
validateXChainCreateBridge,
|
||||
} from './XChainCreateBridge'
|
||||
import {
|
||||
XChainCreateClaimID,
|
||||
validateXChainCreateClaimID,
|
||||
} from './XChainCreateClaimID'
|
||||
import {
|
||||
XChainModifyBridge,
|
||||
validateXChainModifyBridge,
|
||||
} from './XChainModifyBridge'
|
||||
|
||||
/**
|
||||
* @category Transaction Models
|
||||
@@ -92,6 +119,14 @@ export type Transaction =
|
||||
| SignerListSet
|
||||
| TicketCreate
|
||||
| TrustSet
|
||||
| XChainAddAccountCreateAttestation
|
||||
| XChainAddClaimAttestation
|
||||
| XChainClaim
|
||||
| XChainCommit
|
||||
| XChainCreateBridge
|
||||
| XChainCreateClaimID
|
||||
| XChainAccountCreateCommit
|
||||
| XChainModifyBridge
|
||||
|
||||
/**
|
||||
* @category Transaction Models
|
||||
@@ -294,6 +329,38 @@ export function validate(transaction: Record<string, unknown>): void {
|
||||
validateTrustSet(tx)
|
||||
break
|
||||
|
||||
case 'XChainAddAccountCreateAttestation':
|
||||
validateXChainAddAccountCreateAttestation(tx)
|
||||
break
|
||||
|
||||
case 'XChainAddClaimAttestation':
|
||||
validateXChainAddClaimAttestation(tx)
|
||||
break
|
||||
|
||||
case 'XChainClaim':
|
||||
validateXChainClaim(tx)
|
||||
break
|
||||
|
||||
case 'XChainCommit':
|
||||
validateXChainCommit(tx)
|
||||
break
|
||||
|
||||
case 'XChainCreateBridge':
|
||||
validateXChainCreateBridge(tx)
|
||||
break
|
||||
|
||||
case 'XChainCreateClaimID':
|
||||
validateXChainCreateClaimID(tx)
|
||||
break
|
||||
|
||||
case 'XChainAccountCreateCommit':
|
||||
validateXChainAccountCreateCommit(tx)
|
||||
break
|
||||
|
||||
case 'XChainModifyBridge':
|
||||
validateXChainModifyBridge(tx)
|
||||
break
|
||||
|
||||
default:
|
||||
throw new ValidationError(
|
||||
`Invalid field TransactionType: ${tx.TransactionType}`,
|
||||
|
||||
@@ -15,6 +15,7 @@ import { PaymentFlags } from '../transactions/payment'
|
||||
import { PaymentChannelClaimFlags } from '../transactions/paymentChannelClaim'
|
||||
import type { Transaction } from '../transactions/transaction'
|
||||
import { TrustSetFlags } from '../transactions/trustSet'
|
||||
import { XChainModifyBridgeFlags } from '../transactions/XChainModifyBridge'
|
||||
|
||||
import { isFlagEnabled } from '.'
|
||||
|
||||
@@ -78,6 +79,9 @@ export function setTransactionFlagsToNumber(tx: Transaction): void {
|
||||
case 'TrustSet':
|
||||
tx.Flags = convertFlagsToNumber(tx.Flags, TrustSetFlags)
|
||||
return
|
||||
case 'XChainModifyBridge':
|
||||
tx.Flags = convertFlagsToNumber(tx.Flags, XChainModifyBridgeFlags)
|
||||
return
|
||||
default:
|
||||
tx.Flags = 0
|
||||
}
|
||||
|
||||
64
packages/xrpl/src/utils/getXChainClaimID.ts
Normal file
64
packages/xrpl/src/utils/getXChainClaimID.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { decode } from 'ripple-binary-codec'
|
||||
|
||||
import {
|
||||
CreatedNode,
|
||||
isCreatedNode,
|
||||
TransactionMetadata,
|
||||
} from '../models/transactions/metadata'
|
||||
|
||||
/**
|
||||
* Ensures that the metadata is in a deserialized format to parse.
|
||||
*
|
||||
* @param meta - the metadata from a `tx` method call. Can be in json format or binary format.
|
||||
* @returns the metadata in a deserialized format.
|
||||
*/
|
||||
function ensureDecodedMeta(
|
||||
meta: TransactionMetadata | string,
|
||||
): TransactionMetadata {
|
||||
if (typeof meta === 'string') {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Meta is either metadata or serialized metadata.
|
||||
return decode(meta) as unknown as TransactionMetadata
|
||||
}
|
||||
return meta
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the XChainClaimID value from the metadata of an `XChainCreateClaimID` transaction.
|
||||
*
|
||||
* @param meta - Metadata from the response to submitting and waiting for an XChainCreateClaimID transaction
|
||||
* or from a `tx` method call.
|
||||
* @returns The XChainClaimID for the minted NFT.
|
||||
* @throws if meta is not TransactionMetadata.
|
||||
*/
|
||||
export default function getXChainClaimID(
|
||||
meta: TransactionMetadata | string | undefined,
|
||||
): string | undefined {
|
||||
if (typeof meta !== 'string' && meta?.AffectedNodes === undefined) {
|
||||
throw new TypeError(`Unable to parse the parameter given to getXChainClaimID.
|
||||
'meta' must be the metadata from an XChainCreateClaimID transaction. Received ${JSON.stringify(
|
||||
meta,
|
||||
)} instead.`)
|
||||
}
|
||||
|
||||
const decodedMeta = ensureDecodedMeta(meta)
|
||||
|
||||
if (!decodedMeta.TransactionResult) {
|
||||
throw new TypeError(
|
||||
'Cannot get XChainClaimID from un-validated transaction',
|
||||
)
|
||||
}
|
||||
|
||||
if (decodedMeta.TransactionResult !== 'tesSUCCESS') {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const createdNode = decodedMeta.AffectedNodes.find(
|
||||
(node) =>
|
||||
isCreatedNode(node) &&
|
||||
node.CreatedNode.LedgerEntryType === 'XChainOwnedClaimID',
|
||||
)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- necessary here
|
||||
return (createdNode as CreatedNode).CreatedNode.NewFields
|
||||
.XChainClaimID as string
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import { Transaction } from '../models/transactions/transaction'
|
||||
import { deriveKeypair, deriveAddress, deriveXAddress } from './derive'
|
||||
import getBalanceChanges from './getBalanceChanges'
|
||||
import getNFTokenID from './getNFTokenID'
|
||||
import getXChainClaimID from './getXChainClaimID'
|
||||
import {
|
||||
hashSignedTx,
|
||||
hashTx,
|
||||
@@ -220,4 +221,5 @@ export {
|
||||
encodeForSigningClaim,
|
||||
getNFTokenID,
|
||||
parseNFTokenID,
|
||||
getXChainClaimID,
|
||||
}
|
||||
|
||||
8
packages/xrpl/test/fixtures/rippled/index.ts
vendored
8
packages/xrpl/test/fixtures/rippled/index.ts
vendored
@@ -25,8 +25,12 @@ import successSubmit from './submit.json'
|
||||
import successSubscribe from './subscribe.json'
|
||||
import errorSubscribe from './subscribeError.json'
|
||||
import transaction_entry from './transactionEntry.json'
|
||||
import NFTokenMint from './tx/NFTokenMint.json'
|
||||
import NFTokenMint2 from './tx/NFTokenMint2.json'
|
||||
import OfferCreateSell from './tx/offerCreateSell.json'
|
||||
import Payment from './tx/payment.json'
|
||||
import XChainCreateClaimID from './tx/XChainCreateClaimID.json'
|
||||
import XChainCreateClaimID2 from './tx/XChainCreateClaimID2.json'
|
||||
import unsubscribe from './unsubscribe.json'
|
||||
|
||||
const submit = {
|
||||
@@ -89,8 +93,12 @@ const server_info = {
|
||||
}
|
||||
|
||||
const tx = {
|
||||
NFTokenMint,
|
||||
NFTokenMint2,
|
||||
Payment,
|
||||
OfferCreateSell,
|
||||
XChainCreateClaimID,
|
||||
XChainCreateClaimID2,
|
||||
}
|
||||
|
||||
const rippled = {
|
||||
|
||||
118
packages/xrpl/test/fixtures/rippled/tx/XChainCreateClaimID.json
vendored
Normal file
118
packages/xrpl/test/fixtures/rippled/tx/XChainCreateClaimID.json
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
{
|
||||
"tx": {
|
||||
"Account": "rLVUz66tawieqTPAHuTyFTN6pLbHcXiTzd",
|
||||
"Fee": "20",
|
||||
"Flags": 2147483648,
|
||||
"NetworkID": 2552,
|
||||
"OtherChainSource": "rL5Zd9m5XEoGPddMwYY5H5C8ARcR47b6oM",
|
||||
"Sequence": 1007784,
|
||||
"SignatureReward": "100",
|
||||
"SigningPubKey": "039E925058C740A5B73E49300FC205D058520DE37F2C63C4EE3A0D1B50C4E44080",
|
||||
"TransactionType": "XChainCreateClaimID",
|
||||
"TxnSignature": "304402201C6F95B9997FB63DCD9854664707C58C46AA3207612FE32366B77DA084786CAF02205752C58821D7FAFAE26F77DC10AC0AFDDCBCCF4FCBED90E6B8C4523A0EB3E008",
|
||||
"XChainBridge": {
|
||||
"IssuingChainDoor": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"IssuingChainIssue": {
|
||||
"currency": "XRP"
|
||||
},
|
||||
"LockingChainDoor": "rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4",
|
||||
"LockingChainIssue": {
|
||||
"currency": "XRP"
|
||||
}
|
||||
},
|
||||
"date": 1695324353000
|
||||
},
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"Flags": 0,
|
||||
"MinAccountCreateAmount": "10000000",
|
||||
"OwnerNode": "0",
|
||||
"SignatureReward": "100",
|
||||
"XChainAccountClaimCount": "e3",
|
||||
"XChainAccountCreateCount": "0",
|
||||
"XChainBridge": {
|
||||
"IssuingChainDoor": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"IssuingChainIssue": {
|
||||
"currency": "XRP"
|
||||
},
|
||||
"LockingChainDoor": "rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4",
|
||||
"LockingChainIssue": {
|
||||
"currency": "XRP"
|
||||
}
|
||||
},
|
||||
"XChainClaimID": "b0"
|
||||
},
|
||||
"LedgerEntryType": "Bridge",
|
||||
"LedgerIndex": "114C0DC89656D1B0FB1F4A3426034C3FCE75BCE65D9574B5D96ABC2B24D6C8F1",
|
||||
"PreviousFields": {
|
||||
"XChainClaimID": "af"
|
||||
},
|
||||
"PreviousTxnID": "3F6F3BBE584115D1A575AB24BA32B47184F2323B65DE5C8C8EE144A55115E0B9",
|
||||
"PreviousTxnLgrSeq": 1027822
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Owner": "rLVUz66tawieqTPAHuTyFTN6pLbHcXiTzd",
|
||||
"RootIndex": "6C1EA1A93D590E831CCC0EE2CBE26C146A3A6FD36F5854DC5E5AB5CE78FAE49C"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "6C1EA1A93D590E831CCC0EE2CBE26C146A3A6FD36F5854DC5E5AB5CE78FAE49C"
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "XChainOwnedClaimID",
|
||||
"LedgerIndex": "A00BD77AE864509D796B39041AD48E9DEFEC9AF20E5C09CEF2F5DA41D6CFEB1E",
|
||||
"NewFields": {
|
||||
"Account": "rLVUz66tawieqTPAHuTyFTN6pLbHcXiTzd",
|
||||
"OtherChainSource": "rL5Zd9m5XEoGPddMwYY5H5C8ARcR47b6oM",
|
||||
"SignatureReward": "100",
|
||||
"XChainBridge": {
|
||||
"IssuingChainDoor": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"IssuingChainIssue": {
|
||||
"currency": "XRP"
|
||||
},
|
||||
"LockingChainDoor": "rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4",
|
||||
"LockingChainIssue": {
|
||||
"currency": "XRP"
|
||||
}
|
||||
},
|
||||
"XChainClaimID": "b0"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rLVUz66tawieqTPAHuTyFTN6pLbHcXiTzd",
|
||||
"Balance": "39999940",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 3,
|
||||
"Sequence": 1007785
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "FD919D0BAA90C759DA4C7130AEEF6AE7FA2AF074F5E867D40BCBE1ECD8D8D0EA",
|
||||
"PreviousFields": {
|
||||
"Balance": "39999960",
|
||||
"OwnerCount": 2,
|
||||
"Sequence": 1007784
|
||||
},
|
||||
"PreviousTxnID": "3F6F3BBE584115D1A575AB24BA32B47184F2323B65DE5C8C8EE144A55115E0B9",
|
||||
"PreviousTxnLgrSeq": 1027822
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 0,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"hash": "998E76B9840DA5A6009592A2674D0166A9C4862193193AA46EA6B77A64781FB4",
|
||||
"ledger_index": 1027837,
|
||||
"date": 1695324353000
|
||||
}
|
||||
118
packages/xrpl/test/fixtures/rippled/tx/XChainCreateClaimID2.json
vendored
Normal file
118
packages/xrpl/test/fixtures/rippled/tx/XChainCreateClaimID2.json
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
{
|
||||
"tx": {
|
||||
"Account": "rwmUSzi5Xp31AjMTEdbvxgWqLETcVNU6Fv",
|
||||
"Fee": "12",
|
||||
"Flags": 0,
|
||||
"LastLedgerSequence": 1027798,
|
||||
"NetworkID": 2552,
|
||||
"OtherChainSource": "rBXdfZ7NVpdjRfYajPMpviGgq7HLDeuBdR",
|
||||
"Sequence": 1027778,
|
||||
"SignatureReward": "100",
|
||||
"SigningPubKey": "EDDDD69DF802B8DB82D644EF92E2C1F06AC128A275CDFF86F013180D104ED39D3B",
|
||||
"TransactionType": "XChainCreateClaimID",
|
||||
"TxnSignature": "67BE63527EC8A0C872F23E2C4EB97C1F3E7D3FED6D10C8310B9235D3891B6B9343768A080E258F6C3687BFC4B7C5FD429ABB33654C99DE46471FD6F2A7035303",
|
||||
"XChainBridge": {
|
||||
"IssuingChainDoor": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"IssuingChainIssue": {
|
||||
"currency": "XRP"
|
||||
},
|
||||
"LockingChainDoor": "rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4",
|
||||
"LockingChainIssue": {
|
||||
"currency": "XRP"
|
||||
}
|
||||
},
|
||||
"date": 1695324182000
|
||||
},
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"Flags": 0,
|
||||
"MinAccountCreateAmount": "10000000",
|
||||
"OwnerNode": "0",
|
||||
"SignatureReward": "100",
|
||||
"XChainAccountClaimCount": "e2",
|
||||
"XChainAccountCreateCount": "0",
|
||||
"XChainBridge": {
|
||||
"IssuingChainDoor": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"IssuingChainIssue": {
|
||||
"currency": "XRP"
|
||||
},
|
||||
"LockingChainDoor": "rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4",
|
||||
"LockingChainIssue": {
|
||||
"currency": "XRP"
|
||||
}
|
||||
},
|
||||
"XChainClaimID": "ac"
|
||||
},
|
||||
"LedgerEntryType": "Bridge",
|
||||
"LedgerIndex": "114C0DC89656D1B0FB1F4A3426034C3FCE75BCE65D9574B5D96ABC2B24D6C8F1",
|
||||
"PreviousFields": {
|
||||
"XChainClaimID": "ab"
|
||||
},
|
||||
"PreviousTxnID": "80C33D1FB349D698CFDB1A85E8368557C5B7219B74DFCB2B05E0B10E2667F902",
|
||||
"PreviousTxnLgrSeq": 1027779
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rwmUSzi5Xp31AjMTEdbvxgWqLETcVNU6Fv",
|
||||
"Balance": "19999988",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 1,
|
||||
"Sequence": 1027779
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "33442CE111B258424548888D8999F6D064A0866B1300C44AB72E1C5A09765D9D",
|
||||
"PreviousFields": {
|
||||
"Balance": "20000000",
|
||||
"OwnerCount": 0,
|
||||
"Sequence": 1027778
|
||||
},
|
||||
"PreviousTxnID": "7C9ACA230488547B4F39EBCE332447FB90AE59B64C1B03BBF474B509B43739EC",
|
||||
"PreviousTxnLgrSeq": 1027778
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "439684B06C22596B5B86D2F50903B6AA6F68BD07BED636FC6325704B09DE5D61",
|
||||
"NewFields": {
|
||||
"Owner": "rwmUSzi5Xp31AjMTEdbvxgWqLETcVNU6Fv",
|
||||
"RootIndex": "439684B06C22596B5B86D2F50903B6AA6F68BD07BED636FC6325704B09DE5D61"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "XChainOwnedClaimID",
|
||||
"LedgerIndex": "8097863E1200B0174006541763AA8F604782DA10C1BD37190D753C699D69C678",
|
||||
"NewFields": {
|
||||
"Account": "rwmUSzi5Xp31AjMTEdbvxgWqLETcVNU6Fv",
|
||||
"OtherChainSource": "rBXdfZ7NVpdjRfYajPMpviGgq7HLDeuBdR",
|
||||
"SignatureReward": "100",
|
||||
"XChainBridge": {
|
||||
"IssuingChainDoor": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"IssuingChainIssue": {
|
||||
"currency": "XRP"
|
||||
},
|
||||
"LockingChainDoor": "rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4",
|
||||
"LockingChainIssue": {
|
||||
"currency": "XRP"
|
||||
}
|
||||
},
|
||||
"XChainClaimID": "ac"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 0,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"hash": "A42C4E7F5BAF8A9BEB56853114EE686D554F15F400B8DA885A344B13C32D07BC",
|
||||
"ledger_index": 1027780,
|
||||
"date": 1695324182000
|
||||
}
|
||||
161
packages/xrpl/test/models/XChainAccountCreateCommit.test.ts
Normal file
161
packages/xrpl/test/models/XChainAccountCreateCommit.test.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { validate, ValidationError } from '../../src'
|
||||
import { validateXChainAccountCreateCommit } from '../../src/models/transactions/XChainAccountCreateCommit'
|
||||
|
||||
/**
|
||||
* XChainAccountCreateCommit Transaction Verification Testing.
|
||||
*
|
||||
* Providing runtime verification testing for each specific transaction type.
|
||||
*/
|
||||
describe('XChainAccountCreateCommit', function () {
|
||||
let tx
|
||||
|
||||
beforeEach(function () {
|
||||
tx = {
|
||||
Account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
XChainBridge: {
|
||||
LockingChainDoor: 'rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL',
|
||||
LockingChainIssue: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
IssuingChainDoor: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV',
|
||||
IssuingChainIssue: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
},
|
||||
Amount: '1000000',
|
||||
Fee: '10',
|
||||
Flags: 2147483648,
|
||||
Destination: 'rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL',
|
||||
Sequence: 1,
|
||||
SignatureReward: '10000',
|
||||
TransactionType: 'XChainAccountCreateCommit',
|
||||
} as any
|
||||
})
|
||||
|
||||
it('verifies valid XChainAccountCreateCommit', function () {
|
||||
assert.doesNotThrow(() => validateXChainAccountCreateCommit(tx))
|
||||
assert.doesNotThrow(() => validate(tx))
|
||||
})
|
||||
|
||||
it('throws w/ missing XChainBridge', function () {
|
||||
delete tx.XChainBridge
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAccountCreateCommit(tx),
|
||||
ValidationError,
|
||||
'XChainAccountCreateCommit: missing field XChainBridge',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAccountCreateCommit: missing field XChainBridge',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid XChainBridge', function () {
|
||||
tx.XChainBridge = { XChainDoor: 'test' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAccountCreateCommit(tx),
|
||||
ValidationError,
|
||||
'XChainAccountCreateCommit: invalid field XChainBridge',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAccountCreateCommit: invalid field XChainBridge',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing SignatureReward', function () {
|
||||
delete tx.SignatureReward
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAccountCreateCommit(tx),
|
||||
ValidationError,
|
||||
'XChainAccountCreateCommit: missing field SignatureReward',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAccountCreateCommit: missing field SignatureReward',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid SignatureReward', function () {
|
||||
tx.SignatureReward = { currency: 'ETH' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAccountCreateCommit(tx),
|
||||
ValidationError,
|
||||
'XChainAccountCreateCommit: invalid field SignatureReward',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAccountCreateCommit: invalid field SignatureReward',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing Destination', function () {
|
||||
delete tx.Destination
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAccountCreateCommit(tx),
|
||||
ValidationError,
|
||||
'XChainAccountCreateCommit: missing field Destination',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAccountCreateCommit: missing field Destination',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid Destination', function () {
|
||||
tx.Destination = 123
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAccountCreateCommit(tx),
|
||||
ValidationError,
|
||||
'XChainAccountCreateCommit: invalid field Destination',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAccountCreateCommit: invalid field Destination',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing Amount', function () {
|
||||
delete tx.Amount
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAccountCreateCommit(tx),
|
||||
ValidationError,
|
||||
'XChainAccountCreateCommit: missing field Amount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAccountCreateCommit: missing field Amount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid Amount', function () {
|
||||
tx.Amount = { currency: 'ETH' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAccountCreateCommit(tx),
|
||||
ValidationError,
|
||||
'XChainAccountCreateCommit: invalid field Amount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAccountCreateCommit: invalid field Amount',
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,381 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { validate, ValidationError } from '../../src'
|
||||
import { validateXChainAddAccountCreateAttestation } from '../../src/models/transactions/XChainAddAccountCreateAttestation'
|
||||
|
||||
/**
|
||||
* XChainAddAccountCreateAttestation Transaction Verification Testing.
|
||||
*
|
||||
* Providing runtime verification testing for each specific transaction type.
|
||||
*/
|
||||
describe('XChainAddAccountCreateAttestation', function () {
|
||||
let tx
|
||||
|
||||
beforeEach(function () {
|
||||
tx = {
|
||||
Account: 'r9cYxdjQsoXAEz3qQJc961SNLaXRkWXCvT',
|
||||
Amount: '10000000',
|
||||
AttestationRewardAccount: 'r9cYxdjQsoXAEz3qQJc961SNLaXRkWXCvT',
|
||||
AttestationSignerAccount: 'r9cYxdjQsoXAEz3qQJc961SNLaXRkWXCvT',
|
||||
Destination: 'rJdTJRJZ6GXCCRaamHJgEqVzB7Zy4557Pi',
|
||||
Fee: '20',
|
||||
LastLedgerSequence: 13,
|
||||
OtherChainSource: 'raFcdz1g8LWJDJWJE2ZKLRGdmUmsTyxaym',
|
||||
PublicKey:
|
||||
'ED1F4A024ACFEBDB6C7AA88DEDE3364E060487EA31B14CC9E0D610D152B31AADC2',
|
||||
Sequence: 5,
|
||||
Signature:
|
||||
'EEFCFA3DC2AB4AB7C4D2EBBC168CB621A11B82BABD86534DFC8EFA72439A496' +
|
||||
'62D744073CD848E7A587A95B35162CDF9A69BB237E72C9537A987F5B8C394F30D',
|
||||
SignatureReward: '100',
|
||||
TransactionType: 'XChainAddAccountCreateAttestation',
|
||||
WasLockingChainSend: 1,
|
||||
XChainAccountCreateCount: '0000000000000006',
|
||||
XChainBridge: {
|
||||
IssuingChainDoor: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
IssuingChainIssue: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
LockingChainDoor: 'rDJVtEuDKr4rj1B3qtW7R5TVWdXV2DY7Qg',
|
||||
LockingChainIssue: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
},
|
||||
} as any
|
||||
})
|
||||
|
||||
it('verifies valid XChainAddAccountCreateAttestation', function () {
|
||||
assert.doesNotThrow(() => validateXChainAddAccountCreateAttestation(tx))
|
||||
assert.doesNotThrow(() => validate(tx))
|
||||
})
|
||||
|
||||
it('throws w/ missing Amount', function () {
|
||||
delete tx.Amount
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field Amount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field Amount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid Amount', function () {
|
||||
tx.Amount = { currency: 'ETH' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field Amount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field Amount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing AttestationRewardAccount', function () {
|
||||
delete tx.AttestationRewardAccount
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field AttestationRewardAccount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field AttestationRewardAccount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid AttestationRewardAccount', function () {
|
||||
tx.AttestationRewardAccount = 123
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field AttestationRewardAccount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field AttestationRewardAccount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing AttestationSignerAccount', function () {
|
||||
delete tx.AttestationSignerAccount
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field AttestationSignerAccount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field AttestationSignerAccount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid AttestationSignerAccount', function () {
|
||||
tx.AttestationSignerAccount = 123
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field AttestationSignerAccount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field AttestationSignerAccount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing Destination', function () {
|
||||
delete tx.Destination
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field Destination',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field Destination',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid Destination', function () {
|
||||
tx.Destination = 123
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field Destination',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field Destination',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing OtherChainSource', function () {
|
||||
delete tx.OtherChainSource
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field OtherChainSource',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field OtherChainSource',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid OtherChainSource', function () {
|
||||
tx.OtherChainSource = 123
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field OtherChainSource',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field OtherChainSource',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing PublicKey', function () {
|
||||
delete tx.PublicKey
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field PublicKey',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field PublicKey',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid PublicKey', function () {
|
||||
tx.PublicKey = 123
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field PublicKey',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field PublicKey',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing Signature', function () {
|
||||
delete tx.Signature
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field Signature',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field Signature',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid Signature', function () {
|
||||
tx.Signature = 123
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field Signature',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field Signature',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing SignatureReward', function () {
|
||||
delete tx.SignatureReward
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field SignatureReward',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field SignatureReward',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid SignatureReward', function () {
|
||||
tx.SignatureReward = { currency: 'ETH' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field SignatureReward',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field SignatureReward',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing WasLockingChainSend', function () {
|
||||
delete tx.WasLockingChainSend
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field WasLockingChainSend',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field WasLockingChainSend',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid WasLockingChainSend', function () {
|
||||
tx.WasLockingChainSend = 2
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field WasLockingChainSend',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field WasLockingChainSend',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing XChainAccountCreateCount', function () {
|
||||
delete tx.XChainAccountCreateCount
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field XChainAccountCreateCount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field XChainAccountCreateCount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid XChainAccountCreateCount', function () {
|
||||
tx.XChainAccountCreateCount = { currency: 'ETH' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field XChainAccountCreateCount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field XChainAccountCreateCount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing XChainBridge', function () {
|
||||
delete tx.XChainBridge
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field XChainBridge',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: missing field XChainBridge',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid XChainBridge', function () {
|
||||
tx.XChainBridge = { XChainDoor: 'test' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddAccountCreateAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field XChainBridge',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddAccountCreateAttestation: invalid field XChainBridge',
|
||||
)
|
||||
})
|
||||
})
|
||||
334
packages/xrpl/test/models/XChainAddClaimAttestation.test.ts
Normal file
334
packages/xrpl/test/models/XChainAddClaimAttestation.test.ts
Normal file
@@ -0,0 +1,334 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { validate, ValidationError } from '../../src'
|
||||
import { validateXChainAddClaimAttestation } from '../../src/models/transactions/XChainAddClaimAttestation'
|
||||
|
||||
/**
|
||||
* XChainAddClaimAttestation Transaction Verification Testing.
|
||||
*
|
||||
* Providing runtime verification testing for each specific transaction type.
|
||||
*/
|
||||
describe('XChainAddClaimAttestation', function () {
|
||||
let tx
|
||||
|
||||
beforeEach(function () {
|
||||
tx = {
|
||||
Account: 'rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3',
|
||||
Amount: '10000000',
|
||||
AttestationRewardAccount: 'rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3',
|
||||
AttestationSignerAccount: 'rsqvD8WFFEBBv4nztpoW9YYXJ7eRzLrtc3',
|
||||
Destination: 'rJdTJRJZ6GXCCRaamHJgEqVzB7Zy4557Pi',
|
||||
Fee: '20',
|
||||
LastLedgerSequence: 19,
|
||||
OtherChainSource: 'raFcdz1g8LWJDJWJE2ZKLRGdmUmsTyxaym',
|
||||
PublicKey:
|
||||
'ED7541DEC700470F54276C90C333A13CDBB5D341FD43C60CEA12170F6D6D4E1136',
|
||||
Sequence: 9,
|
||||
Signature:
|
||||
'7C175050B08000AD35EEB2D87E16CD3F95A0AEEBF2A049474275153D9D4DD44528FE99AA50E71660A15B0B768E1B90E609BBD5DC7AFAFD45D9705D72D40EA10C',
|
||||
TransactionType: 'XChainAddClaimAttestation',
|
||||
WasLockingChainSend: 1,
|
||||
XChainBridge: {
|
||||
IssuingChainDoor: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
IssuingChainIssue: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
LockingChainDoor: 'rDJVtEuDKr4rj1B3qtW7R5TVWdXV2DY7Qg',
|
||||
LockingChainIssue: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
},
|
||||
XChainClaimID: '0000000000000001',
|
||||
} as any
|
||||
})
|
||||
|
||||
it('verifies valid XChainAddClaimAttestation', function () {
|
||||
assert.doesNotThrow(() => validateXChainAddClaimAttestation(tx))
|
||||
assert.doesNotThrow(() => validate(tx))
|
||||
})
|
||||
|
||||
it('throws w/ missing Amount', function () {
|
||||
delete tx.Amount
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field Amount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field Amount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid Amount', function () {
|
||||
tx.Amount = { currency: 'ETH' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field Amount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field Amount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing AttestationRewardAccount', function () {
|
||||
delete tx.AttestationRewardAccount
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field AttestationRewardAccount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field AttestationRewardAccount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid AttestationRewardAccount', function () {
|
||||
tx.AttestationRewardAccount = 123
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field AttestationRewardAccount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field AttestationRewardAccount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing AttestationSignerAccount', function () {
|
||||
delete tx.AttestationSignerAccount
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field AttestationSignerAccount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field AttestationSignerAccount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid AttestationSignerAccount', function () {
|
||||
tx.AttestationSignerAccount = 123
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field AttestationSignerAccount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field AttestationSignerAccount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid Destination', function () {
|
||||
tx.Destination = 123
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field Destination',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field Destination',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing OtherChainSource', function () {
|
||||
delete tx.OtherChainSource
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field OtherChainSource',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field OtherChainSource',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid OtherChainSource', function () {
|
||||
tx.OtherChainSource = 123
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field OtherChainSource',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field OtherChainSource',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing PublicKey', function () {
|
||||
delete tx.PublicKey
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field PublicKey',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field PublicKey',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid PublicKey', function () {
|
||||
tx.PublicKey = 123
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field PublicKey',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field PublicKey',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing Signature', function () {
|
||||
delete tx.Signature
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field Signature',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field Signature',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid Signature', function () {
|
||||
tx.Signature = 123
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field Signature',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field Signature',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing WasLockingChainSend', function () {
|
||||
delete tx.WasLockingChainSend
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field WasLockingChainSend',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field WasLockingChainSend',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid WasLockingChainSend', function () {
|
||||
tx.WasLockingChainSend = 2
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field WasLockingChainSend',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field WasLockingChainSend',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing XChainBridge', function () {
|
||||
delete tx.XChainBridge
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field XChainBridge',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field XChainBridge',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid XChainBridge', function () {
|
||||
tx.XChainBridge = { XChainDoor: 'test' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field XChainBridge',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field XChainBridge',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing XChainClaimID', function () {
|
||||
delete tx.XChainClaimID
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field XChainClaimID',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: missing field XChainClaimID',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid XChainClaimID', function () {
|
||||
tx.XChainClaimID = { currency: 'ETH' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainAddClaimAttestation(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field XChainClaimID',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainAddClaimAttestation: invalid field XChainClaimID',
|
||||
)
|
||||
})
|
||||
})
|
||||
176
packages/xrpl/test/models/XChainClaim.test.ts
Normal file
176
packages/xrpl/test/models/XChainClaim.test.ts
Normal file
@@ -0,0 +1,176 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { validate, ValidationError } from '../../src'
|
||||
import { validateXChainClaim } from '../../src/models/transactions/XChainClaim'
|
||||
|
||||
/**
|
||||
* XChainClaim Transaction Verification Testing.
|
||||
*
|
||||
* Providing runtime verification testing for each specific transaction type.
|
||||
*/
|
||||
describe('XChainClaim', function () {
|
||||
let tx
|
||||
|
||||
beforeEach(function () {
|
||||
tx = {
|
||||
Account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
Amount: '10000',
|
||||
XChainBridge: {
|
||||
LockingChainDoor: 'rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL',
|
||||
LockingChainIssue: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
IssuingChainDoor: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV',
|
||||
IssuingChainIssue: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
},
|
||||
Destination: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV',
|
||||
Fee: '10',
|
||||
Flags: 2147483648,
|
||||
Sequence: 1,
|
||||
TransactionType: 'XChainClaim',
|
||||
XChainClaimID: '0000000000000001',
|
||||
} as any
|
||||
})
|
||||
|
||||
it('verifies valid XChainClaim', function () {
|
||||
assert.doesNotThrow(() => validateXChainClaim(tx))
|
||||
assert.doesNotThrow(() => validate(tx))
|
||||
})
|
||||
|
||||
it('throws w/ missing XChainBridge', function () {
|
||||
delete tx.XChainBridge
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainClaim(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: missing field XChainBridge',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: missing field XChainBridge',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid XChainBridge', function () {
|
||||
tx.XChainBridge = { XChainDoor: 'test' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainClaim(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: invalid field XChainBridge',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: invalid field XChainBridge',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing XChainClaimID', function () {
|
||||
delete tx.XChainClaimID
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainClaim(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: missing field XChainClaimID',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: missing field XChainClaimID',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid XChainClaimID', function () {
|
||||
tx.XChainClaimID = { currency: 'ETH' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainClaim(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: invalid field XChainClaimID',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: invalid field XChainClaimID',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing Destination', function () {
|
||||
delete tx.Destination
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainClaim(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: missing field Destination',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: missing field Destination',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid Destination', function () {
|
||||
tx.Destination = 123
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainClaim(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: invalid field Destination',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: invalid field Destination',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid DestinationTag', function () {
|
||||
tx.DestinationTag = 'number'
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainClaim(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: invalid field DestinationTag',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: invalid field DestinationTag',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing Amount', function () {
|
||||
delete tx.Amount
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainClaim(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: missing field Amount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: missing field Amount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid Amount', function () {
|
||||
tx.Amount = { currency: 'ETH' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainClaim(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: invalid field Amount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainClaim: invalid field Amount',
|
||||
)
|
||||
})
|
||||
})
|
||||
145
packages/xrpl/test/models/XChainCommit.test.ts
Normal file
145
packages/xrpl/test/models/XChainCommit.test.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { validate, ValidationError } from '../../src'
|
||||
import { validateXChainCommit } from '../../src/models/transactions/XChainCommit'
|
||||
|
||||
/**
|
||||
* XChainCommit Transaction Verification Testing.
|
||||
*
|
||||
* Providing runtime verification testing for each specific transaction type.
|
||||
*/
|
||||
describe('XChainCommit', function () {
|
||||
let tx
|
||||
|
||||
beforeEach(function () {
|
||||
tx = {
|
||||
Account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
Amount: '10000',
|
||||
XChainBridge: {
|
||||
LockingChainDoor: 'rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL',
|
||||
LockingChainIssue: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
IssuingChainDoor: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV',
|
||||
IssuingChainIssue: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
},
|
||||
Fee: '10',
|
||||
Flags: 2147483648,
|
||||
Sequence: 1,
|
||||
TransactionType: 'XChainCommit',
|
||||
XChainClaimID: '0000000000000001',
|
||||
} as any
|
||||
})
|
||||
|
||||
it('verifies valid XChainCommit', function () {
|
||||
assert.doesNotThrow(() => validateXChainCommit(tx))
|
||||
assert.doesNotThrow(() => validate(tx))
|
||||
})
|
||||
|
||||
it('throws w/ missing XChainBridge', function () {
|
||||
delete tx.XChainBridge
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCommit(tx),
|
||||
ValidationError,
|
||||
'XChainCommit: missing field XChainBridge',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCommit: missing field XChainBridge',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid XChainBridge', function () {
|
||||
tx.XChainBridge = { XChainDoor: 'test' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCommit(tx),
|
||||
ValidationError,
|
||||
'XChainCommit: invalid field XChainBridge',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCommit: invalid field XChainBridge',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing XChainClaimID', function () {
|
||||
delete tx.XChainClaimID
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCommit(tx),
|
||||
ValidationError,
|
||||
'XChainCommit: missing field XChainClaimID',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCommit: missing field XChainClaimID',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid XChainClaimID', function () {
|
||||
tx.XChainClaimID = { currency: 'ETH' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCommit(tx),
|
||||
ValidationError,
|
||||
'XChainCommit: invalid field XChainClaimID',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCommit: invalid field XChainClaimID',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid OtherChainDestination', function () {
|
||||
tx.OtherChainDestination = 123
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCommit(tx),
|
||||
ValidationError,
|
||||
'XChainCommit: invalid field OtherChainDestination',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCommit: invalid field OtherChainDestination',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing Amount', function () {
|
||||
delete tx.Amount
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCommit(tx),
|
||||
ValidationError,
|
||||
'XChainCommit: missing field Amount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCommit: missing field Amount',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid Amount', function () {
|
||||
tx.Amount = { currency: 'ETH' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCommit(tx),
|
||||
ValidationError,
|
||||
'XChainCommit: invalid field Amount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCommit: invalid field Amount',
|
||||
)
|
||||
})
|
||||
})
|
||||
115
packages/xrpl/test/models/XChainCreateBridge.test.ts
Normal file
115
packages/xrpl/test/models/XChainCreateBridge.test.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { validate, ValidationError } from '../../src'
|
||||
import { validateXChainCreateBridge } from '../../src/models/transactions/XChainCreateBridge'
|
||||
|
||||
/**
|
||||
* XChainCreateBridge Transaction Verification Testing.
|
||||
*
|
||||
* Providing runtime verification testing for each specific transaction type.
|
||||
*/
|
||||
describe('XChainCreateBridge', function () {
|
||||
let tx
|
||||
|
||||
beforeEach(function () {
|
||||
tx = {
|
||||
Account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
XChainBridge: {
|
||||
LockingChainDoor: 'rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL',
|
||||
LockingChainIssue: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
IssuingChainDoor: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV',
|
||||
IssuingChainIssue: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
},
|
||||
Fee: '10',
|
||||
Flags: 0,
|
||||
MinAccountCreateAmount: '10000',
|
||||
Sequence: 1,
|
||||
SignatureReward: '1000',
|
||||
TransactionType: 'XChainCreateBridge',
|
||||
} as any
|
||||
})
|
||||
|
||||
it('verifies valid XChainCreateBridge', function () {
|
||||
assert.doesNotThrow(() => validateXChainCreateBridge(tx))
|
||||
assert.doesNotThrow(() => validate(tx))
|
||||
})
|
||||
|
||||
it('throws w/ missing XChainBridge', function () {
|
||||
delete tx.XChainBridge
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCreateBridge(tx),
|
||||
ValidationError,
|
||||
'XChainCreateBridge: missing field XChainBridge',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCreateBridge: missing field XChainBridge',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid XChainBridge', function () {
|
||||
tx.XChainBridge = { XChainDoor: 'test' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCreateBridge(tx),
|
||||
ValidationError,
|
||||
'XChainCreateBridge: invalid field XChainBridge',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCreateBridge: invalid field XChainBridge',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing SignatureReward', function () {
|
||||
delete tx.SignatureReward
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCreateBridge(tx),
|
||||
ValidationError,
|
||||
'XChainCreateBridge: missing field SignatureReward',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCreateBridge: missing field SignatureReward',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid SignatureReward', function () {
|
||||
tx.SignatureReward = { currency: 'ETH' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCreateBridge(tx),
|
||||
ValidationError,
|
||||
'XChainCreateBridge: invalid field SignatureReward',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCreateBridge: invalid field SignatureReward',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid MinAccountCreateAmount', function () {
|
||||
tx.MinAccountCreateAmount = { currency: 'ETH' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCreateBridge(tx),
|
||||
ValidationError,
|
||||
'XChainCreateBridge: invalid field MinAccountCreateAmount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCreateBridge: invalid field MinAccountCreateAmount',
|
||||
)
|
||||
})
|
||||
})
|
||||
130
packages/xrpl/test/models/XChainCreateClaimID.test.ts
Normal file
130
packages/xrpl/test/models/XChainCreateClaimID.test.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { validate, ValidationError } from '../../src'
|
||||
import { validateXChainCreateClaimID } from '../../src/models/transactions/XChainCreateClaimID'
|
||||
|
||||
/**
|
||||
* XChainCreateClaimID Transaction Verification Testing.
|
||||
*
|
||||
* Providing runtime verification testing for each specific transaction type.
|
||||
*/
|
||||
describe('XChainCreateClaimID', function () {
|
||||
let tx
|
||||
|
||||
beforeEach(function () {
|
||||
tx = {
|
||||
Account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
XChainBridge: {
|
||||
LockingChainDoor: 'rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL',
|
||||
LockingChainIssue: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
IssuingChainDoor: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV',
|
||||
IssuingChainIssue: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
},
|
||||
Fee: '10',
|
||||
Flags: 2147483648,
|
||||
OtherChainSource: 'rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL',
|
||||
Sequence: 1,
|
||||
SignatureReward: '10000',
|
||||
TransactionType: 'XChainCreateClaimID',
|
||||
} as any
|
||||
})
|
||||
|
||||
it('verifies valid XChainCreateClaimID', function () {
|
||||
assert.doesNotThrow(() => validateXChainCreateClaimID(tx))
|
||||
assert.doesNotThrow(() => validate(tx))
|
||||
})
|
||||
|
||||
it('throws w/ missing XChainBridge', function () {
|
||||
delete tx.XChainBridge
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCreateClaimID(tx),
|
||||
ValidationError,
|
||||
'XChainCreateClaimID: missing field XChainBridge',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCreateClaimID: missing field XChainBridge',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid XChainBridge', function () {
|
||||
tx.XChainBridge = { XChainDoor: 'test' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCreateClaimID(tx),
|
||||
ValidationError,
|
||||
'XChainCreateClaimID: invalid field XChainBridge',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCreateClaimID: invalid field XChainBridge',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing SignatureReward', function () {
|
||||
delete tx.SignatureReward
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCreateClaimID(tx),
|
||||
ValidationError,
|
||||
'XChainCreateClaimID: missing field SignatureReward',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCreateClaimID: missing field SignatureReward',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid SignatureReward', function () {
|
||||
tx.SignatureReward = { currency: 'ETH' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCreateClaimID(tx),
|
||||
ValidationError,
|
||||
'XChainCreateClaimID: invalid field SignatureReward',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCreateClaimID: invalid field SignatureReward',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ missing OtherChainSource', function () {
|
||||
delete tx.OtherChainSource
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCreateClaimID(tx),
|
||||
ValidationError,
|
||||
'XChainCreateClaimID: missing field OtherChainSource',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCreateClaimID: missing field OtherChainSource',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid OtherChainSource', function () {
|
||||
tx.OtherChainSource = 123
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainCreateClaimID(tx),
|
||||
ValidationError,
|
||||
'XChainCreateClaimID: invalid field OtherChainSource',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainCreateClaimID: invalid field OtherChainSource',
|
||||
)
|
||||
})
|
||||
})
|
||||
100
packages/xrpl/test/models/XChainModifyBridge.test.ts
Normal file
100
packages/xrpl/test/models/XChainModifyBridge.test.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { validate, ValidationError } from '../../src'
|
||||
import { validateXChainModifyBridge } from '../../src/models/transactions/XChainModifyBridge'
|
||||
|
||||
/**
|
||||
* XChainModifyBridge Transaction Verification Testing.
|
||||
*
|
||||
* Providing runtime verification testing for each specific transaction type.
|
||||
*/
|
||||
describe('XChainModifyBridge', function () {
|
||||
let tx
|
||||
|
||||
beforeEach(function () {
|
||||
tx = {
|
||||
Account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
XChainBridge: {
|
||||
LockingChainDoor: 'rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL',
|
||||
LockingChainIssue: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
IssuingChainDoor: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV',
|
||||
IssuingChainIssue: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
},
|
||||
Fee: '10',
|
||||
Flags: 0,
|
||||
MinAccountCreateAmount: '10000',
|
||||
Sequence: 1,
|
||||
SignatureReward: '1000',
|
||||
TransactionType: 'XChainModifyBridge',
|
||||
} as any
|
||||
})
|
||||
|
||||
it('verifies valid XChainModifyBridge', function () {
|
||||
assert.doesNotThrow(() => validateXChainModifyBridge(tx))
|
||||
assert.doesNotThrow(() => validate(tx))
|
||||
})
|
||||
|
||||
it('throws w/ missing XChainBridge', function () {
|
||||
delete tx.XChainBridge
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainModifyBridge(tx),
|
||||
ValidationError,
|
||||
'XChainModifyBridge: missing field XChainBridge',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainModifyBridge: missing field XChainBridge',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid XChainBridge', function () {
|
||||
tx.XChainBridge = { XChainDoor: 'test' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainModifyBridge(tx),
|
||||
ValidationError,
|
||||
'XChainModifyBridge: invalid field XChainBridge',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainModifyBridge: invalid field XChainBridge',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid SignatureReward', function () {
|
||||
tx.SignatureReward = { currency: 'ETH' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainModifyBridge(tx),
|
||||
ValidationError,
|
||||
'XChainModifyBridge: invalid field SignatureReward',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainModifyBridge: invalid field SignatureReward',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws w/ invalid MinAccountCreateAmount', function () {
|
||||
tx.MinAccountCreateAmount = { currency: 'ETH' }
|
||||
|
||||
assert.throws(
|
||||
() => validateXChainModifyBridge(tx),
|
||||
ValidationError,
|
||||
'XChainModifyBridge: invalid field MinAccountCreateAmount',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'XChainModifyBridge: invalid field MinAccountCreateAmount',
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -78,7 +78,7 @@ describe('BaseTransaction', function () {
|
||||
assert.throws(
|
||||
() => validateBaseTransaction(invalidFee),
|
||||
ValidationError,
|
||||
'BaseTransaction: invalid Fee',
|
||||
'Payment: invalid field Fee',
|
||||
)
|
||||
})
|
||||
|
||||
@@ -92,7 +92,7 @@ describe('BaseTransaction', function () {
|
||||
assert.throws(
|
||||
() => validateBaseTransaction(invalidSeq),
|
||||
ValidationError,
|
||||
'BaseTransaction: invalid Sequence',
|
||||
'Payment: invalid field Sequence',
|
||||
)
|
||||
})
|
||||
|
||||
@@ -106,7 +106,7 @@ describe('BaseTransaction', function () {
|
||||
assert.throws(
|
||||
() => validateBaseTransaction(invalidID),
|
||||
ValidationError,
|
||||
'BaseTransaction: invalid AccountTxnID',
|
||||
'Payment: invalid field AccountTxnID',
|
||||
)
|
||||
})
|
||||
|
||||
@@ -120,7 +120,7 @@ describe('BaseTransaction', function () {
|
||||
assert.throws(
|
||||
() => validateBaseTransaction(invalidLastLedgerSequence),
|
||||
ValidationError,
|
||||
'BaseTransaction: invalid LastLedgerSequence',
|
||||
'Payment: invalid field LastLedgerSequence',
|
||||
)
|
||||
})
|
||||
|
||||
@@ -134,7 +134,7 @@ describe('BaseTransaction', function () {
|
||||
assert.throws(
|
||||
() => validateBaseTransaction(invalidSourceTag),
|
||||
ValidationError,
|
||||
'BaseTransaction: invalid SourceTag',
|
||||
'Payment: invalid field SourceTag',
|
||||
)
|
||||
})
|
||||
|
||||
@@ -148,7 +148,7 @@ describe('BaseTransaction', function () {
|
||||
assert.throws(
|
||||
() => validateBaseTransaction(invalidSigningPubKey),
|
||||
ValidationError,
|
||||
'BaseTransaction: invalid SigningPubKey',
|
||||
'Payment: invalid field SigningPubKey',
|
||||
)
|
||||
})
|
||||
|
||||
@@ -162,7 +162,7 @@ describe('BaseTransaction', function () {
|
||||
assert.throws(
|
||||
() => validateBaseTransaction(invalidTicketSequence),
|
||||
ValidationError,
|
||||
'BaseTransaction: invalid TicketSequence',
|
||||
'Payment: invalid field TicketSequence',
|
||||
)
|
||||
})
|
||||
|
||||
@@ -176,7 +176,7 @@ describe('BaseTransaction', function () {
|
||||
assert.throws(
|
||||
() => validateBaseTransaction(invalidTxnSignature),
|
||||
ValidationError,
|
||||
'BaseTransaction: invalid TxnSignature',
|
||||
'Payment: invalid field TxnSignature',
|
||||
)
|
||||
})
|
||||
|
||||
@@ -242,7 +242,7 @@ describe('BaseTransaction', function () {
|
||||
assert.throws(
|
||||
() => validateBaseTransaction(invalidNetworkID),
|
||||
ValidationError,
|
||||
'BaseTransaction: invalid NetworkID',
|
||||
'Payment: invalid field NetworkID',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { getNFTokenID } from '../../src'
|
||||
import * as NFTokenResponse from '../fixtures/rippled/mintNFTMeta.json'
|
||||
import * as NFTokenResponse2 from '../fixtures/rippled/mintNFTMeta2.json'
|
||||
import fixtures from '../fixtures/rippled'
|
||||
|
||||
describe('getNFTokenID', function () {
|
||||
it('decode a valid NFTokenID', function () {
|
||||
const result = getNFTokenID(NFTokenResponse.meta)
|
||||
const result = getNFTokenID(fixtures.tx.NFTokenMint.meta)
|
||||
const expectedNFTokenID =
|
||||
'00081388DC1AB4937C899037B2FDFC3CB20F6F64E73120BB5F8AA66A00000228'
|
||||
assert.equal(result, expectedNFTokenID)
|
||||
})
|
||||
|
||||
it('decode a different valid NFTokenID', function () {
|
||||
const result = getNFTokenID(NFTokenResponse2.meta)
|
||||
const result = getNFTokenID(fixtures.tx.NFTokenMint2.meta)
|
||||
const expectedNFTokenID =
|
||||
'0008125CBE4B401B2F62ED35CC67362165AA813CCA06316FFA766254000003EE'
|
||||
assert.equal(result, expectedNFTokenID)
|
||||
@@ -21,8 +20,8 @@ describe('getNFTokenID', function () {
|
||||
|
||||
it('fails with nice error when given raw response instead of meta', function () {
|
||||
assert.throws(() => {
|
||||
// @ts-expect-error - Validating error for javascript users
|
||||
const _ = getNFTokenID(NFTokenResponse)
|
||||
// @ts-expect-error -- on purpose, to check the error
|
||||
const _ = getNFTokenID(fixtures.tx.NFTokenMint)
|
||||
}, /^Unable to parse the parameter given to getNFTokenID.*/u)
|
||||
})
|
||||
})
|
||||
|
||||
25
packages/xrpl/test/utils/getXChainClaimID.test.ts
Normal file
25
packages/xrpl/test/utils/getXChainClaimID.test.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { getXChainClaimID } from '../../src'
|
||||
import fixtures from '../fixtures/rippled'
|
||||
|
||||
describe('getXChainClaimID', function () {
|
||||
it('decode a valid XChainClaimID', function () {
|
||||
const result = getXChainClaimID(fixtures.tx.XChainCreateClaimID.meta)
|
||||
const expectedXChainClaimID = 'b0'
|
||||
assert.equal(result, expectedXChainClaimID)
|
||||
})
|
||||
|
||||
it('decode a different valid XChainClaimID', function () {
|
||||
const result = getXChainClaimID(fixtures.tx.XChainCreateClaimID2.meta)
|
||||
const expectedXChainClaimID = 'ac'
|
||||
assert.equal(result, expectedXChainClaimID)
|
||||
})
|
||||
|
||||
it('fails with nice error when given raw response instead of meta', function () {
|
||||
assert.throws(() => {
|
||||
// @ts-expect-error -- on purpose, to check the error
|
||||
const _ = getXChainClaimID(fixtures.tx.XChainCreateClaimID)
|
||||
}, /^Unable to parse the parameter given to getXChainClaimID.*/u)
|
||||
})
|
||||
})
|
||||
147
packages/xrpl/tools/createValidate.js
Normal file
147
packages/xrpl/tools/createValidate.js
Normal file
@@ -0,0 +1,147 @@
|
||||
/* eslint-disable no-continue -- unneeded here */
|
||||
/**
|
||||
* This file writes the `validate` function for a transaction, when provided the model name in the `src/models/transactions`
|
||||
* folder.
|
||||
*/
|
||||
const fs = require('fs')
|
||||
|
||||
const NORMAL_TYPES = ['number', 'string']
|
||||
const NUMBERS = ['0', '1']
|
||||
|
||||
// TODO: rewrite this to use regex
|
||||
|
||||
async function main() {
|
||||
if (process.argv.length < 3) {
|
||||
console.log(`Usage: ${process.argv[0]} ${process.argv[1]} TxName`)
|
||||
process.exit(1)
|
||||
}
|
||||
const modelName = process.argv[2]
|
||||
const filename = `./src/models/transactions/${modelName}.ts`
|
||||
const [model, txName] = await getModel(filename)
|
||||
return processModel(model, txName)
|
||||
}
|
||||
|
||||
async function getModel(filename) {
|
||||
let model = ''
|
||||
let started = false
|
||||
let ended = false
|
||||
const data = await fs.promises.readFile(filename, { encoding: 'utf8' })
|
||||
const lines = data.split('\n')
|
||||
for (const line of lines) {
|
||||
if (ended) {
|
||||
continue
|
||||
}
|
||||
if (!started && !line.startsWith('export')) {
|
||||
continue
|
||||
}
|
||||
if (!started && line.includes('Flags')) {
|
||||
continue
|
||||
}
|
||||
if (!started) {
|
||||
started = true
|
||||
}
|
||||
model += `${line}\n`
|
||||
if (line === '}') {
|
||||
ended = true
|
||||
}
|
||||
}
|
||||
const name_line = model.split('\n')[0].split(' ')
|
||||
const txName = name_line[2]
|
||||
return [model, txName]
|
||||
}
|
||||
|
||||
function getValidationFunction(paramType) {
|
||||
if (NORMAL_TYPES.includes(paramType)) {
|
||||
const paramTypeCapitalized =
|
||||
paramType.substring(0, 1).toUpperCase() + paramType.substring(1)
|
||||
return `is${paramTypeCapitalized}(inp)`
|
||||
}
|
||||
if (NUMBERS.includes(paramType)) {
|
||||
return `inp === ${paramType}`
|
||||
}
|
||||
return `is${paramType}(inp)`
|
||||
}
|
||||
|
||||
function getValidationLine(validationFns) {
|
||||
if (validationFns.length === 1) {
|
||||
if (!validationFns[0].includes('===')) {
|
||||
// Example: `validateRequiredFields(tx, 'Amount', isAmount)`
|
||||
const validationFn = validationFns[0]
|
||||
// strip the `(inp)` in e.g. `isAmount(inp)`
|
||||
return validationFn.substring(0, validationFn.length - 5)
|
||||
}
|
||||
}
|
||||
// Example:
|
||||
// `validateRequiredFields(tx, 'XChainAccountCreateCount',
|
||||
// (inp) => isNumber(inp) || isString(inp)))`
|
||||
return `(inp) => ${validationFns.join(' || ')}`
|
||||
}
|
||||
|
||||
function processModel(model, txName) {
|
||||
let output = ''
|
||||
// process the TS model and get the types of each parameter
|
||||
for (let line of model.split('\n')) {
|
||||
if (line === '') {
|
||||
continue
|
||||
}
|
||||
if (line.startsWith('export')) {
|
||||
continue
|
||||
}
|
||||
if (line === '}') {
|
||||
continue
|
||||
}
|
||||
line = line.trim()
|
||||
if (line.startsWith('TransactionType')) {
|
||||
continue
|
||||
}
|
||||
if (line.startsWith('Flags')) {
|
||||
continue
|
||||
}
|
||||
if (line.startsWith('/**')) {
|
||||
continue
|
||||
}
|
||||
if (line.startsWith('*')) {
|
||||
continue
|
||||
}
|
||||
|
||||
// process the line with a type
|
||||
const split = line.split(' ')
|
||||
const param = split[0].replace('?:', '').replace(':', '').trim()
|
||||
const paramTypes = split.slice(1)
|
||||
const optional = split[0].endsWith('?:')
|
||||
const functionName = optional
|
||||
? 'validateOptionalField'
|
||||
: 'validateRequiredField'
|
||||
|
||||
// process the types and turn them into a validation function
|
||||
let idx = 0
|
||||
const if_outputs = []
|
||||
while (idx < paramTypes.length) {
|
||||
const paramType = paramTypes[idx]
|
||||
if_outputs.push(getValidationFunction(paramType))
|
||||
idx += 2
|
||||
}
|
||||
|
||||
output += ` ${functionName}(tx, '${param}', ${getValidationLine(
|
||||
if_outputs,
|
||||
)})\n\n`
|
||||
}
|
||||
output = output.substring(0, output.length - 1)
|
||||
output += '}\n'
|
||||
|
||||
// initial output content
|
||||
output = `/**
|
||||
* Verify the form and type of a ${txName} at runtime.
|
||||
*
|
||||
* @param tx - A ${txName} Transaction.
|
||||
* @throws When the ${txName} is malformed.
|
||||
*/
|
||||
export function validate${txName}(tx: Record<string, unknown>): void {
|
||||
validateBaseTransaction(tx)
|
||||
|
||||
${output}`
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
main().then(console.log)
|
||||
@@ -6,6 +6,7 @@
|
||||
"./test/**/*.json",
|
||||
"./src/**/*.json",
|
||||
"./snippets/src/**/*.ts",
|
||||
".eslintrc.js"
|
||||
".eslintrc.js",
|
||||
],
|
||||
"exclude": ["./tools/*.js"]
|
||||
}
|
||||
|
||||
187
tools/createValidateTests.js
Normal file
187
tools/createValidateTests.js
Normal file
@@ -0,0 +1,187 @@
|
||||
const fs = require("fs");
|
||||
const fixtures = require("../packages/ripple-binary-codec/test/fixtures/codec-fixtures.json");
|
||||
|
||||
const NORMAL_TYPES = ["number", "string"];
|
||||
const NUMBERS = ["0", "1"];
|
||||
|
||||
function getTx(txName) {
|
||||
transactions = fixtures.transactions;
|
||||
const validTxs = fixtures.transactions
|
||||
.filter((tx) => tx.json.TransactionType === txName)
|
||||
.map((tx) => tx.json);
|
||||
const validTx = validTxs[0];
|
||||
delete validTx.TxnSignature;
|
||||
delete validTx.SigningPubKey;
|
||||
return JSON.stringify(validTx, null, 2);
|
||||
}
|
||||
|
||||
function main() {
|
||||
const modelName = process.argv[2];
|
||||
const filename = `./packages/xrpl/src/models/transactions/${modelName}.ts`;
|
||||
const [model, txName] = getModel(filename);
|
||||
return processModel(model, txName);
|
||||
}
|
||||
|
||||
// Extract just the model from the file
|
||||
function getModel(filename) {
|
||||
let model = "";
|
||||
let started = false;
|
||||
let ended = false;
|
||||
const data = fs.readFileSync(filename, "utf8");
|
||||
const lines = data.split("\n");
|
||||
for (let line of lines) {
|
||||
if (ended) {
|
||||
continue;
|
||||
}
|
||||
if (!started && !line.startsWith("export")) {
|
||||
continue;
|
||||
}
|
||||
if (!started && line.includes("Flags")) {
|
||||
continue;
|
||||
}
|
||||
if (!started) {
|
||||
started = true;
|
||||
}
|
||||
model += line + "\n";
|
||||
if (line === "}") {
|
||||
ended = true;
|
||||
}
|
||||
}
|
||||
const name_line = model.split("\n")[0].split(" ");
|
||||
const txName = name_line[2];
|
||||
return [model, txName];
|
||||
}
|
||||
|
||||
function getInvalidValue(paramTypes) {
|
||||
if (paramTypes.length === 1) {
|
||||
const paramType = paramTypes[0];
|
||||
if (paramType == "number") {
|
||||
return "'number'";
|
||||
} else if (paramType == "string") {
|
||||
return 123;
|
||||
} else if (paramType == "IssuedCurrency") {
|
||||
return JSON.stringify({ test: "test" });
|
||||
} else if (paramType == "Amount") {
|
||||
return JSON.stringify({ currency: "ETH" });
|
||||
} else if (paramType == "XChainBridge") {
|
||||
return JSON.stringify({ XChainDoor: "test" });
|
||||
} else {
|
||||
throw Error(`${paramType} not supported yet`);
|
||||
}
|
||||
}
|
||||
|
||||
const simplifiedParamTypes = paramTypes.filter(
|
||||
(_paramType, index) => index % 2 == 0
|
||||
);
|
||||
if (JSON.stringify(simplifiedParamTypes) === '["0","1"]') {
|
||||
return 2;
|
||||
} else if (JSON.stringify(simplifiedParamTypes) === '["number","string"]') {
|
||||
return JSON.stringify({ currency: "ETH" });
|
||||
} else {
|
||||
throw Error(`${simplifiedParamTypes} not supported yet`);
|
||||
}
|
||||
}
|
||||
|
||||
// Process the model and build the tests
|
||||
|
||||
function processModel(model, txName) {
|
||||
let output = "";
|
||||
for (let line of model.split("\n")) {
|
||||
if (line == "") {
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("export")) {
|
||||
continue;
|
||||
}
|
||||
if (line == "}") {
|
||||
continue;
|
||||
}
|
||||
line = line.trim();
|
||||
if (line.startsWith("TransactionType")) {
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("Flags")) {
|
||||
// TODO: support flag checking
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("/**")) {
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("*")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const split = line.split(" ");
|
||||
const param = split[0].replace("?:", "").replace(":", "").trim();
|
||||
const paramTypes = split.slice(1);
|
||||
const optional = split[0].endsWith("?:");
|
||||
|
||||
if (!optional) {
|
||||
output += ` it("throws w/ missing ${param}", function () {
|
||||
delete tx.${param}
|
||||
|
||||
assert.throws(
|
||||
() => validate${txName}(tx),
|
||||
ValidationError,
|
||||
'${txName}: missing field ${param}',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'${txName}: missing field ${param}',
|
||||
)
|
||||
})
|
||||
|
||||
`;
|
||||
}
|
||||
|
||||
const fakeValue = getInvalidValue(paramTypes);
|
||||
output += ` it('throws w/ invalid ${param}', function () {
|
||||
tx.${param} = ${fakeValue}
|
||||
|
||||
assert.throws(
|
||||
() => validate${txName}(tx),
|
||||
ValidationError,
|
||||
'${txName}: invalid field ${param}',
|
||||
)
|
||||
assert.throws(
|
||||
() => validate(tx),
|
||||
ValidationError,
|
||||
'${txName}: invalid field ${param}',
|
||||
)
|
||||
})
|
||||
|
||||
`;
|
||||
}
|
||||
|
||||
output = output.substring(0, output.length - 2);
|
||||
output += "\n})\n";
|
||||
output =
|
||||
`import { assert } from 'chai'
|
||||
|
||||
import { validate, ValidationError } from '../../src'
|
||||
import { validate${txName} } from '../../src/models/transactions/${txName}'
|
||||
|
||||
/**
|
||||
* ${txName} Transaction Verification Testing.
|
||||
*
|
||||
* Providing runtime verification testing for each specific transaction type.
|
||||
*/
|
||||
describe('${txName}', function () {
|
||||
let tx
|
||||
|
||||
beforeEach(function () {
|
||||
tx = ${getTx(txName)} as any
|
||||
})
|
||||
|
||||
it('verifies valid ${txName}', function () {
|
||||
assert.doesNotThrow(() => validate${txName}(tx))
|
||||
assert.doesNotThrow(() => validate(tx))
|
||||
})
|
||||
|
||||
` + output;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
console.log(main());
|
||||
Reference in New Issue
Block a user