mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-26 15:15:49 +00:00
feat: add AMM support (#2071)
* update definitions.json * add AMMInstanceCreate * renamed LPTokens to LPToken in definitions.json * update HISTORY.md * add amm_info RPC command * add AMMDeposit * use null check for missing fields * add AMMWithdraw * add AMMVote * fix lint error * add max trading fee check to AMMVote * refactor MAX_TRADING_FEE to be in one place * add AMMBid * add AuthAccount interface to AMMBid * refactor tests * add AMMID to AMMInfoResponse * update amm_info docstrings * fix EPrice type to be Amount * update EPrice validation error message and add missing tests * update definitions to fix AMM in LEDGER_ENTRY_TYPES * add missing test case Asset1In and Asset2In valid * add missing test case Asset1Out and Asset2Out valid * add negative FeeVal check * update HISTORY.md to specify XLS-30 * update wording on AMMDeposit & AMMWithdraw validation errors * add negative TradingFee check * fix ammInfo response * add AMMID as optional param in ammInfo response * fix EPrice validation checks in AMMDeposit & AMMWithdraw * add VoteSlots as optional param in AMMInfoResponse * update VoteEntry interface * fix deposit and withdraw tests * fix AMMBid ValidationError * update definitions.json with different AuthAccounts number * Change amm_info asset parameters to Currency type * API name changes with updated definitions.json * rename amm_info param asset1 -> asset * fix typo * change AMM_MAX_TRADING_FEE to 1% * Use Asset/Asset2 instead of AMMID for Deposit/Withdraw/Bid/Vote * add Deposit/Withdraw flags * rename FeeVal -> TradingFee in VoteEntry * rename MinBidPrice -> BidMin and MaxBidPrice -> BidMax * update definitions to change Asset & Asset2 nth values to 3 & 4 * update definitions * add Issue type and tests for Asset/Asset2 * remove AMMID from amm_info and use Issue type * update amm_info fields * fix lint errors * update unit tests * add AMM codec-fixtures * update Issue type * add one asset and withdraw all tests * refactor amm_info response fields to match AMMDevnet * update definitions.json with refactored error codes * update ammInfo.ts response model * remove invalid fields from ammInfo.ts response model * update time_interval description * rename test model names and fix lint errors * add Owner Reserve Fee for AMMCreate transaction * add missing asset_frozen field * replace Issue with IssuedCurrency * refactor: convert flags to number * update asset pair to use Currency type * refactor isIssue to isCurrency * add AMM ledger entry object, lsfAMM flag, amm fields to LedgerEntryRequest * update definitions.json * WIP defintions * update codec-fixtures * fix definitions test * update DiscountedFee definition * update definitions * update codec-fixtures * update definitions * update unit tests * update amm_info response * sort imports/exports * update jsdoc * update amm_info jsdoc * update jsdoc * convert caution to all caps * add validation for AuthAccounts * refactor and export interfaces * use Currency type * update definitions * add AMMDelete * rename Issue to Currency in error message * mark asset frozen as optional fields * refactor isAuthAccounts * add AMMDelete jsdoc * rename to validateAuthAccounts * fix typo * fix typo in unit test --------- Co-authored-by: Caleb Kniffen <ckniffen@ripple.com>
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
"UInt192": 21,
|
"UInt192": 21,
|
||||||
"UInt384": 22,
|
"UInt384": 22,
|
||||||
"UInt512": 23,
|
"UInt512": 23,
|
||||||
|
"Issue": 24,
|
||||||
"Transaction": 10001,
|
"Transaction": 10001,
|
||||||
"LedgerEntry": 10002,
|
"LedgerEntry": 10002,
|
||||||
"Validation": 10003,
|
"Validation": 10003,
|
||||||
@@ -44,6 +45,7 @@
|
|||||||
"NegativeUNL": 78,
|
"NegativeUNL": 78,
|
||||||
"NFTokenPage": 80,
|
"NFTokenPage": 80,
|
||||||
"NFTokenOffer": 55,
|
"NFTokenOffer": 55,
|
||||||
|
"AMM": 121,
|
||||||
"Any": -3,
|
"Any": -3,
|
||||||
"Child": -2,
|
"Child": -2,
|
||||||
"Nickname": 110,
|
"Nickname": 110,
|
||||||
@@ -271,6 +273,26 @@
|
|||||||
"type": "UInt16"
|
"type": "UInt16"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"TradingFee",
|
||||||
|
{
|
||||||
|
"nth": 5,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "UInt16"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"DiscountedFee",
|
||||||
|
{
|
||||||
|
"nth": 6,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "UInt16"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"Version",
|
"Version",
|
||||||
{
|
{
|
||||||
@@ -771,6 +793,26 @@
|
|||||||
"type": "UInt32"
|
"type": "UInt32"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"VoteWeight",
|
||||||
|
{
|
||||||
|
"nth": 48,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "UInt32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"FirstNFTokenSequence",
|
||||||
|
{
|
||||||
|
"nth": 50,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "UInt32"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"IndexNext",
|
"IndexNext",
|
||||||
{
|
{
|
||||||
@@ -1121,6 +1163,16 @@
|
|||||||
"type": "Hash256"
|
"type": "Hash256"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"AMMID",
|
||||||
|
{
|
||||||
|
"nth": 14,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Hash256"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"BookDirectory",
|
"BookDirectory",
|
||||||
{
|
{
|
||||||
@@ -1391,6 +1443,36 @@
|
|||||||
"type": "Amount"
|
"type": "Amount"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"Amount2",
|
||||||
|
{
|
||||||
|
"nth": 11,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Amount"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"BidMin",
|
||||||
|
{
|
||||||
|
"nth": 12,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Amount"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"BidMax",
|
||||||
|
{
|
||||||
|
"nth": 13,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Amount"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"MinimumOffer",
|
"MinimumOffer",
|
||||||
{
|
{
|
||||||
@@ -1431,6 +1513,86 @@
|
|||||||
"type": "Amount"
|
"type": "Amount"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"BaseFeeDrops",
|
||||||
|
{
|
||||||
|
"nth": 22,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Amount"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ReserveBaseDrops",
|
||||||
|
{
|
||||||
|
"nth": 23,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Amount"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ReserveIncrementDrops",
|
||||||
|
{
|
||||||
|
"nth": 24,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Amount"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"LPTokenOut",
|
||||||
|
{
|
||||||
|
"nth": 25,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Amount"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"LPTokenIn",
|
||||||
|
{
|
||||||
|
"nth": 26,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Amount"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"EPrice",
|
||||||
|
{
|
||||||
|
"nth": 27,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Amount"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Price",
|
||||||
|
{
|
||||||
|
"nth": 28,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Amount"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"LPTokenBalance",
|
||||||
|
{
|
||||||
|
"nth": 31,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Amount"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"PublicKey",
|
"PublicKey",
|
||||||
{
|
{
|
||||||
@@ -1821,6 +1983,26 @@
|
|||||||
"type": "PathSet"
|
"type": "PathSet"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"Asset",
|
||||||
|
{
|
||||||
|
"nth": 3,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Issue"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Asset2",
|
||||||
|
{
|
||||||
|
"nth": 4,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Issue"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"TransactionMetaData",
|
"TransactionMetaData",
|
||||||
{
|
{
|
||||||
@@ -2031,6 +2213,36 @@
|
|||||||
"type": "STObject"
|
"type": "STObject"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"VoteEntry",
|
||||||
|
{
|
||||||
|
"nth": 25,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "STObject"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"AuctionSlot",
|
||||||
|
{
|
||||||
|
"nth": 26,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "STObject"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"AuthAccount",
|
||||||
|
{
|
||||||
|
"nth": 27,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "STObject"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"Signers",
|
"Signers",
|
||||||
{
|
{
|
||||||
@@ -2121,6 +2333,16 @@
|
|||||||
"type": "STArray"
|
"type": "STArray"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"VoteSlots",
|
||||||
|
{
|
||||||
|
"nth": 12,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "STArray"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"Majorities",
|
"Majorities",
|
||||||
{
|
{
|
||||||
@@ -2170,6 +2392,16 @@
|
|||||||
"isSigningField": true,
|
"isSigningField": true,
|
||||||
"type": "STArray"
|
"type": "STArray"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"AuthAccounts",
|
||||||
|
{
|
||||||
|
"nth": 25,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "STArray"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"TRANSACTION_RESULTS": {
|
"TRANSACTION_RESULTS": {
|
||||||
@@ -2228,6 +2460,7 @@
|
|||||||
"temUNKNOWN": -264,
|
"temUNKNOWN": -264,
|
||||||
"temSEQ_AND_TICKET": -263,
|
"temSEQ_AND_TICKET": -263,
|
||||||
"temBAD_NFTOKEN_TRANSFER_FEE": -262,
|
"temBAD_NFTOKEN_TRANSFER_FEE": -262,
|
||||||
|
"temBAD_AMM_TOKENS": -261,
|
||||||
|
|
||||||
"tefFAILURE": -199,
|
"tefFAILURE": -199,
|
||||||
"tefALREADY": -198,
|
"tefALREADY": -198,
|
||||||
@@ -2263,6 +2496,7 @@
|
|||||||
"terNO_RIPPLE": -90,
|
"terNO_RIPPLE": -90,
|
||||||
"terQUEUED": -89,
|
"terQUEUED": -89,
|
||||||
"terPRE_TICKET": -88,
|
"terPRE_TICKET": -88,
|
||||||
|
"terNO_AMM": -87,
|
||||||
|
|
||||||
"tesSUCCESS": 0,
|
"tesSUCCESS": 0,
|
||||||
|
|
||||||
@@ -2311,7 +2545,15 @@
|
|||||||
"tecCANT_ACCEPT_OWN_NFTOKEN_OFFER": 158,
|
"tecCANT_ACCEPT_OWN_NFTOKEN_OFFER": 158,
|
||||||
"tecINSUFFICIENT_FUNDS": 159,
|
"tecINSUFFICIENT_FUNDS": 159,
|
||||||
"tecOBJECT_NOT_FOUND": 160,
|
"tecOBJECT_NOT_FOUND": 160,
|
||||||
"tecINSUFFICIENT_PAYMENT": 161
|
"tecINSUFFICIENT_PAYMENT": 161,
|
||||||
|
"tecUNFUNDED_AMM": 162,
|
||||||
|
"tecAMM_BALANCE": 163,
|
||||||
|
"tecAMM_FAILED": 164,
|
||||||
|
"tecAMM_INVALID_TOKENS": 165,
|
||||||
|
"tecAMM_EMPTY": 166,
|
||||||
|
"tecAMM_NOT_EMPTY": 167,
|
||||||
|
"tecAMM_ACCOUNT": 168,
|
||||||
|
"tecINCOMPLETE": 169
|
||||||
},
|
},
|
||||||
"TRANSACTION_TYPES": {
|
"TRANSACTION_TYPES": {
|
||||||
"Invalid": -1,
|
"Invalid": -1,
|
||||||
@@ -2344,6 +2586,12 @@
|
|||||||
"NFTokenCancelOffer": 28,
|
"NFTokenCancelOffer": 28,
|
||||||
"NFTokenAcceptOffer": 29,
|
"NFTokenAcceptOffer": 29,
|
||||||
"Clawback": 30,
|
"Clawback": 30,
|
||||||
|
"AMMCreate": 35,
|
||||||
|
"AMMDeposit": 36,
|
||||||
|
"AMMWithdraw": 37,
|
||||||
|
"AMMVote": 38,
|
||||||
|
"AMMBid": 39,
|
||||||
|
"AMMDelete": 40,
|
||||||
"EnableAmendment": 100,
|
"EnableAmendment": 100,
|
||||||
"SetFee": 101,
|
"SetFee": 101,
|
||||||
"UNLModify": 102
|
"UNLModify": 102
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Currency } from './currency'
|
|||||||
import { Hash128 } from './hash-128'
|
import { Hash128 } from './hash-128'
|
||||||
import { Hash160 } from './hash-160'
|
import { Hash160 } from './hash-160'
|
||||||
import { Hash256 } from './hash-256'
|
import { Hash256 } from './hash-256'
|
||||||
|
import { Issue } from './issue'
|
||||||
import { PathSet } from './path-set'
|
import { PathSet } from './path-set'
|
||||||
import { STArray } from './st-array'
|
import { STArray } from './st-array'
|
||||||
import { STObject } from './st-object'
|
import { STObject } from './st-object'
|
||||||
@@ -24,6 +25,7 @@ const coreTypes: Record<string, typeof SerializedType> = {
|
|||||||
Hash128,
|
Hash128,
|
||||||
Hash160,
|
Hash160,
|
||||||
Hash256,
|
Hash256,
|
||||||
|
Issue,
|
||||||
PathSet,
|
PathSet,
|
||||||
STArray,
|
STArray,
|
||||||
STObject,
|
STObject,
|
||||||
|
|||||||
96
packages/ripple-binary-codec/src/types/issue.ts
Normal file
96
packages/ripple-binary-codec/src/types/issue.ts
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
import { BinaryParser } from '../serdes/binary-parser'
|
||||||
|
|
||||||
|
import { AccountID } from './account-id'
|
||||||
|
import { Currency } from './currency'
|
||||||
|
import { JsonObject, SerializedType } from './serialized-type'
|
||||||
|
import { Buffer } from 'buffer/'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for JSON objects that represent amounts
|
||||||
|
*/
|
||||||
|
interface IssueObject extends JsonObject {
|
||||||
|
currency: string
|
||||||
|
issuer?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type guard for AmountObject
|
||||||
|
*/
|
||||||
|
function isIssueObject(arg): arg is IssueObject {
|
||||||
|
const keys = Object.keys(arg).sort()
|
||||||
|
if (keys.length === 1) {
|
||||||
|
return keys[0] === 'currency'
|
||||||
|
}
|
||||||
|
return keys.length === 2 && keys[0] === 'currency' && keys[1] === 'issuer'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for serializing/Deserializing Amounts
|
||||||
|
*/
|
||||||
|
class Issue extends SerializedType {
|
||||||
|
static readonly ZERO_ISSUED_CURRENCY: Issue = new Issue(Buffer.alloc(20))
|
||||||
|
|
||||||
|
constructor(bytes: Buffer) {
|
||||||
|
super(bytes ?? Issue.ZERO_ISSUED_CURRENCY.bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an amount from an IOU or string amount
|
||||||
|
*
|
||||||
|
* @param value An Amount, object representing an IOU, or a string
|
||||||
|
* representing an integer amount
|
||||||
|
* @returns An Amount object
|
||||||
|
*/
|
||||||
|
static from<T extends Issue | IssueObject>(value: T): Issue {
|
||||||
|
if (value instanceof Issue) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isIssueObject(value)) {
|
||||||
|
const currency = Currency.from(value.currency).toBytes()
|
||||||
|
if (value.issuer == null) {
|
||||||
|
return new Issue(currency)
|
||||||
|
}
|
||||||
|
const issuer = AccountID.from(value.issuer).toBytes()
|
||||||
|
return new Issue(Buffer.concat([currency, issuer]))
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Invalid type to construct an Amount')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read an amount from a BinaryParser
|
||||||
|
*
|
||||||
|
* @param parser BinaryParser to read the Amount from
|
||||||
|
* @returns An Amount object
|
||||||
|
*/
|
||||||
|
static fromParser(parser: BinaryParser): Issue {
|
||||||
|
const currency = parser.read(20)
|
||||||
|
if (new Currency(currency).toJSON() === 'XRP') {
|
||||||
|
return new Issue(currency)
|
||||||
|
}
|
||||||
|
const currencyAndIssuer = [currency, parser.read(20)]
|
||||||
|
return new Issue(Buffer.concat(currencyAndIssuer))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the JSON representation of this Amount
|
||||||
|
*
|
||||||
|
* @returns the JSON interpretation of this.bytes
|
||||||
|
*/
|
||||||
|
toJSON(): IssueObject {
|
||||||
|
const parser = new BinaryParser(this.toString())
|
||||||
|
const currency = Currency.fromParser(parser) as Currency
|
||||||
|
if (currency.toJSON() === 'XRP') {
|
||||||
|
return { currency: currency.toJSON() }
|
||||||
|
}
|
||||||
|
const issuer = AccountID.fromParser(parser) as AccountID
|
||||||
|
|
||||||
|
return {
|
||||||
|
currency: currency.toJSON(),
|
||||||
|
issuer: issuer.toJSON(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Issue, IssueObject }
|
||||||
@@ -129,7 +129,7 @@ describe('encode and decode using new types as a parameter', function () {
|
|||||||
// Normally this would be generated directly from rippled with something like `server_definitions`.
|
// Normally this would be generated directly from rippled with something like `server_definitions`.
|
||||||
// Added here to make it easier to see what is actually changing in the definitions.json file.
|
// Added here to make it easier to see what is actually changing in the definitions.json file.
|
||||||
const definitions = JSON.parse(JSON.stringify(normalDefinitionsJson))
|
const definitions = JSON.parse(JSON.stringify(normalDefinitionsJson))
|
||||||
definitions.TYPES.NewType = 24
|
definitions.TYPES.NewType = 31
|
||||||
definitions.FIELDS.push([
|
definitions.FIELDS.push([
|
||||||
'TestField',
|
'TestField',
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4448,6 +4448,213 @@
|
|||||||
"Flags": 0,
|
"Flags": 0,
|
||||||
"Sequence": 62
|
"Sequence": 62
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binary": "12002315000A2200000000240015DAE161400000000000271068400000000000000A6BD5838D7EA4C680000000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C7321ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B87440B3154D968314FCEB58001E1B0C3A4CFB33DF9FF6C73207E5EAEB9BD07E2747672168E1A2786D950495C38BD8DEE3391BF45F3008DD36F4B12E7C07D82CA5250E8114F92F27CC5EE2F2760278FE096D0CBE32BDD3653A",
|
||||||
|
"json": {
|
||||||
|
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
|
||||||
|
"TransactionType": "AMMCreate",
|
||||||
|
"TxnSignature": "B3154D968314FCEB58001E1B0C3A4CFB33DF9FF6C73207E5EAEB9BD07E2747672168E1A2786D950495C38BD8DEE3391BF45F3008DD36F4B12E7C07D82CA5250E",
|
||||||
|
"Amount": "10000",
|
||||||
|
"Amount2": {
|
||||||
|
"currency": "ETH",
|
||||||
|
"issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9",
|
||||||
|
"value": "10000"
|
||||||
|
},
|
||||||
|
"TradingFee": 10,
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 0,
|
||||||
|
"Sequence": 1432289,
|
||||||
|
"SigningPubKey": "ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binary": "1200242200010000240015DAE168400000000000000A6019D5438D7EA4C68000B3813FCAB4EE68B3D0D735D6849465A9113EE048B3813FCAB4EE68B3D0D735D6849465A9113EE0487321ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B874408073C588E7EF672DD171E414638D9AF8DBE9A1359E030DE3E1C9AA6A38A2CE9E138CB56482BB844F7228D48B1E4AD7D09BB7E9F639C115958EEEA374749CA00B8114F92F27CC5EE2F2760278FE096D0CBE32BDD3653A0318000000000000000000000000000000000000000004180000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C",
|
||||||
|
"json": {
|
||||||
|
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
|
||||||
|
"TransactionType": "AMMDeposit",
|
||||||
|
"TxnSignature": "8073C588E7EF672DD171E414638D9AF8DBE9A1359E030DE3E1C9AA6A38A2CE9E138CB56482BB844F7228D48B1E4AD7D09BB7E9F639C115958EEEA374749CA00B",
|
||||||
|
"Asset": {"currency": "XRP"},
|
||||||
|
"Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
|
||||||
|
"LPTokenOut": {"currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048", "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg", "value": "1000"},
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 65536,
|
||||||
|
"Sequence": 1432289,
|
||||||
|
"SigningPubKey": "ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binary": "1200242200080000240015DAE16140000000000003E868400000000000000A7321ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8744096CA066F42871C55088D2758D64148921B1ACAA5C6C648D0F7D675BBF47F87DF711F17C5BD172666D5AEC257520C587A849A6E063345609D91E121A78816EB048114F92F27CC5EE2F2760278FE096D0CBE32BDD3653A0318000000000000000000000000000000000000000004180000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C",
|
||||||
|
"json": {
|
||||||
|
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
|
||||||
|
"TransactionType": "AMMDeposit",
|
||||||
|
"Asset": {"currency": "XRP"},
|
||||||
|
"Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
|
||||||
|
"Amount": "1000",
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 524288,
|
||||||
|
"Sequence": 1432289,
|
||||||
|
"SigningPubKey": "ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8",
|
||||||
|
"TxnSignature": "96CA066F42871C55088D2758D64148921B1ACAA5C6C648D0F7D675BBF47F87DF711F17C5BD172666D5AEC257520C587A849A6E063345609D91E121A78816EB04"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binary": "1200242200100000240015DAE16140000000000003E868400000000000000A6BD511C37937E080000000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C7321ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B87440FC22B16A098C236ED7EDB3EBC983026DFD218A03C8BAA848F3E1D5389D5B8B00473C1178C5BA257BFA2DCD433C414690A430A5CFD71C1C0A7F7BF725EC1759018114F92F27CC5EE2F2760278FE096D0CBE32BDD3653A0318000000000000000000000000000000000000000004180000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C",
|
||||||
|
"json": {
|
||||||
|
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
|
||||||
|
"TransactionType": "AMMDeposit",
|
||||||
|
"Asset": {"currency": "XRP"},
|
||||||
|
"Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
|
||||||
|
"Amount": "1000",
|
||||||
|
"Amount2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9", "value": "500"},
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 1048576,
|
||||||
|
"Sequence": 1432289,
|
||||||
|
"SigningPubKey": "ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8",
|
||||||
|
"TxnSignature": "FC22B16A098C236ED7EDB3EBC983026DFD218A03C8BAA848F3E1D5389D5B8B00473C1178C5BA257BFA2DCD433C414690A430A5CFD71C1C0A7F7BF725EC175901"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binary": "1200242200200000240015DAE16140000000000003E868400000000000000A6019D5438D7EA4C68000B3813FCAB4EE68B3D0D735D6849465A9113EE048B3813FCAB4EE68B3D0D735D6849465A9113EE0487321ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B87440117CF90F9B113AD3BD638B6DB63562B37C287D5180F278B3CCF58FC14A5BAEE98307EA0F6DFE19E2FBA887C92955BA5D1A04F92ADAAEB309DE89C3610D074C098114F92F27CC5EE2F2760278FE096D0CBE32BDD3653A0318000000000000000000000000000000000000000004180000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C",
|
||||||
|
"json": {
|
||||||
|
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
|
||||||
|
"TransactionType": "AMMDeposit",
|
||||||
|
"Asset": {"currency": "XRP"},
|
||||||
|
"Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
|
||||||
|
"Amount": "1000",
|
||||||
|
"LPTokenOut": {"currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048", "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg", "value": "1000"},
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 2097152,
|
||||||
|
"Sequence": 1432289,
|
||||||
|
"SigningPubKey": "ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8",
|
||||||
|
"TxnSignature": "117CF90F9B113AD3BD638B6DB63562B37C287D5180F278B3CCF58FC14A5BAEE98307EA0F6DFE19E2FBA887C92955BA5D1A04F92ADAAEB309DE89C3610D074C09"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binary": "1200242200400000240015DAE16140000000000003E868400000000000000A601B40000000000000197321ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B874405E51EBC6B52A7C3BA5D0AE2FC8F62E779B80182009B3108A87AB6D770D68F56053C193DB0640128E4765565970625B1E2878E116AC854E6DED412202CCDE0B0D8114F92F27CC5EE2F2760278FE096D0CBE32BDD3653A0318000000000000000000000000000000000000000004180000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C",
|
||||||
|
"json": {
|
||||||
|
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
|
||||||
|
"TransactionType": "AMMDeposit",
|
||||||
|
"Asset": {"currency": "XRP"},
|
||||||
|
"Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
|
||||||
|
"Amount": "1000",
|
||||||
|
"EPrice": "25",
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 4194304,
|
||||||
|
"Sequence": 1432289,
|
||||||
|
"SigningPubKey": "ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8",
|
||||||
|
"TxnSignature": "5E51EBC6B52A7C3BA5D0AE2FC8F62E779B80182009B3108A87AB6D770D68F56053C193DB0640128E4765565970625B1E2878E116AC854E6DED412202CCDE0B0D"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binary": "1200252200010000240015DAE168400000000000000A601AD5438D7EA4C68000B3813FCAB4EE68B3D0D735D6849465A9113EE048B3813FCAB4EE68B3D0D735D6849465A9113EE0487321ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B874409D4F41FC452526C0AD17191959D9B6D04A3C73B3A6C29E0F34C8459675A83A7A7D6E3021390EC8C9BE6C93E11C167E12016465E523F64F9EB3194B0A52E418028114F92F27CC5EE2F2760278FE096D0CBE32BDD3653A0318000000000000000000000000000000000000000004180000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C",
|
||||||
|
"json": {
|
||||||
|
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
|
||||||
|
"TransactionType": "AMMWithdraw",
|
||||||
|
"Asset": {"currency": "XRP"},
|
||||||
|
"Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
|
||||||
|
"LPTokenIn": {"currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048", "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg", "value": "1000"},
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 65536,
|
||||||
|
"Sequence": 1432289,
|
||||||
|
"SigningPubKey": "ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8",
|
||||||
|
"TxnSignature": "9D4F41FC452526C0AD17191959D9B6D04A3C73B3A6C29E0F34C8459675A83A7A7D6E3021390EC8C9BE6C93E11C167E12016465E523F64F9EB3194B0A52E41802"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binary": "1200252200080000240015DAE16140000000000003E868400000000000000A7321ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B87440E2C60D56C337D6D73E4B7D53579C93C666605494E82A89DD58CFDE79E2A4866BCF52370A2146877A2EF748E98168373710001133A51B645D89491849079035018114F92F27CC5EE2F2760278FE096D0CBE32BDD3653A0318000000000000000000000000000000000000000004180000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C",
|
||||||
|
"json": {
|
||||||
|
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
|
||||||
|
"TransactionType": "AMMWithdraw",
|
||||||
|
"Asset": {"currency": "XRP"},
|
||||||
|
"Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
|
||||||
|
"Amount": "1000",
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 524288,
|
||||||
|
"Sequence": 1432289,
|
||||||
|
"SigningPubKey": "ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8",
|
||||||
|
"TxnSignature": "E2C60D56C337D6D73E4B7D53579C93C666605494E82A89DD58CFDE79E2A4866BCF52370A2146877A2EF748E98168373710001133A51B645D8949184907903501"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binary": "1200252200100000240015DAE16140000000000003E868400000000000000A6BD511C37937E080000000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C7321ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B87440D2FCD7D03E53358BC6188BA88A7BA4FF2519B639C3B5C0EBCBDCB704426CA2837111430E92A6003D1CD0D81C63682C74839320539EC4F89B82AA5607714952028114F92F27CC5EE2F2760278FE096D0CBE32BDD3653A0318000000000000000000000000000000000000000004180000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C",
|
||||||
|
"json": {
|
||||||
|
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
|
||||||
|
"TransactionType": "AMMWithdraw",
|
||||||
|
"Asset": {"currency": "XRP"},
|
||||||
|
"Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
|
||||||
|
"Amount": "1000",
|
||||||
|
"Amount2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9", "value": "500"},
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 1048576,
|
||||||
|
"Sequence": 1432289,
|
||||||
|
"SigningPubKey": "ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8",
|
||||||
|
"TxnSignature": "D2FCD7D03E53358BC6188BA88A7BA4FF2519B639C3B5C0EBCBDCB704426CA2837111430E92A6003D1CD0D81C63682C74839320539EC4F89B82AA560771495202"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binary": "1200252200200000240015DAE16140000000000003E868400000000000000A601AD5438D7EA4C68000B3813FCAB4EE68B3D0D735D6849465A9113EE048B3813FCAB4EE68B3D0D735D6849465A9113EE0487321ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8744042DA5620E924E2D2059BBB4E0C4F03244140ACED93B543136FEEDF802165F814D09F45C7E2A4618468442516F4712A23B1D3332D5DBDBAE830337F39F259C90F8114F92F27CC5EE2F2760278FE096D0CBE32BDD3653A0318000000000000000000000000000000000000000004180000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C",
|
||||||
|
"json": {
|
||||||
|
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
|
||||||
|
"TransactionType": "AMMWithdraw",
|
||||||
|
"Asset": {"currency": "XRP"},
|
||||||
|
"Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
|
||||||
|
"Amount": "1000",
|
||||||
|
"LPTokenIn": {"currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048", "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg", "value": "1000"},
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 2097152,
|
||||||
|
"Sequence": 1432289,
|
||||||
|
"SigningPubKey": "ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8",
|
||||||
|
"TxnSignature": "42DA5620E924E2D2059BBB4E0C4F03244140ACED93B543136FEEDF802165F814D09F45C7E2A4618468442516F4712A23B1D3332D5DBDBAE830337F39F259C90F"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binary": "1200252200400000240015DAE16140000000000003E868400000000000000A601B40000000000000197321ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8744045BCEE5A12E5F5F1FB085A24F2F7FD962BBCB0D89A44A5319E3F7E3799E1870341880B6F684132971DDDF2E6B15356B3F407962D6D4E8DE10989F3B16E3CB90D8114F92F27CC5EE2F2760278FE096D0CBE32BDD3653A0318000000000000000000000000000000000000000004180000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C",
|
||||||
|
"json": {
|
||||||
|
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
|
||||||
|
"TransactionType": "AMMWithdraw",
|
||||||
|
"Asset": {"currency": "XRP"},
|
||||||
|
"Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
|
||||||
|
"Amount": "1000",
|
||||||
|
"EPrice": "25",
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 4194304,
|
||||||
|
"Sequence": 1432289,
|
||||||
|
"SigningPubKey": "ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8",
|
||||||
|
"TxnSignature": "45BCEE5A12E5F5F1FB085A24F2F7FD962BBCB0D89A44A5319E3F7E3799E1870341880B6F684132971DDDF2E6B15356B3F407962D6D4E8DE10989F3B16E3CB90D"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binary": "1200272200000000240015DAE168400000000000000A6CD4C8E1BC9BF04000B3813FCAB4EE68B3D0D735D6849465A9113EE048B3813FCAB4EE68B3D0D735D6849465A9113EE0486DD4CC6F3B40B6C000B3813FCAB4EE68B3D0D735D6849465A9113EE048B3813FCAB4EE68B3D0D735D6849465A9113EE0487321ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B87440F8EAAFB5EC1A69275167589969F0B9764BACE6BC8CC81482C2FC5ACCE691EDBD0D88D141137B1253BB1B9AC90A8A52CB37F5B6F7E1028B06DD06F91BE06F5A0F8114F92F27CC5EE2F2760278FE096D0CBE32BDD3653AF019E01B81149A91957F8F16BC57F3F200CD8C98375BF1791586E1F10318000000000000000000000000000000000000000004180000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C",
|
||||||
|
"json": {
|
||||||
|
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
|
||||||
|
"TransactionType": "AMMBid",
|
||||||
|
"Asset": {"currency": "XRP"},
|
||||||
|
"Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
|
||||||
|
"AuthAccounts": [{"AuthAccount": {"Account": "rEaHTti4HZsMBpxTAF4ncWxkcdqDh1h6P7"}}],
|
||||||
|
"BidMax": {"currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048", "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg", "value": "35"},
|
||||||
|
"BidMin": {"currency": "B3813FCAB4EE68B3D0D735D6849465A9113EE048", "issuer": "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg", "value": "25"},
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 0,
|
||||||
|
"Sequence": 1432289,
|
||||||
|
"SigningPubKey": "ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8",
|
||||||
|
"TxnSignature": "F8EAAFB5EC1A69275167589969F0B9764BACE6BC8CC81482C2FC5ACCE691EDBD0D88D141137B1253BB1B9AC90A8A52CB37F5B6F7E1028B06DD06F91BE06F5A0F"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binary": "1200261500EA2200000000240015DAE168400000000000000A7321ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B87440BC2F6E76969E3747E9BDE183C97573B086212F09D5387460E6EE2F32953E85EAEB9618FBBEF077276E30E59D619FCF7C7BDCDDDD9EB94D7CE1DD5CE9246B21078114F92F27CC5EE2F2760278FE096D0CBE32BDD3653A0318000000000000000000000000000000000000000004180000000000000000000000004554480000000000FBEF9A3A2B814E807745FA3D9C32FFD155FA2E8C",
|
||||||
|
"json": {
|
||||||
|
"Account": "rP5ZkB5RZQaECsSVR4DeSFK4fAw52BYtbw",
|
||||||
|
"TransactionType": "AMMVote",
|
||||||
|
"Asset": {"currency": "XRP"},
|
||||||
|
"Asset2": {"currency": "ETH", "issuer": "rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
|
||||||
|
"TradingFee": 234,
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 0,
|
||||||
|
"Sequence": 1432289,
|
||||||
|
"SigningPubKey": "ED7453D2572A2104E7B266A45888C53F503CEB1F11DC4BB3710EB2995238EC65B8",
|
||||||
|
"TxnSignature": "BC2F6E76969E3747E9BDE183C97573B086212F09D5387460E6EE2F32953E85EAEB9618FBBEF077276E30E59D619FCF7C7BDCDDDD9EB94D7CE1DD5CE9246B2107"
|
||||||
|
}
|
||||||
}],
|
}],
|
||||||
"ledgerData": [{
|
"ledgerData": [{
|
||||||
"binary": "01E91435016340767BF1C4A3EACEB081770D8ADE216C85445DD6FB002C6B5A2930F2DECE006DA18150CB18F6DD33F6F0990754C962A7CCE62F332FF9C13939B03B864117F0BDA86B6E9B4F873B5C3E520634D343EF5D9D9A4246643D64DAD278BA95DC0EAC6EB5350CF970D521276CDE21276CE60A00",
|
"binary": "01E91435016340767BF1C4A3EACEB081770D8ADE216C85445DD6FB002C6B5A2930F2DECE006DA18150CB18F6DD33F6F0990754C962A7CCE62F332FF9C13939B03B864117F0BDA86B6E9B4F873B5C3E520634D343EF5D9D9A4246643D64DAD278BA95DC0EAC6EB5350CF970D521276CDE21276CE60A00",
|
||||||
@@ -4463,4 +4670,4 @@
|
|||||||
"transaction_hash": "DD33F6F0990754C962A7CCE62F332FF9C13939B03B864117F0BDA86B6E9B4F87"
|
"transaction_hash": "DD33F6F0990754C962A7CCE62F332FF9C13939B03B864117F0BDA86B6E9B4F87"
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,6 +121,9 @@ Wallet.fromMmnemonic()
|
|||||||
* `Wallet.fromMnemonic` detects when an invalid encoding is provided, and throws an error
|
* `Wallet.fromMnemonic` detects when an invalid encoding is provided, and throws an error
|
||||||
* Made unexpected errors in `submitAndWait` more verbose to make them easier to debug.
|
* Made unexpected errors in `submitAndWait` more verbose to make them easier to debug.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* Support for Automated Market Maker (AMM) transactions and requests as defined in XLS-30.
|
||||||
|
|
||||||
## 2.3.1 (2022-06-27)
|
## 2.3.1 (2022-06-27)
|
||||||
### Fixed
|
### Fixed
|
||||||
* Signing tx with standard currency codes with lowercase and allowed symbols causing an error on decode.
|
* Signing tx with standard currency codes with lowercase and allowed symbols causing an error on decode.
|
||||||
|
|||||||
@@ -95,6 +95,9 @@ import {
|
|||||||
NFTInfoResponse,
|
NFTInfoResponse,
|
||||||
NFTHistoryRequest,
|
NFTHistoryRequest,
|
||||||
NFTHistoryResponse,
|
NFTHistoryResponse,
|
||||||
|
// AMM methods
|
||||||
|
AMMInfoRequest,
|
||||||
|
AMMInfoResponse,
|
||||||
} from '../models/methods'
|
} from '../models/methods'
|
||||||
import { BaseRequest, BaseResponse } from '../models/methods/baseMethod'
|
import { BaseRequest, BaseResponse } from '../models/methods/baseMethod'
|
||||||
import {
|
import {
|
||||||
@@ -316,6 +319,7 @@ class Client extends EventEmitter {
|
|||||||
): Promise<AccountObjectsResponse>
|
): Promise<AccountObjectsResponse>
|
||||||
public async request(r: AccountOffersRequest): Promise<AccountOffersResponse>
|
public async request(r: AccountOffersRequest): Promise<AccountOffersResponse>
|
||||||
public async request(r: AccountTxRequest): Promise<AccountTxResponse>
|
public async request(r: AccountTxRequest): Promise<AccountTxResponse>
|
||||||
|
public async request(r: AMMInfoRequest): Promise<AMMInfoResponse>
|
||||||
public async request(r: BookOffersRequest): Promise<BookOffersResponse>
|
public async request(r: BookOffersRequest): Promise<BookOffersResponse>
|
||||||
public async request(r: ChannelVerifyRequest): Promise<ChannelVerifyResponse>
|
public async request(r: ChannelVerifyRequest): Promise<ChannelVerifyResponse>
|
||||||
public async request(
|
public async request(
|
||||||
|
|||||||
@@ -141,3 +141,9 @@ export interface NFToken {
|
|||||||
nft_serial: number
|
nft_serial: number
|
||||||
uri: string
|
uri: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AuthAccount {
|
||||||
|
AuthAccount: {
|
||||||
|
account: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
78
packages/xrpl/src/models/ledger/AMM.ts
Normal file
78
packages/xrpl/src/models/ledger/AMM.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { AuthAccount, Currency } from '../common'
|
||||||
|
|
||||||
|
import BaseLedgerEntry from './BaseLedgerEntry'
|
||||||
|
|
||||||
|
export interface VoteSlot {
|
||||||
|
VoteEntry: {
|
||||||
|
Account: string
|
||||||
|
TradingFee: number
|
||||||
|
VoteWeight: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AMM object type describes a single Automated Market Maker (AMM) instance.
|
||||||
|
*
|
||||||
|
* @category Ledger Entries
|
||||||
|
*/
|
||||||
|
export default interface AMM extends BaseLedgerEntry {
|
||||||
|
LedgerEntryType: 'AMM'
|
||||||
|
/**
|
||||||
|
* The address of the special account that holds this AMM's assets.
|
||||||
|
*/
|
||||||
|
AMMAccount: string
|
||||||
|
/**
|
||||||
|
* The definition for one of the two assets this AMM holds.
|
||||||
|
*/
|
||||||
|
Asset: Currency
|
||||||
|
/**
|
||||||
|
* The definition for the other asset this AMM holds.
|
||||||
|
*/
|
||||||
|
Asset2: Currency
|
||||||
|
/**
|
||||||
|
* Details of the current owner of the auction slot.
|
||||||
|
*/
|
||||||
|
AuctionSlot?: {
|
||||||
|
/**
|
||||||
|
* The current owner of this auction slot.
|
||||||
|
*/
|
||||||
|
Account: string
|
||||||
|
/**
|
||||||
|
* A list of at most 4 additional accounts that are authorized to trade at the discounted fee for this AMM instance.
|
||||||
|
*/
|
||||||
|
AuthAccounts?: AuthAccount[]
|
||||||
|
/**
|
||||||
|
* The trading fee to be charged to the auction owner, in the same format as TradingFee.
|
||||||
|
* By default this is 0, meaning that the auction owner can trade at no fee instead of the standard fee for this AMM.
|
||||||
|
*/
|
||||||
|
DiscountedFee: number
|
||||||
|
/**
|
||||||
|
* The time when this slot expires, in seconds since the Ripple Epoch.
|
||||||
|
*/
|
||||||
|
Expiration: number
|
||||||
|
/**
|
||||||
|
* The amount the auction owner paid to win this slot, in LP Tokens.
|
||||||
|
*/
|
||||||
|
Price: Currency
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* The total outstanding balance of liquidity provider tokens from this AMM instance.
|
||||||
|
* The holders of these tokens can vote on the AMM's trading fee in proportion to their holdings,
|
||||||
|
* or redeem the tokens for a share of the AMM's assets which grows with the trading fees collected.
|
||||||
|
*/
|
||||||
|
LPTokenBalance: Currency
|
||||||
|
/**
|
||||||
|
* The percentage fee to be charged for trades against this AMM instance, in units of 1/100,000.
|
||||||
|
* The maximum value is 1000, for a 1% fee.
|
||||||
|
*/
|
||||||
|
TradingFee: number
|
||||||
|
/**
|
||||||
|
* A list of vote objects, representing votes on the pool's trading fee.
|
||||||
|
*/
|
||||||
|
VoteSlots?: VoteSlot[]
|
||||||
|
/**
|
||||||
|
* A bit-map of boolean flags. No flags are defined for the AMM object
|
||||||
|
* type, so this value is always 0.
|
||||||
|
*/
|
||||||
|
Flags: 0
|
||||||
|
}
|
||||||
@@ -126,6 +126,10 @@ export interface AccountRootFlagsInterface {
|
|||||||
* (It has DepositAuth enabled.)
|
* (It has DepositAuth enabled.)
|
||||||
*/
|
*/
|
||||||
lsfDepositAuth?: boolean
|
lsfDepositAuth?: boolean
|
||||||
|
/**
|
||||||
|
* This account is an Automated Market Maker (AMM) instance.
|
||||||
|
*/
|
||||||
|
lsfAMM?: boolean
|
||||||
/**
|
/**
|
||||||
* Disallow incoming NFTOffers from other accounts.
|
* Disallow incoming NFTOffers from other accounts.
|
||||||
*/
|
*/
|
||||||
@@ -186,6 +190,10 @@ export enum AccountRootFlags {
|
|||||||
* (It has DepositAuth enabled.)
|
* (It has DepositAuth enabled.)
|
||||||
*/
|
*/
|
||||||
lsfDepositAuth = 0x01000000,
|
lsfDepositAuth = 0x01000000,
|
||||||
|
/**
|
||||||
|
* This account is an Automated Market Maker (AMM) instance.
|
||||||
|
*/
|
||||||
|
lsfAMM = 0x02000000,
|
||||||
/**
|
/**
|
||||||
* Disallow incoming NFTOffers from other accounts.
|
* Disallow incoming NFTOffers from other accounts.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import AccountRoot from './AccountRoot'
|
import AccountRoot from './AccountRoot'
|
||||||
import Amendments from './Amendments'
|
import Amendments from './Amendments'
|
||||||
|
import AMM from './AMM'
|
||||||
import Check from './Check'
|
import Check from './Check'
|
||||||
import DepositPreauth from './DepositPreauth'
|
import DepositPreauth from './DepositPreauth'
|
||||||
import DirectoryNode from './DirectoryNode'
|
import DirectoryNode from './DirectoryNode'
|
||||||
@@ -16,6 +17,7 @@ import Ticket from './Ticket'
|
|||||||
type LedgerEntry =
|
type LedgerEntry =
|
||||||
| AccountRoot
|
| AccountRoot
|
||||||
| Amendments
|
| Amendments
|
||||||
|
| AMM
|
||||||
| Check
|
| Check
|
||||||
| DepositPreauth
|
| DepositPreauth
|
||||||
| DirectoryNode
|
| DirectoryNode
|
||||||
|
|||||||
145
packages/xrpl/src/models/methods/ammInfo.ts
Normal file
145
packages/xrpl/src/models/methods/ammInfo.ts
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
import { Amount, Currency, IssuedCurrencyAmount } from '../common'
|
||||||
|
|
||||||
|
import { BaseRequest, BaseResponse } from './baseMethod'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `amm_info` method gets information about an Automated Market Maker (AMM) instance.
|
||||||
|
* Returns an {@link AMMInfoResponse}.
|
||||||
|
*
|
||||||
|
* @category Requests
|
||||||
|
*/
|
||||||
|
export interface AMMInfoRequest extends BaseRequest {
|
||||||
|
command: 'amm_info'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One of the assets of the AMM pool to look up.
|
||||||
|
*/
|
||||||
|
asset: Currency
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The other asset of the AMM pool.
|
||||||
|
*/
|
||||||
|
asset2: Currency
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response expected from an {@link AMMInfoRequest}.
|
||||||
|
*
|
||||||
|
* @category Responses
|
||||||
|
*/
|
||||||
|
export interface AMMInfoResponse extends BaseResponse {
|
||||||
|
result: {
|
||||||
|
amm: {
|
||||||
|
/**
|
||||||
|
* The address of the AMM Account.
|
||||||
|
*/
|
||||||
|
account: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The total amount of one asset in the AMM's pool.
|
||||||
|
* (Note: This could be asset or asset2 from the request)
|
||||||
|
*/
|
||||||
|
amount: Amount
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The total amount of the other asset in the AMM's pool.
|
||||||
|
* (Note: This could be asset or asset2 from the request)
|
||||||
|
*/
|
||||||
|
amount2: Amount
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Omitted for XRP) If true, the amount currency is currently frozen for asset.
|
||||||
|
*/
|
||||||
|
asset_frozen?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Omitted for XRP) If true, the amount currency is currently frozen for asset2.
|
||||||
|
*/
|
||||||
|
asset2_frozen?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (May be omitted) An Auction Slot Object describing the current auction slot holder, if there is one.
|
||||||
|
*/
|
||||||
|
auction_slot?: {
|
||||||
|
/**
|
||||||
|
* The address of the account that owns the auction slot.
|
||||||
|
*/
|
||||||
|
account: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of additional accounts that the auction slot holder has designated as being eligible
|
||||||
|
* of the discounted trading fee.
|
||||||
|
* Each member of this array is an object with one field, account, containing the address of the designated account.
|
||||||
|
*/
|
||||||
|
auth_accounts: Array<{
|
||||||
|
account: string
|
||||||
|
}>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The discounted trading fee that applies to the auction slot holder, and any eligible accounts
|
||||||
|
* when trading against this AMM.
|
||||||
|
* This is always 0.
|
||||||
|
*/
|
||||||
|
discounted_fee: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ISO 8601 UTC timestamp after which this auction slot expires.
|
||||||
|
* After expired, the auction slot does not apply (but the data can remain in the ledger
|
||||||
|
* until another transaction replaces it or cleans it up).
|
||||||
|
*/
|
||||||
|
expiration: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount, in LP Tokens, that the auction slot holder paid to win the auction slot.
|
||||||
|
* This affects the price to outbid the current slot holder.
|
||||||
|
*/
|
||||||
|
price: Amount
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current 72-minute time interval this auction slot is in, from 0 to 19.
|
||||||
|
* The auction slot expires after 24 hours (20 intervals of 72 minutes)
|
||||||
|
* and affects the cost to outbid the current holder and how much the current holder is refunded if someone outbids them.
|
||||||
|
*/
|
||||||
|
time_interval: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The total amount of this AMM's LP Tokens outstanding.
|
||||||
|
*/
|
||||||
|
lp_token: IssuedCurrencyAmount
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AMM's current trading fee, in units of 1/100,000; a value of 1 is equivalent to a 0.001% fee.
|
||||||
|
*/
|
||||||
|
trading_fee: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (May be omitted) The current votes for the AMM's trading fee, as Vote Slot Objects.
|
||||||
|
*/
|
||||||
|
vote_slots?: Array<{
|
||||||
|
account: string
|
||||||
|
trading_fee: number
|
||||||
|
vote_weight: number
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The identifying hash of the ledger that was used to generate this
|
||||||
|
* response.
|
||||||
|
*/
|
||||||
|
ledger_hash?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ledger index of the ledger version that was used to generate this
|
||||||
|
* response.
|
||||||
|
*/
|
||||||
|
ledger_index?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If included and set to true, the information in this response comes from
|
||||||
|
* a validated ledger version. Otherwise, the information is subject to
|
||||||
|
* change.
|
||||||
|
*/
|
||||||
|
validated?: boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,6 +41,7 @@ import {
|
|||||||
AccountTxResponse,
|
AccountTxResponse,
|
||||||
AccountTxTransaction,
|
AccountTxTransaction,
|
||||||
} from './accountTx'
|
} from './accountTx'
|
||||||
|
import { AMMInfoRequest, AMMInfoResponse } from './ammInfo'
|
||||||
import {
|
import {
|
||||||
BaseRequest,
|
BaseRequest,
|
||||||
BaseResponse,
|
BaseResponse,
|
||||||
@@ -196,6 +197,8 @@ type Request =
|
|||||||
// clio only methods
|
// clio only methods
|
||||||
| NFTInfoRequest
|
| NFTInfoRequest
|
||||||
| NFTHistoryRequest
|
| NFTHistoryRequest
|
||||||
|
// AMM methods
|
||||||
|
| AMMInfoRequest
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @category Responses
|
* @category Responses
|
||||||
@@ -247,6 +250,8 @@ type Response =
|
|||||||
// clio only methods
|
// clio only methods
|
||||||
| NFTInfoResponse
|
| NFTInfoResponse
|
||||||
| NFTHistoryResponse
|
| NFTHistoryResponse
|
||||||
|
// AMM methods
|
||||||
|
| AMMInfoResponse
|
||||||
|
|
||||||
export {
|
export {
|
||||||
// Allow users to define their own requests and responses. This is useful for releasing experimental versions
|
// Allow users to define their own requests and responses. This is useful for releasing experimental versions
|
||||||
@@ -380,4 +385,7 @@ export {
|
|||||||
NFTHistoryRequest,
|
NFTHistoryRequest,
|
||||||
NFTHistoryResponse,
|
NFTHistoryResponse,
|
||||||
NFTHistoryTransaction,
|
NFTHistoryTransaction,
|
||||||
|
// AMM methods
|
||||||
|
AMMInfoRequest,
|
||||||
|
AMMInfoResponse,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,21 @@ import { BaseRequest, BaseResponse, LookupByLedgerRequest } from './baseMethod'
|
|||||||
*/
|
*/
|
||||||
export interface LedgerEntryRequest extends BaseRequest, LookupByLedgerRequest {
|
export interface LedgerEntryRequest extends BaseRequest, LookupByLedgerRequest {
|
||||||
command: 'ledger_entry'
|
command: 'ledger_entry'
|
||||||
|
/**
|
||||||
|
* Retrieve an Automated Market Maker (AMM) object from the ledger.
|
||||||
|
* This is similar to amm_info method, but the ledger_entry version returns only the ledger entry as stored.
|
||||||
|
*/
|
||||||
|
amm?: {
|
||||||
|
asset: {
|
||||||
|
currency: string
|
||||||
|
issuer?: string
|
||||||
|
}
|
||||||
|
asset2: {
|
||||||
|
currency: string
|
||||||
|
issuer?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If true, return the requested ledger object's contents as a hex string in
|
* If true, return the requested ledger object's contents as a hex string in
|
||||||
* the XRP Ledger's binary format. Otherwise, return data in JSON format. The
|
* the XRP Ledger's binary format. Otherwise, return data in JSON format. The
|
||||||
|
|||||||
140
packages/xrpl/src/models/transactions/AMMBid.ts
Normal file
140
packages/xrpl/src/models/transactions/AMMBid.ts
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
/* eslint-disable complexity -- required for validateAMMBid */
|
||||||
|
import { ValidationError } from '../../errors'
|
||||||
|
import { Amount, AuthAccount, Currency } from '../common'
|
||||||
|
|
||||||
|
import {
|
||||||
|
BaseTransaction,
|
||||||
|
isAmount,
|
||||||
|
isCurrency,
|
||||||
|
validateBaseTransaction,
|
||||||
|
} from './common'
|
||||||
|
|
||||||
|
const MAX_AUTH_ACCOUNTS = 4
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bid on an Automated Market Maker's (AMM's) auction slot.
|
||||||
|
*
|
||||||
|
* If you win, you can trade against the AMM at a discounted fee until you are outbid or 24 hours have passed.
|
||||||
|
* If you are outbid before 24 hours have passed, you are refunded part of the cost of your bid based on how much time remains.
|
||||||
|
* You bid using the AMM's LP Tokens; the amount of a winning bid is returned to the AMM,
|
||||||
|
* decreasing the outstanding balance of LP Tokens.
|
||||||
|
*/
|
||||||
|
export interface AMMBid extends BaseTransaction {
|
||||||
|
TransactionType: 'AMMBid'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The definition for one of the assets in the AMM's pool.
|
||||||
|
*/
|
||||||
|
Asset: Currency
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The definition for the other asset in the AMM's pool.
|
||||||
|
*/
|
||||||
|
Asset2: Currency
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pay at least this amount for the slot.
|
||||||
|
* Setting this value higher makes it harder for others to outbid you.
|
||||||
|
* If omitted, pay the minimum necessary to win the bid.
|
||||||
|
*/
|
||||||
|
BidMin?: Amount
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pay at most this amount for the slot.
|
||||||
|
* If the cost to win the bid is higher than this amount, the transaction fails.
|
||||||
|
* If omitted, pay as much as necessary to win the bid.
|
||||||
|
*/
|
||||||
|
BidMax?: Amount
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of up to 4 additional accounts that you allow to trade at the discounted fee.
|
||||||
|
* This cannot include the address of the transaction sender.
|
||||||
|
*/
|
||||||
|
AuthAccounts?: AuthAccount[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the form and type of an AMMBid at runtime.
|
||||||
|
*
|
||||||
|
* @param tx - An AMMBid Transaction.
|
||||||
|
* @throws When the AMMBid is Malformed.
|
||||||
|
*/
|
||||||
|
export function validateAMMBid(tx: Record<string, unknown>): void {
|
||||||
|
validateBaseTransaction(tx)
|
||||||
|
|
||||||
|
if (tx.Asset == null) {
|
||||||
|
throw new ValidationError('AMMBid: missing field Asset')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCurrency(tx.Asset)) {
|
||||||
|
throw new ValidationError('AMMBid: Asset must be a Currency')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.Asset2 == null) {
|
||||||
|
throw new ValidationError('AMMBid: missing field Asset2')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCurrency(tx.Asset2)) {
|
||||||
|
throw new ValidationError('AMMBid: Asset2 must be a Currency')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.BidMin != null && !isAmount(tx.BidMin)) {
|
||||||
|
throw new ValidationError('AMMBid: BidMin must be an Amount')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.BidMax != null && !isAmount(tx.BidMax)) {
|
||||||
|
throw new ValidationError('AMMBid: BidMax must be an Amount')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.AuthAccounts != null) {
|
||||||
|
if (!Array.isArray(tx.AuthAccounts)) {
|
||||||
|
throw new ValidationError(
|
||||||
|
`AMMBid: AuthAccounts must be an AuthAccount array`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (tx.AuthAccounts.length > MAX_AUTH_ACCOUNTS) {
|
||||||
|
throw new ValidationError(
|
||||||
|
`AMMBid: AuthAccounts length must not be greater than ${MAX_AUTH_ACCOUNTS}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
validateAuthAccounts(
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Only used by JS
|
||||||
|
tx.Account as string,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Only used by JS
|
||||||
|
tx.AuthAccounts as Array<Record<string, unknown>>,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateAuthAccounts(
|
||||||
|
senderAddress: string,
|
||||||
|
authAccounts: Array<Record<string, unknown>>,
|
||||||
|
): boolean {
|
||||||
|
for (const authAccount of authAccounts) {
|
||||||
|
if (
|
||||||
|
authAccount.AuthAccount == null ||
|
||||||
|
typeof authAccount.AuthAccount !== 'object'
|
||||||
|
) {
|
||||||
|
throw new ValidationError(`AMMBid: invalid AuthAccounts`)
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- used for null check
|
||||||
|
// @ts-expect-error -- used for null check
|
||||||
|
if (authAccount.AuthAccount.Account == null) {
|
||||||
|
throw new ValidationError(`AMMBid: invalid AuthAccounts`)
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- used for null check
|
||||||
|
// @ts-expect-error -- used for null check
|
||||||
|
if (typeof authAccount.AuthAccount.Account !== 'string') {
|
||||||
|
throw new ValidationError(`AMMBid: invalid AuthAccounts`)
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- used for null check
|
||||||
|
// @ts-expect-error -- used for null check
|
||||||
|
if (authAccount.AuthAccount.Account === senderAddress) {
|
||||||
|
throw new ValidationError(
|
||||||
|
`AMMBid: AuthAccounts must not include sender's address`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
80
packages/xrpl/src/models/transactions/AMMCreate.ts
Normal file
80
packages/xrpl/src/models/transactions/AMMCreate.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import { ValidationError } from '../../errors'
|
||||||
|
import { Amount } from '../common'
|
||||||
|
|
||||||
|
import { BaseTransaction, isAmount, validateBaseTransaction } from './common'
|
||||||
|
|
||||||
|
export const AMM_MAX_TRADING_FEE = 1000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Automated Market Maker (AMM) instance for trading a pair of assets (fungible tokens or XRP).
|
||||||
|
*
|
||||||
|
* Creates both an AMM object and a special AccountRoot object to represent the AMM.
|
||||||
|
* Also transfers ownership of the starting balance of both assets from the sender to the created AccountRoot
|
||||||
|
* and issues an initial balance of liquidity provider tokens (LP Tokens) from the AMM account to the sender.
|
||||||
|
*
|
||||||
|
* CAUTION: When you create the AMM, you should fund it with (approximately) equal-value amounts of each asset.
|
||||||
|
* Otherwise, other users can profit at your expense by trading with this AMM (performing arbitrage).
|
||||||
|
* The currency risk that liquidity providers take on increases with the volatility (potential for imbalance) of the asset pair.
|
||||||
|
* The higher the trading fee, the more it offsets this risk,
|
||||||
|
* so it's best to set the trading fee based on the volatility of the asset pair.
|
||||||
|
*/
|
||||||
|
export interface AMMCreate extends BaseTransaction {
|
||||||
|
TransactionType: 'AMMCreate'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first of the two assets to fund this AMM with. This must be a positive amount.
|
||||||
|
*/
|
||||||
|
Amount: Amount
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The second of the two assets to fund this AMM with. This must be a positive amount.
|
||||||
|
*/
|
||||||
|
Amount2: Amount
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fee to charge for trades against this AMM instance, in units of 1/100,000; a value of 1 is equivalent to 0.001%.
|
||||||
|
* The maximum value is 1000, indicating a 1% fee.
|
||||||
|
* The minimum value is 0.
|
||||||
|
*/
|
||||||
|
TradingFee: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the form and type of an AMMCreate at runtime.
|
||||||
|
*
|
||||||
|
* @param tx - An AMMCreate Transaction.
|
||||||
|
* @throws When the AMMCreate is Malformed.
|
||||||
|
*/
|
||||||
|
export function validateAMMCreate(tx: Record<string, unknown>): void {
|
||||||
|
validateBaseTransaction(tx)
|
||||||
|
|
||||||
|
if (tx.Amount == null) {
|
||||||
|
throw new ValidationError('AMMCreate: missing field Amount')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isAmount(tx.Amount)) {
|
||||||
|
throw new ValidationError('AMMCreate: Amount must be an Amount')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.Amount2 == null) {
|
||||||
|
throw new ValidationError('AMMCreate: missing field Amount2')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isAmount(tx.Amount2)) {
|
||||||
|
throw new ValidationError('AMMCreate: Amount2 must be an Amount')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.TradingFee == null) {
|
||||||
|
throw new ValidationError('AMMCreate: missing field TradingFee')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof tx.TradingFee !== 'number') {
|
||||||
|
throw new ValidationError('AMMCreate: TradingFee must be a number')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.TradingFee < 0 || tx.TradingFee > AMM_MAX_TRADING_FEE) {
|
||||||
|
throw new ValidationError(
|
||||||
|
`AMMCreate: TradingFee must be between 0 and ${AMM_MAX_TRADING_FEE}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
55
packages/xrpl/src/models/transactions/AMMDelete.ts
Normal file
55
packages/xrpl/src/models/transactions/AMMDelete.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { ValidationError } from '../../errors'
|
||||||
|
import { Currency } from '../common'
|
||||||
|
|
||||||
|
import { BaseTransaction, isCurrency, validateBaseTransaction } from './common'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an empty Automated Market Maker (AMM) instance that could not be fully deleted automatically.
|
||||||
|
*
|
||||||
|
* Tip: The AMMWithdraw transaction automatically tries to delete an AMM, along with associated ledger
|
||||||
|
* entries such as empty trust lines, if it withdrew all the assets from the AMM's pool.
|
||||||
|
* However, if there are too many trust lines to the AMM account to remove in one transaction,
|
||||||
|
* it may stop before fully removing the AMM. Similarly, an AMMDelete transaction removes up to
|
||||||
|
* a maximum number of trust lines; in extreme cases, it may take several AMMDelete transactions
|
||||||
|
* to fully delete the trust lines and the associated AMM.
|
||||||
|
* In all cases, the AMM ledger entry and AMM account are deleted by the last such transaction.
|
||||||
|
*/
|
||||||
|
export interface AMMDelete extends BaseTransaction {
|
||||||
|
TransactionType: 'AMMDelete'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The definition for one of the assets in the AMM's pool.
|
||||||
|
*/
|
||||||
|
Asset: Currency
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The definition for the other asset in the AMM's pool.
|
||||||
|
*/
|
||||||
|
Asset2: Currency
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the form and type of an AMMDelete at runtime.
|
||||||
|
*
|
||||||
|
* @param tx - An AMMDelete Transaction.
|
||||||
|
* @throws When the AMMDelete is Malformed.
|
||||||
|
*/
|
||||||
|
export function validateAMMDelete(tx: Record<string, unknown>): void {
|
||||||
|
validateBaseTransaction(tx)
|
||||||
|
|
||||||
|
if (tx.Asset == null) {
|
||||||
|
throw new ValidationError('AMMDelete: missing field Asset')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCurrency(tx.Asset)) {
|
||||||
|
throw new ValidationError('AMMDelete: Asset must be a Currency')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.Asset2 == null) {
|
||||||
|
throw new ValidationError('AMMDelete: missing field Asset2')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCurrency(tx.Asset2)) {
|
||||||
|
throw new ValidationError('AMMDelete: Asset2 must be a Currency')
|
||||||
|
}
|
||||||
|
}
|
||||||
130
packages/xrpl/src/models/transactions/AMMDeposit.ts
Normal file
130
packages/xrpl/src/models/transactions/AMMDeposit.ts
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
/* eslint-disable complexity -- required for validateAMMDeposit */
|
||||||
|
import { ValidationError } from '../../errors'
|
||||||
|
import { Amount, Currency, IssuedCurrencyAmount } from '../common'
|
||||||
|
|
||||||
|
import {
|
||||||
|
BaseTransaction,
|
||||||
|
GlobalFlags,
|
||||||
|
isAmount,
|
||||||
|
isCurrency,
|
||||||
|
isIssuedCurrency,
|
||||||
|
validateBaseTransaction,
|
||||||
|
} from './common'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representing values for AMMDeposit Transaction Flags.
|
||||||
|
*
|
||||||
|
* @category Transaction Flags
|
||||||
|
*/
|
||||||
|
export enum AMMDepositFlags {
|
||||||
|
tfLPToken = 0x00010000,
|
||||||
|
tfSingleAsset = 0x00080000,
|
||||||
|
tfTwoAsset = 0x00100000,
|
||||||
|
tfOneAssetLPToken = 0x00200000,
|
||||||
|
tfLimitLPToken = 0x00400000,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AMMDepositFlagsInterface extends GlobalFlags {
|
||||||
|
tfLPToken?: boolean
|
||||||
|
tfSingleAsset?: boolean
|
||||||
|
tfTwoAsset?: boolean
|
||||||
|
tfOneAssetLPToken?: boolean
|
||||||
|
tfLimitLPToken?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deposit funds into an Automated Market Maker (AMM) instance
|
||||||
|
* and receive the AMM's liquidity provider tokens (LP Tokens) in exchange.
|
||||||
|
*
|
||||||
|
* You can deposit one or both of the assets in the AMM's pool.
|
||||||
|
* If successful, this transaction creates a trust line to the AMM Account (limit 0) to hold the LP Tokens.
|
||||||
|
*/
|
||||||
|
export interface AMMDeposit extends BaseTransaction {
|
||||||
|
TransactionType: 'AMMDeposit'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The definition for one of the assets in the AMM's pool.
|
||||||
|
*/
|
||||||
|
Asset: Currency
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The definition for the other asset in the AMM's pool.
|
||||||
|
*/
|
||||||
|
Asset2: Currency
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of one asset to deposit to the AMM.
|
||||||
|
* If present, this must match the type of one of the assets (tokens or XRP) in the AMM's pool.
|
||||||
|
*/
|
||||||
|
Amount?: Amount
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of another asset to add to the AMM.
|
||||||
|
* If present, this must match the type of the other asset in the AMM's pool and cannot be the same asset as Amount.
|
||||||
|
*/
|
||||||
|
Amount2?: Amount
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum effective price, in the deposit asset, to pay for each LP Token received.
|
||||||
|
*/
|
||||||
|
EPrice?: Amount
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How many of the AMM's LP Tokens to buy.
|
||||||
|
*/
|
||||||
|
LPTokenOut?: IssuedCurrencyAmount
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the form and type of an AMMDeposit at runtime.
|
||||||
|
*
|
||||||
|
* @param tx - An AMMDeposit Transaction.
|
||||||
|
* @throws When the AMMDeposit is Malformed.
|
||||||
|
*/
|
||||||
|
export function validateAMMDeposit(tx: Record<string, unknown>): void {
|
||||||
|
validateBaseTransaction(tx)
|
||||||
|
|
||||||
|
if (tx.Asset == null) {
|
||||||
|
throw new ValidationError('AMMDeposit: missing field Asset')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCurrency(tx.Asset)) {
|
||||||
|
throw new ValidationError('AMMDeposit: Asset must be a Currency')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.Asset2 == null) {
|
||||||
|
throw new ValidationError('AMMDeposit: missing field Asset2')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCurrency(tx.Asset2)) {
|
||||||
|
throw new ValidationError('AMMDeposit: Asset2 must be a Currency')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.Amount2 != null && tx.Amount == null) {
|
||||||
|
throw new ValidationError('AMMDeposit: must set Amount with Amount2')
|
||||||
|
} else if (tx.EPrice != null && tx.Amount == null) {
|
||||||
|
throw new ValidationError('AMMDeposit: must set Amount with EPrice')
|
||||||
|
} else if (tx.LPTokenOut == null && tx.Amount == null) {
|
||||||
|
throw new ValidationError(
|
||||||
|
'AMMDeposit: must set at least LPTokenOut or Amount',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.LPTokenOut != null && !isIssuedCurrency(tx.LPTokenOut)) {
|
||||||
|
throw new ValidationError(
|
||||||
|
'AMMDeposit: LPTokenOut must be an IssuedCurrencyAmount',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.Amount != null && !isAmount(tx.Amount)) {
|
||||||
|
throw new ValidationError('AMMDeposit: Amount must be an Amount')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.Amount2 != null && !isAmount(tx.Amount2)) {
|
||||||
|
throw new ValidationError('AMMDeposit: Amount2 must be an Amount')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.EPrice != null && !isAmount(tx.EPrice)) {
|
||||||
|
throw new ValidationError('AMMDeposit: EPrice must be an Amount')
|
||||||
|
}
|
||||||
|
}
|
||||||
71
packages/xrpl/src/models/transactions/AMMVote.ts
Normal file
71
packages/xrpl/src/models/transactions/AMMVote.ts
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { ValidationError } from '../../errors'
|
||||||
|
import { Currency } from '../common'
|
||||||
|
|
||||||
|
import { AMM_MAX_TRADING_FEE } from './AMMCreate'
|
||||||
|
import { BaseTransaction, isCurrency, validateBaseTransaction } from './common'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vote on the trading fee for an Automated Market Maker (AMM) instance.
|
||||||
|
*
|
||||||
|
* Up to 8 accounts can vote in proportion to the amount of the AMM's LP Tokens they hold.
|
||||||
|
* Each new vote re-calculates the AMM's trading fee based on a weighted average of the votes.
|
||||||
|
*/
|
||||||
|
export interface AMMVote extends BaseTransaction {
|
||||||
|
TransactionType: 'AMMVote'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The definition for one of the assets in the AMM's pool.
|
||||||
|
*/
|
||||||
|
Asset: Currency
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The definition for the other asset in the AMM's pool.
|
||||||
|
*/
|
||||||
|
Asset2: Currency
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The proposed fee to vote for, in units of 1/100,000; a value of 1 is equivalent to 0.001%.
|
||||||
|
* The maximum value is 1000, indicating a 1% fee.
|
||||||
|
*/
|
||||||
|
TradingFee: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the form and type of an AMMVote at runtime.
|
||||||
|
*
|
||||||
|
* @param tx - An AMMVote Transaction.
|
||||||
|
* @throws When the AMMVote is Malformed.
|
||||||
|
*/
|
||||||
|
export function validateAMMVote(tx: Record<string, unknown>): void {
|
||||||
|
validateBaseTransaction(tx)
|
||||||
|
|
||||||
|
if (tx.Asset == null) {
|
||||||
|
throw new ValidationError('AMMVote: missing field Asset')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCurrency(tx.Asset)) {
|
||||||
|
throw new ValidationError('AMMVote: Asset must be a Currency')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.Asset2 == null) {
|
||||||
|
throw new ValidationError('AMMVote: missing field Asset2')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCurrency(tx.Asset2)) {
|
||||||
|
throw new ValidationError('AMMVote: Asset2 must be a Currency')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.TradingFee == null) {
|
||||||
|
throw new ValidationError('AMMVote: missing field TradingFee')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof tx.TradingFee !== 'number') {
|
||||||
|
throw new ValidationError('AMMVote: TradingFee must be a number')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.TradingFee < 0 || tx.TradingFee > AMM_MAX_TRADING_FEE) {
|
||||||
|
throw new ValidationError(
|
||||||
|
`AMMVote: TradingFee must be between 0 and ${AMM_MAX_TRADING_FEE}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
126
packages/xrpl/src/models/transactions/AMMWithdraw.ts
Normal file
126
packages/xrpl/src/models/transactions/AMMWithdraw.ts
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
/* eslint-disable complexity -- required for validateAMMWithdraw */
|
||||||
|
import { ValidationError } from '../../errors'
|
||||||
|
import { Amount, Currency, IssuedCurrencyAmount } from '../common'
|
||||||
|
|
||||||
|
import {
|
||||||
|
BaseTransaction,
|
||||||
|
GlobalFlags,
|
||||||
|
isAmount,
|
||||||
|
isCurrency,
|
||||||
|
isIssuedCurrency,
|
||||||
|
validateBaseTransaction,
|
||||||
|
} from './common'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representing values for AMMWithdrawFlags Transaction Flags.
|
||||||
|
*
|
||||||
|
* @category Transaction Flags
|
||||||
|
*/
|
||||||
|
export enum AMMWithdrawFlags {
|
||||||
|
tfLPToken = 0x00010000,
|
||||||
|
tfWithdrawAll = 0x00020000,
|
||||||
|
tfOneAssetWithdrawAll = 0x00040000,
|
||||||
|
tfSingleAsset = 0x00080000,
|
||||||
|
tfTwoAsset = 0x00100000,
|
||||||
|
tfOneAssetLPToken = 0x00200000,
|
||||||
|
tfLimitLPToken = 0x00400000,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AMMWithdrawFlagsInterface extends GlobalFlags {
|
||||||
|
tfLPToken?: boolean
|
||||||
|
tfWithdrawAll?: boolean
|
||||||
|
tfOneAssetWithdrawAll?: boolean
|
||||||
|
tfSingleAsset?: boolean
|
||||||
|
tfTwoAsset?: boolean
|
||||||
|
tfOneAssetLPToken?: boolean
|
||||||
|
tfLimitLPToken?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Withdraw assets from an Automated Market Maker (AMM) instance by returning the AMM's liquidity provider tokens (LP Tokens).
|
||||||
|
*/
|
||||||
|
export interface AMMWithdraw extends BaseTransaction {
|
||||||
|
TransactionType: 'AMMWithdraw'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The definition for one of the assets in the AMM's pool.
|
||||||
|
*/
|
||||||
|
Asset: Currency
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The definition for the other asset in the AMM's pool.
|
||||||
|
*/
|
||||||
|
Asset2: Currency
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of one asset to withdraw from the AMM.
|
||||||
|
* This must match the type of one of the assets (tokens or XRP) in the AMM's pool.
|
||||||
|
*/
|
||||||
|
Amount?: Amount
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of another asset to withdraw from the AMM.
|
||||||
|
* If present, this must match the type of the other asset in the AMM's pool and cannot be the same type as Amount.
|
||||||
|
*/
|
||||||
|
Amount2?: Amount
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum effective price, in LP Token returned, to pay per unit of the asset to withdraw.
|
||||||
|
*/
|
||||||
|
EPrice?: Amount
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How many of the AMM's LP Tokens to redeem.
|
||||||
|
*/
|
||||||
|
LPTokenIn?: IssuedCurrencyAmount
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the form and type of an AMMWithdraw at runtime.
|
||||||
|
*
|
||||||
|
* @param tx - An AMMWithdraw Transaction.
|
||||||
|
* @throws When the AMMWithdraw is Malformed.
|
||||||
|
*/
|
||||||
|
export function validateAMMWithdraw(tx: Record<string, unknown>): void {
|
||||||
|
validateBaseTransaction(tx)
|
||||||
|
|
||||||
|
if (tx.Asset == null) {
|
||||||
|
throw new ValidationError('AMMWithdraw: missing field Asset')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCurrency(tx.Asset)) {
|
||||||
|
throw new ValidationError('AMMWithdraw: Asset must be a Currency')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.Asset2 == null) {
|
||||||
|
throw new ValidationError('AMMWithdraw: missing field Asset2')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCurrency(tx.Asset2)) {
|
||||||
|
throw new ValidationError('AMMWithdraw: Asset2 must be a Currency')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.Amount2 != null && tx.Amount == null) {
|
||||||
|
throw new ValidationError('AMMWithdraw: must set Amount with Amount2')
|
||||||
|
} else if (tx.EPrice != null && tx.Amount == null) {
|
||||||
|
throw new ValidationError('AMMWithdraw: must set Amount with EPrice')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.LPTokenIn != null && !isIssuedCurrency(tx.LPTokenIn)) {
|
||||||
|
throw new ValidationError(
|
||||||
|
'AMMWithdraw: LPTokenIn must be an IssuedCurrencyAmount',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.Amount != null && !isAmount(tx.Amount)) {
|
||||||
|
throw new ValidationError('AMMWithdraw: Amount must be an Amount')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.Amount2 != null && !isAmount(tx.Amount2)) {
|
||||||
|
throw new ValidationError('AMMWithdraw: Amount2 must be an Amount')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.EPrice != null && !isAmount(tx.EPrice)) {
|
||||||
|
throw new ValidationError('AMMWithdraw: EPrice must be an Amount')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
import { TRANSACTION_TYPES } from 'ripple-binary-codec'
|
import { TRANSACTION_TYPES } from 'ripple-binary-codec'
|
||||||
|
|
||||||
import { ValidationError } from '../../errors'
|
import { ValidationError } from '../../errors'
|
||||||
import { Amount, IssuedCurrencyAmount, Memo, Signer } from '../common'
|
import { Amount, Currency, IssuedCurrencyAmount, Memo, Signer } from '../common'
|
||||||
import { onlyHasFields } from '../utils'
|
import { onlyHasFields } from '../utils'
|
||||||
|
|
||||||
const MEMO_SIZE = 3
|
const MEMO_SIZE = 3
|
||||||
@@ -50,17 +50,36 @@ function isSigner(obj: unknown): boolean {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const XRP_CURRENCY_SIZE = 1
|
||||||
|
const ISSUE_SIZE = 2
|
||||||
const ISSUED_CURRENCY_SIZE = 3
|
const ISSUED_CURRENCY_SIZE = 3
|
||||||
|
|
||||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||||
return value !== null && typeof value === 'object'
|
return value !== null && typeof value === 'object'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the form and type of an IssuedCurrency at runtime.
|
||||||
|
*
|
||||||
|
* @param input - The input to check the form and type of.
|
||||||
|
* @returns Whether the IssuedCurrency is properly formed.
|
||||||
|
*/
|
||||||
|
export function isCurrency(input: unknown): input is Currency {
|
||||||
|
return (
|
||||||
|
isRecord(input) &&
|
||||||
|
((Object.keys(input).length === ISSUE_SIZE &&
|
||||||
|
typeof input.issuer === 'string' &&
|
||||||
|
typeof input.currency === 'string') ||
|
||||||
|
(Object.keys(input).length === XRP_CURRENCY_SIZE &&
|
||||||
|
input.currency === 'XRP'))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify the form and type of an IssuedCurrencyAmount at runtime.
|
* Verify the form and type of an IssuedCurrencyAmount at runtime.
|
||||||
*
|
*
|
||||||
* @param input - The input to check the form and type of.
|
* @param input - The input to check the form and type of.
|
||||||
* @returns Whether the IssuedCurrencyAmount is malformed.
|
* @returns Whether the IssuedCurrencyAmount is properly formed.
|
||||||
*/
|
*/
|
||||||
export function isIssuedCurrency(
|
export function isIssuedCurrency(
|
||||||
input: unknown,
|
input: unknown,
|
||||||
@@ -78,7 +97,7 @@ export function isIssuedCurrency(
|
|||||||
* Verify the form and type of an Amount at runtime.
|
* Verify the form and type of an Amount at runtime.
|
||||||
*
|
*
|
||||||
* @param amount - The object to check the form and type of.
|
* @param amount - The object to check the form and type of.
|
||||||
* @returns Whether the Amount is malformed.
|
* @returns Whether the Amount is properly formed.
|
||||||
*/
|
*/
|
||||||
export function isAmount(amount: unknown): amount is Amount {
|
export function isAmount(amount: unknown): amount is Amount {
|
||||||
return typeof amount === 'string' || isIssuedCurrency(amount)
|
return typeof amount === 'string' || isIssuedCurrency(amount)
|
||||||
|
|||||||
@@ -8,6 +8,20 @@ export {
|
|||||||
AccountSet,
|
AccountSet,
|
||||||
} from './accountSet'
|
} from './accountSet'
|
||||||
export { AccountDelete } from './accountDelete'
|
export { AccountDelete } from './accountDelete'
|
||||||
|
export { AMMBid } from './AMMBid'
|
||||||
|
export { AMMDelete } from './AMMDelete'
|
||||||
|
export {
|
||||||
|
AMMDepositFlags,
|
||||||
|
AMMDepositFlagsInterface,
|
||||||
|
AMMDeposit,
|
||||||
|
} from './AMMDeposit'
|
||||||
|
export { AMMCreate } from './AMMCreate'
|
||||||
|
export { AMMVote } from './AMMVote'
|
||||||
|
export {
|
||||||
|
AMMWithdrawFlags,
|
||||||
|
AMMWithdrawFlagsInterface,
|
||||||
|
AMMWithdraw,
|
||||||
|
} from './AMMWithdraw'
|
||||||
export { CheckCancel } from './checkCancel'
|
export { CheckCancel } from './checkCancel'
|
||||||
export { CheckCash } from './checkCash'
|
export { CheckCash } from './checkCash'
|
||||||
export { CheckCreate } from './checkCreate'
|
export { CheckCreate } from './checkCreate'
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ import { setTransactionFlagsToNumber } from '../utils/flags'
|
|||||||
|
|
||||||
import { AccountDelete, validateAccountDelete } from './accountDelete'
|
import { AccountDelete, validateAccountDelete } from './accountDelete'
|
||||||
import { AccountSet, validateAccountSet } from './accountSet'
|
import { AccountSet, validateAccountSet } from './accountSet'
|
||||||
|
import { AMMBid, validateAMMBid } from './AMMBid'
|
||||||
|
import { AMMCreate, validateAMMCreate } from './AMMCreate'
|
||||||
|
import { AMMDelete, validateAMMDelete } from './AMMDelete'
|
||||||
|
import { AMMDeposit, validateAMMDeposit } from './AMMDeposit'
|
||||||
|
import { AMMVote, validateAMMVote } from './AMMVote'
|
||||||
|
import { AMMWithdraw, validateAMMWithdraw } from './AMMWithdraw'
|
||||||
import { CheckCancel, validateCheckCancel } from './checkCancel'
|
import { CheckCancel, validateCheckCancel } from './checkCancel'
|
||||||
import { CheckCash, validateCheckCash } from './checkCash'
|
import { CheckCash, validateCheckCash } from './checkCash'
|
||||||
import { CheckCreate, validateCheckCreate } from './checkCreate'
|
import { CheckCreate, validateCheckCreate } from './checkCreate'
|
||||||
@@ -58,6 +64,12 @@ import { TrustSet, validateTrustSet } from './trustSet'
|
|||||||
export type Transaction =
|
export type Transaction =
|
||||||
| AccountDelete
|
| AccountDelete
|
||||||
| AccountSet
|
| AccountSet
|
||||||
|
| AMMBid
|
||||||
|
| AMMDelete
|
||||||
|
| AMMDeposit
|
||||||
|
| AMMCreate
|
||||||
|
| AMMVote
|
||||||
|
| AMMWithdraw
|
||||||
| CheckCancel
|
| CheckCancel
|
||||||
| CheckCash
|
| CheckCash
|
||||||
| CheckCreate
|
| CheckCreate
|
||||||
@@ -167,6 +179,30 @@ export function validate(transaction: Record<string, unknown>): void {
|
|||||||
validateAccountSet(tx)
|
validateAccountSet(tx)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
case 'AMMBid':
|
||||||
|
validateAMMBid(tx)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'AMMDelete':
|
||||||
|
validateAMMDelete(tx)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'AMMDeposit':
|
||||||
|
validateAMMDeposit(tx)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'AMMCreate':
|
||||||
|
validateAMMCreate(tx)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'AMMVote':
|
||||||
|
validateAMMVote(tx)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'AMMWithdraw':
|
||||||
|
validateAMMWithdraw(tx)
|
||||||
|
break
|
||||||
|
|
||||||
case 'CheckCancel':
|
case 'CheckCancel':
|
||||||
validateCheckCancel(tx)
|
validateCheckCancel(tx)
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -6,22 +6,15 @@ import {
|
|||||||
AccountRootFlagsInterface,
|
AccountRootFlagsInterface,
|
||||||
AccountRootFlags,
|
AccountRootFlags,
|
||||||
} from '../ledger/AccountRoot'
|
} from '../ledger/AccountRoot'
|
||||||
import {
|
import { AccountSetTfFlags } from '../transactions/accountSet'
|
||||||
AccountSetFlagsInterface,
|
import { AMMDepositFlags } from '../transactions/AMMDeposit'
|
||||||
AccountSetTfFlags,
|
import { AMMWithdrawFlags } from '../transactions/AMMWithdraw'
|
||||||
} from '../transactions/accountSet'
|
|
||||||
import { GlobalFlags } from '../transactions/common'
|
import { GlobalFlags } from '../transactions/common'
|
||||||
import {
|
import { OfferCreateFlags } from '../transactions/offerCreate'
|
||||||
OfferCreateFlagsInterface,
|
import { PaymentFlags } from '../transactions/payment'
|
||||||
OfferCreateFlags,
|
import { PaymentChannelClaimFlags } from '../transactions/paymentChannelClaim'
|
||||||
} from '../transactions/offerCreate'
|
|
||||||
import { PaymentFlagsInterface, PaymentFlags } from '../transactions/payment'
|
|
||||||
import {
|
|
||||||
PaymentChannelClaimFlagsInterface,
|
|
||||||
PaymentChannelClaimFlags,
|
|
||||||
} from '../transactions/paymentChannelClaim'
|
|
||||||
import type { Transaction } from '../transactions/transaction'
|
import type { Transaction } from '../transactions/transaction'
|
||||||
import { TrustSetFlagsInterface, TrustSetFlags } from '../transactions/trustSet'
|
import { TrustSetFlags } from '../transactions/trustSet'
|
||||||
|
|
||||||
import { isFlagEnabled } from '.'
|
import { isFlagEnabled } from '.'
|
||||||
|
|
||||||
@@ -65,55 +58,33 @@ export function setTransactionFlagsToNumber(tx: Transaction): void {
|
|||||||
|
|
||||||
switch (tx.TransactionType) {
|
switch (tx.TransactionType) {
|
||||||
case 'AccountSet':
|
case 'AccountSet':
|
||||||
tx.Flags = convertAccountSetFlagsToNumber(tx.Flags)
|
tx.Flags = convertFlagsToNumber(tx.Flags, AccountSetTfFlags)
|
||||||
|
return
|
||||||
|
case 'AMMDeposit':
|
||||||
|
tx.Flags = convertFlagsToNumber(tx.Flags, AMMDepositFlags)
|
||||||
|
return
|
||||||
|
case 'AMMWithdraw':
|
||||||
|
tx.Flags = convertFlagsToNumber(tx.Flags, AMMWithdrawFlags)
|
||||||
return
|
return
|
||||||
case 'OfferCreate':
|
case 'OfferCreate':
|
||||||
tx.Flags = convertOfferCreateFlagsToNumber(tx.Flags)
|
tx.Flags = convertFlagsToNumber(tx.Flags, OfferCreateFlags)
|
||||||
return
|
return
|
||||||
case 'PaymentChannelClaim':
|
case 'PaymentChannelClaim':
|
||||||
tx.Flags = convertPaymentChannelClaimFlagsToNumber(tx.Flags)
|
tx.Flags = convertFlagsToNumber(tx.Flags, PaymentChannelClaimFlags)
|
||||||
return
|
return
|
||||||
case 'Payment':
|
case 'Payment':
|
||||||
tx.Flags = convertPaymentTransactionFlagsToNumber(tx.Flags)
|
tx.Flags = convertFlagsToNumber(tx.Flags, PaymentFlags)
|
||||||
return
|
return
|
||||||
case 'TrustSet':
|
case 'TrustSet':
|
||||||
tx.Flags = convertTrustSetFlagsToNumber(tx.Flags)
|
tx.Flags = convertFlagsToNumber(tx.Flags, TrustSetFlags)
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
tx.Flags = 0
|
tx.Flags = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertAccountSetFlagsToNumber(
|
|
||||||
flags: AccountSetFlagsInterface,
|
|
||||||
): number {
|
|
||||||
return reduceFlags(flags, AccountSetTfFlags)
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertOfferCreateFlagsToNumber(
|
|
||||||
flags: OfferCreateFlagsInterface,
|
|
||||||
): number {
|
|
||||||
return reduceFlags(flags, OfferCreateFlags)
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertPaymentChannelClaimFlagsToNumber(
|
|
||||||
flags: PaymentChannelClaimFlagsInterface,
|
|
||||||
): number {
|
|
||||||
return reduceFlags(flags, PaymentChannelClaimFlags)
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertPaymentTransactionFlagsToNumber(
|
|
||||||
flags: PaymentFlagsInterface,
|
|
||||||
): number {
|
|
||||||
return reduceFlags(flags, PaymentFlags)
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertTrustSetFlagsToNumber(flags: TrustSetFlagsInterface): number {
|
|
||||||
return reduceFlags(flags, TrustSetFlags)
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- added ValidationError check for flagEnum
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- added ValidationError check for flagEnum
|
||||||
function reduceFlags(flags: GlobalFlags, flagEnum: any): number {
|
function convertFlagsToNumber(flags: GlobalFlags, flagEnum: any): number {
|
||||||
return Object.keys(flags).reduce((resultFlags, flag) => {
|
return Object.keys(flags).reduce((resultFlags, flag) => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- safe member access
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- safe member access
|
||||||
if (flagEnum[flag] == null) {
|
if (flagEnum[flag] == null) {
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ async function setNextValidSequenceNumber(
|
|||||||
tx.Sequence = data.result.account_data.Sequence
|
tx.Sequence = data.result.account_data.Sequence
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchAccountDeleteFee(client: Client): Promise<BigNumber> {
|
async function fetchOwnerReserveFee(client: Client): Promise<BigNumber> {
|
||||||
const response = await client.request({ command: 'server_state' })
|
const response = await client.request({ command: 'server_state' })
|
||||||
const fee = response.result.state.validated_ledger?.reserve_inc
|
const fee = response.result.state.validated_ledger?.reserve_inc
|
||||||
|
|
||||||
@@ -307,9 +307,11 @@ async function calculateFeePerTransactionType(
|
|||||||
baseFee = product.dp(0, BigNumber.ROUND_CEIL)
|
baseFee = product.dp(0, BigNumber.ROUND_CEIL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccountDelete Transaction
|
if (
|
||||||
if (tx.TransactionType === 'AccountDelete') {
|
tx.TransactionType === 'AccountDelete' ||
|
||||||
baseFee = await fetchAccountDeleteFee(client)
|
tx.TransactionType === 'AMMCreate'
|
||||||
|
) {
|
||||||
|
baseFee = await fetchOwnerReserveFee(client)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
168
packages/xrpl/test/models/AMMBid.test.ts
Normal file
168
packages/xrpl/test/models/AMMBid.test.ts
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import { validate, ValidationError } from '../../src'
|
||||||
|
import { validateAMMBid } from '../../src/models/transactions/AMMBid'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AMMBid Transaction Verification Testing.
|
||||||
|
*
|
||||||
|
* Providing runtime verification testing for each specific transaction type.
|
||||||
|
*/
|
||||||
|
describe('AMMBid', function () {
|
||||||
|
let bid
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
bid = {
|
||||||
|
TransactionType: 'AMMBid',
|
||||||
|
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
||||||
|
Asset: {
|
||||||
|
currency: 'XRP',
|
||||||
|
},
|
||||||
|
Asset2: {
|
||||||
|
currency: 'ETH',
|
||||||
|
issuer: 'rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd',
|
||||||
|
},
|
||||||
|
BidMin: '5',
|
||||||
|
BidMax: '10',
|
||||||
|
AuthAccounts: [
|
||||||
|
{
|
||||||
|
AuthAccount: {
|
||||||
|
Account: 'rNZdsTBP5tH1M6GHC6bTreHAp6ouP8iZSh',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AuthAccount: {
|
||||||
|
Account: 'rfpFv97Dwu89FTyUwPjtpZBbuZxTqqgTmH',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AuthAccount: {
|
||||||
|
Account: 'rzzYHPGb8Pa64oqxCzmuffm122bitq3Vb',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AuthAccount: {
|
||||||
|
Account: 'rhwxHxaHok86fe4LykBom1jSJ3RYQJs1h4',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
Sequence: 1337,
|
||||||
|
} as any
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMBid`, function () {
|
||||||
|
assert.doesNotThrow(() => validateAMMBid(bid))
|
||||||
|
assert.doesNotThrow(() => validate(bid))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing field Asset`, function () {
|
||||||
|
delete bid.Asset
|
||||||
|
const errorMessage = 'AMMBid: missing field Asset'
|
||||||
|
assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(bid), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Asset must be a Currency`, function () {
|
||||||
|
bid.Asset = 1234
|
||||||
|
const errorMessage = 'AMMBid: Asset must be a Currency'
|
||||||
|
assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(bid), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing field Asset2`, function () {
|
||||||
|
delete bid.Asset2
|
||||||
|
const errorMessage = 'AMMBid: missing field Asset2'
|
||||||
|
assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(bid), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Asset2 must be a Currency`, function () {
|
||||||
|
bid.Asset2 = 1234
|
||||||
|
const errorMessage = 'AMMBid: Asset2 must be a Currency'
|
||||||
|
assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(bid), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ BidMin must be an Amount`, function () {
|
||||||
|
bid.BidMin = 5
|
||||||
|
const errorMessage = 'AMMBid: BidMin must be an Amount'
|
||||||
|
assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(bid), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ BidMax must be an Amount`, function () {
|
||||||
|
bid.BidMax = 10
|
||||||
|
const errorMessage = 'AMMBid: BidMax must be an Amount'
|
||||||
|
assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(bid), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ AuthAccounts length must not be greater than 4`, function () {
|
||||||
|
bid.AuthAccounts.push({
|
||||||
|
AuthAccount: {
|
||||||
|
Account: 'r3X6noRsvaLapAKCG78zAtWcbhB3sggS1s',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const errorMessage =
|
||||||
|
'AMMBid: AuthAccounts length must not be greater than 4'
|
||||||
|
assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(bid), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ AuthAccounts must be an AuthAccount array`, function () {
|
||||||
|
bid.AuthAccounts = 1234
|
||||||
|
const errorMessage = 'AMMBid: AuthAccounts must be an AuthAccount array'
|
||||||
|
assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(bid), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ invalid AuthAccounts when AuthAccount is null`, function () {
|
||||||
|
bid.AuthAccounts[0] = {
|
||||||
|
AuthAccount: null,
|
||||||
|
}
|
||||||
|
const errorMessage = 'AMMBid: invalid AuthAccounts'
|
||||||
|
assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(bid), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ invalid AuthAccounts when AuthAccount is undefined`, function () {
|
||||||
|
bid.AuthAccounts[0] = {
|
||||||
|
AuthAccount: undefined,
|
||||||
|
}
|
||||||
|
const errorMessage = 'AMMBid: invalid AuthAccounts'
|
||||||
|
assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(bid), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ invalid AuthAccounts when AuthAccount is not an object`, function () {
|
||||||
|
bid.AuthAccounts[0] = {
|
||||||
|
AuthAccount: 1234,
|
||||||
|
}
|
||||||
|
const errorMessage = 'AMMBid: invalid AuthAccounts'
|
||||||
|
assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(bid), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ invalid AuthAccounts when AuthAccount.Account is not a string`, function () {
|
||||||
|
bid.AuthAccounts[0] = {
|
||||||
|
AuthAccount: {
|
||||||
|
Account: 1234,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const errorMessage = 'AMMBid: invalid AuthAccounts'
|
||||||
|
assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(bid), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ AuthAccounts must not include sender's address`, function () {
|
||||||
|
bid.AuthAccounts[0] = {
|
||||||
|
AuthAccount: {
|
||||||
|
Account: bid.Account,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const errorMessage =
|
||||||
|
"AMMBid: AuthAccounts must not include sender's address"
|
||||||
|
assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(bid), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
121
packages/xrpl/test/models/AMMCreate.test.ts
Normal file
121
packages/xrpl/test/models/AMMCreate.test.ts
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import { validate, ValidationError } from '../../src'
|
||||||
|
import { validateAMMCreate } from '../../src/models/transactions/AMMCreate'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AMMCreate Transaction Verification Testing.
|
||||||
|
*
|
||||||
|
* Providing runtime verification testing for each specific transaction type.
|
||||||
|
*/
|
||||||
|
describe('AMMCreate', function () {
|
||||||
|
let ammCreate
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
ammCreate = {
|
||||||
|
TransactionType: 'AMMCreate',
|
||||||
|
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
||||||
|
Amount: '1000',
|
||||||
|
Amount2: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: 'rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9',
|
||||||
|
value: '1000',
|
||||||
|
},
|
||||||
|
TradingFee: 12,
|
||||||
|
Sequence: 1337,
|
||||||
|
} as any
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMCreate`, function () {
|
||||||
|
assert.doesNotThrow(() => validateAMMCreate(ammCreate))
|
||||||
|
assert.doesNotThrow(() => validate(ammCreate))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing Amount`, function () {
|
||||||
|
delete ammCreate.Amount
|
||||||
|
const errorMessage = 'AMMCreate: missing field Amount'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMCreate(ammCreate),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammCreate), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Amount must be an Amount`, function () {
|
||||||
|
ammCreate.Amount = 1000
|
||||||
|
const errorMessage = 'AMMCreate: Amount must be an Amount'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMCreate(ammCreate),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammCreate), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing Amount2`, function () {
|
||||||
|
delete ammCreate.Amount2
|
||||||
|
const errorMessage = 'AMMCreate: missing field Amount2'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMCreate(ammCreate),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammCreate), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Amount2 must be an Amount`, function () {
|
||||||
|
ammCreate.Amount2 = 1000
|
||||||
|
const errorMessage = 'AMMCreate: Amount2 must be an Amount'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMCreate(ammCreate),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammCreate), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing TradingFee`, function () {
|
||||||
|
delete ammCreate.TradingFee
|
||||||
|
const errorMessage = 'AMMCreate: missing field TradingFee'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMCreate(ammCreate),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammCreate), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ TradingFee must be a number`, function () {
|
||||||
|
ammCreate.TradingFee = '12'
|
||||||
|
const errorMessage = 'AMMCreate: TradingFee must be a number'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMCreate(ammCreate),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammCreate), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws when TradingFee is greater than 1000`, function () {
|
||||||
|
ammCreate.TradingFee = 1001
|
||||||
|
const errorMessage = 'AMMCreate: TradingFee must be between 0 and 1000'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMCreate(ammCreate),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammCreate), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws when TradingFee is a negative number`, function () {
|
||||||
|
ammCreate.TradingFee = -1
|
||||||
|
const errorMessage = 'AMMCreate: TradingFee must be between 0 and 1000'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMCreate(ammCreate),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammCreate), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
78
packages/xrpl/test/models/AMMDelete.test.ts
Normal file
78
packages/xrpl/test/models/AMMDelete.test.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import { validate, ValidationError } from '../../src'
|
||||||
|
import { validateAMMDelete } from '../../src/models/transactions/AMMDelete'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AMMDelete Transaction Verification Testing.
|
||||||
|
*
|
||||||
|
* Providing runtime verification testing for each specific transaction type.
|
||||||
|
*/
|
||||||
|
describe('AMMDelete', function () {
|
||||||
|
let ammDelete
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
ammDelete = {
|
||||||
|
TransactionType: 'AMMDelete',
|
||||||
|
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
||||||
|
Asset: {
|
||||||
|
currency: 'XRP',
|
||||||
|
},
|
||||||
|
Asset2: {
|
||||||
|
currency: 'ETH',
|
||||||
|
issuer: 'rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd',
|
||||||
|
},
|
||||||
|
Sequence: 1337,
|
||||||
|
Flags: 0,
|
||||||
|
} as any
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMDelete`, function () {
|
||||||
|
assert.doesNotThrow(() => validateAMMDelete(ammDelete))
|
||||||
|
assert.doesNotThrow(() => validate(ammDelete))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing field Asset`, function () {
|
||||||
|
delete ammDelete.Asset
|
||||||
|
const errorMessage = 'AMMDelete: missing field Asset'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMDelete(ammDelete),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammDelete), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Asset must be a Currency`, function () {
|
||||||
|
ammDelete.Asset = 1234
|
||||||
|
const errorMessage = 'AMMDelete: Asset must be a Currency'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMDelete(ammDelete),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammDelete), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing field Asset2`, function () {
|
||||||
|
delete ammDelete.Asset2
|
||||||
|
const errorMessage = 'AMMDelete: missing field Asset2'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMDelete(ammDelete),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammDelete), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Asset2 must be a Currency`, function () {
|
||||||
|
ammDelete.Asset2 = 1234
|
||||||
|
const errorMessage = 'AMMDelete: Asset2 must be a Currency'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMDelete(ammDelete),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(ammDelete), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
204
packages/xrpl/test/models/AMMDeposit.test.ts
Normal file
204
packages/xrpl/test/models/AMMDeposit.test.ts
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
/* eslint-disable no-bitwise -- bitwise necessary for enabling flags */
|
||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import { AMMDepositFlags, validate, ValidationError } from '../../src'
|
||||||
|
import { validateAMMDeposit } from '../../src/models/transactions/AMMDeposit'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AMMDeposit Transaction Verification Testing.
|
||||||
|
*
|
||||||
|
* Providing runtime verification testing for each specific transaction type.
|
||||||
|
*/
|
||||||
|
describe('AMMDeposit', function () {
|
||||||
|
const LPTokenOut = {
|
||||||
|
currency: 'B3813FCAB4EE68B3D0D735D6849465A9113EE048',
|
||||||
|
issuer: 'rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg',
|
||||||
|
value: '1000',
|
||||||
|
}
|
||||||
|
let deposit
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
deposit = {
|
||||||
|
TransactionType: 'AMMDeposit',
|
||||||
|
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
||||||
|
Asset: {
|
||||||
|
currency: 'XRP',
|
||||||
|
},
|
||||||
|
Asset2: {
|
||||||
|
currency: 'ETH',
|
||||||
|
issuer: 'rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd',
|
||||||
|
},
|
||||||
|
Sequence: 1337,
|
||||||
|
Flags: 0,
|
||||||
|
} as any
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMDeposit with LPTokenOut`, function () {
|
||||||
|
deposit.LPTokenOut = LPTokenOut
|
||||||
|
deposit.Flags |= AMMDepositFlags.tfLPToken
|
||||||
|
assert.doesNotThrow(() => validateAMMDeposit(deposit))
|
||||||
|
assert.doesNotThrow(() => validate(deposit))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMDeposit with Amount`, function () {
|
||||||
|
deposit.Amount = '1000'
|
||||||
|
deposit.Flags |= AMMDepositFlags.tfSingleAsset
|
||||||
|
assert.doesNotThrow(() => validateAMMDeposit(deposit))
|
||||||
|
assert.doesNotThrow(() => validate(deposit))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMDeposit with Amount and Amount2`, function () {
|
||||||
|
deposit.Amount = '1000'
|
||||||
|
deposit.Amount2 = {
|
||||||
|
currency: 'ETH',
|
||||||
|
issuer: 'rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd',
|
||||||
|
value: '2.5',
|
||||||
|
}
|
||||||
|
deposit.Flags |= AMMDepositFlags.tfTwoAsset
|
||||||
|
assert.doesNotThrow(() => validateAMMDeposit(deposit))
|
||||||
|
assert.doesNotThrow(() => validate(deposit))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMDeposit with Amount and LPTokenOut`, function () {
|
||||||
|
deposit.Amount = '1000'
|
||||||
|
deposit.LPTokenOut = LPTokenOut
|
||||||
|
deposit.Flags |= AMMDepositFlags.tfOneAssetLPToken
|
||||||
|
assert.doesNotThrow(() => validateAMMDeposit(deposit))
|
||||||
|
assert.doesNotThrow(() => validate(deposit))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMDeposit with Amount and EPrice`, function () {
|
||||||
|
deposit.Amount = '1000'
|
||||||
|
deposit.EPrice = '25'
|
||||||
|
deposit.Flags |= AMMDepositFlags.tfLimitLPToken
|
||||||
|
assert.doesNotThrow(() => validateAMMDeposit(deposit))
|
||||||
|
assert.doesNotThrow(() => validate(deposit))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing field Asset`, function () {
|
||||||
|
delete deposit.Asset
|
||||||
|
const errorMessage = 'AMMDeposit: missing field Asset'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMDeposit(deposit),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(deposit), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Asset must be a Currency`, function () {
|
||||||
|
deposit.Asset = 1234
|
||||||
|
const errorMessage = 'AMMDeposit: Asset must be a Currency'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMDeposit(deposit),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(deposit), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing field Asset2`, function () {
|
||||||
|
delete deposit.Asset2
|
||||||
|
const errorMessage = 'AMMDeposit: missing field Asset2'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMDeposit(deposit),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(deposit), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Asset2 must be a Currency`, function () {
|
||||||
|
deposit.Asset2 = 1234
|
||||||
|
const errorMessage = 'AMMDeposit: Asset2 must be a Currency'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMDeposit(deposit),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(deposit), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ must set at least LPTokenOut or Amount`, function () {
|
||||||
|
const errorMessage = 'AMMDeposit: must set at least LPTokenOut or Amount'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMDeposit(deposit),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(deposit), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ must set Amount with Amount2`, function () {
|
||||||
|
deposit.Amount2 = {
|
||||||
|
currency: 'ETH',
|
||||||
|
issuer: 'rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd',
|
||||||
|
value: '2.5',
|
||||||
|
}
|
||||||
|
const errorMessage = 'AMMDeposit: must set Amount with Amount2'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMDeposit(deposit),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(deposit), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ must set Amount with EPrice`, function () {
|
||||||
|
deposit.EPrice = '25'
|
||||||
|
const errorMessage = 'AMMDeposit: must set Amount with EPrice'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMDeposit(deposit),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(deposit), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ LPTokenOut must be an IssuedCurrencyAmount`, function () {
|
||||||
|
deposit.LPTokenOut = 1234
|
||||||
|
const errorMessage =
|
||||||
|
'AMMDeposit: LPTokenOut must be an IssuedCurrencyAmount'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMDeposit(deposit),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(deposit), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Amount must be an Amount`, function () {
|
||||||
|
deposit.Amount = 1234
|
||||||
|
const errorMessage = 'AMMDeposit: Amount must be an Amount'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMDeposit(deposit),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(deposit), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Amount2 must be an Amount`, function () {
|
||||||
|
deposit.Amount = '1000'
|
||||||
|
deposit.Amount2 = 1234
|
||||||
|
const errorMessage = 'AMMDeposit: Amount2 must be an Amount'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMDeposit(deposit),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(deposit), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ EPrice must be an Amount`, function () {
|
||||||
|
deposit.Amount = '1000'
|
||||||
|
deposit.EPrice = 1234
|
||||||
|
const errorMessage = 'AMMDeposit: EPrice must be an Amount'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMDeposit(deposit),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(deposit), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
90
packages/xrpl/test/models/AMMVote.test.ts
Normal file
90
packages/xrpl/test/models/AMMVote.test.ts
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import { validate, ValidationError } from '../../src'
|
||||||
|
import { validateAMMVote } from '../../src/models/transactions/AMMVote'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AMMVote Transaction Verification Testing.
|
||||||
|
*
|
||||||
|
* Providing runtime verification testing for each specific transaction type.
|
||||||
|
*/
|
||||||
|
describe('AMMVote', function () {
|
||||||
|
let vote
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
vote = {
|
||||||
|
TransactionType: 'AMMVote',
|
||||||
|
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
||||||
|
Asset: {
|
||||||
|
currency: 'XRP',
|
||||||
|
},
|
||||||
|
Asset2: {
|
||||||
|
currency: 'ETH',
|
||||||
|
issuer: 'rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd',
|
||||||
|
},
|
||||||
|
TradingFee: 25,
|
||||||
|
Sequence: 1337,
|
||||||
|
} as any
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMVote`, function () {
|
||||||
|
assert.doesNotThrow(() => validateAMMVote(vote))
|
||||||
|
assert.doesNotThrow(() => validate(vote))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing field Asset`, function () {
|
||||||
|
delete vote.Asset
|
||||||
|
const errorMessage = 'AMMVote: missing field Asset'
|
||||||
|
assert.throws(() => validateAMMVote(vote), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(vote), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Asset must be a Currency`, function () {
|
||||||
|
vote.Asset = 1234
|
||||||
|
const errorMessage = 'AMMVote: Asset must be a Currency'
|
||||||
|
assert.throws(() => validateAMMVote(vote), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(vote), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing field Asset2`, function () {
|
||||||
|
delete vote.Asset2
|
||||||
|
const errorMessage = 'AMMVote: missing field Asset2'
|
||||||
|
assert.throws(() => validateAMMVote(vote), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(vote), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Asset2 must be a Currency`, function () {
|
||||||
|
vote.Asset2 = 1234
|
||||||
|
const errorMessage = 'AMMVote: Asset2 must be a Currency'
|
||||||
|
assert.throws(() => validateAMMVote(vote), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(vote), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing field TradingFee`, function () {
|
||||||
|
delete vote.TradingFee
|
||||||
|
const errorMessage = 'AMMVote: missing field TradingFee'
|
||||||
|
assert.throws(() => validateAMMVote(vote), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(vote), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ TradingFee must be a number`, function () {
|
||||||
|
vote.TradingFee = '25'
|
||||||
|
const errorMessage = 'AMMVote: TradingFee must be a number'
|
||||||
|
assert.throws(() => validateAMMVote(vote), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(vote), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws when TradingFee is greater than AMM_MAX_TRADING_FEE`, function () {
|
||||||
|
vote.TradingFee = 1001
|
||||||
|
const errorMessage = 'AMMVote: TradingFee must be between 0 and 1000'
|
||||||
|
assert.throws(() => validateAMMVote(vote), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(vote), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws when TradingFee is a negative number`, function () {
|
||||||
|
vote.TradingFee = -1
|
||||||
|
const errorMessage = 'AMMVote: TradingFee must be between 0 and 1000'
|
||||||
|
assert.throws(() => validateAMMVote(vote), ValidationError, errorMessage)
|
||||||
|
assert.throws(() => validate(vote), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
207
packages/xrpl/test/models/AMMWithdraw.test.ts
Normal file
207
packages/xrpl/test/models/AMMWithdraw.test.ts
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
/* eslint-disable no-bitwise -- bitwise necessary for enabling flags */
|
||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import { AMMWithdrawFlags, validate, ValidationError } from '../../src'
|
||||||
|
import { validateAMMWithdraw } from '../../src/models/transactions/AMMWithdraw'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AMMWithdraw Transaction Verification Testing.
|
||||||
|
*
|
||||||
|
* Providing runtime verification testing for each specific transaction type.
|
||||||
|
*/
|
||||||
|
describe('AMMWithdraw', function () {
|
||||||
|
const LPTokenIn = {
|
||||||
|
currency: 'B3813FCAB4EE68B3D0D735D6849465A9113EE048',
|
||||||
|
issuer: 'rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg',
|
||||||
|
value: '1000',
|
||||||
|
}
|
||||||
|
let withdraw
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
withdraw = {
|
||||||
|
TransactionType: 'AMMWithdraw',
|
||||||
|
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
|
||||||
|
Asset: {
|
||||||
|
currency: 'XRP',
|
||||||
|
},
|
||||||
|
Asset2: {
|
||||||
|
currency: 'ETH',
|
||||||
|
issuer: 'rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd',
|
||||||
|
},
|
||||||
|
Sequence: 1337,
|
||||||
|
Flags: 0,
|
||||||
|
} as any
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMWithdraw with LPTokenIn`, function () {
|
||||||
|
withdraw.LPTokenIn = LPTokenIn
|
||||||
|
withdraw.Flags |= AMMWithdrawFlags.tfLPToken
|
||||||
|
assert.doesNotThrow(() => validateAMMWithdraw(withdraw))
|
||||||
|
assert.doesNotThrow(() => validate(withdraw))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMWithdraw with Amount`, function () {
|
||||||
|
withdraw.Amount = '1000'
|
||||||
|
withdraw.Flags |= AMMWithdrawFlags.tfSingleAsset
|
||||||
|
assert.doesNotThrow(() => validateAMMWithdraw(withdraw))
|
||||||
|
assert.doesNotThrow(() => validate(withdraw))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMWithdraw with Amount and Amount2`, function () {
|
||||||
|
withdraw.Amount = '1000'
|
||||||
|
withdraw.Amount2 = {
|
||||||
|
currency: 'ETH',
|
||||||
|
issuer: 'rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd',
|
||||||
|
value: '2.5',
|
||||||
|
}
|
||||||
|
withdraw.Flags |= AMMWithdrawFlags.tfTwoAsset
|
||||||
|
assert.doesNotThrow(() => validateAMMWithdraw(withdraw))
|
||||||
|
assert.doesNotThrow(() => validate(withdraw))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMWithdraw with Amount and LPTokenIn`, function () {
|
||||||
|
withdraw.Amount = '1000'
|
||||||
|
withdraw.LPTokenIn = LPTokenIn
|
||||||
|
withdraw.Flags |= AMMWithdrawFlags.tfOneAssetLPToken
|
||||||
|
assert.doesNotThrow(() => validateAMMWithdraw(withdraw))
|
||||||
|
assert.doesNotThrow(() => validate(withdraw))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMWithdraw with Amount and EPrice`, function () {
|
||||||
|
withdraw.Amount = '1000'
|
||||||
|
withdraw.EPrice = '25'
|
||||||
|
withdraw.Flags |= AMMWithdrawFlags.tfLimitLPToken
|
||||||
|
assert.doesNotThrow(() => validateAMMWithdraw(withdraw))
|
||||||
|
assert.doesNotThrow(() => validate(withdraw))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMWithdraw one asset withdraw all`, function () {
|
||||||
|
withdraw.Amount = '1000'
|
||||||
|
withdraw.Flags |= AMMWithdrawFlags.tfOneAssetWithdrawAll
|
||||||
|
assert.doesNotThrow(() => validateAMMWithdraw(withdraw))
|
||||||
|
assert.doesNotThrow(() => validate(withdraw))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid AMMWithdraw withdraw all`, function () {
|
||||||
|
withdraw.Flags |= AMMWithdrawFlags.tfWithdrawAll
|
||||||
|
assert.doesNotThrow(() => validateAMMWithdraw(withdraw))
|
||||||
|
assert.doesNotThrow(() => validate(withdraw))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing field Asset`, function () {
|
||||||
|
delete withdraw.Asset
|
||||||
|
const errorMessage = 'AMMWithdraw: missing field Asset'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMWithdraw(withdraw),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(withdraw), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Asset must be a Currency`, function () {
|
||||||
|
withdraw.Asset = 1234
|
||||||
|
const errorMessage = 'AMMWithdraw: Asset must be a Currency'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMWithdraw(withdraw),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(withdraw), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ missing field Asset2`, function () {
|
||||||
|
delete withdraw.Asset2
|
||||||
|
const errorMessage = 'AMMWithdraw: missing field Asset2'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMWithdraw(withdraw),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(withdraw), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Asset2 must be a Currency`, function () {
|
||||||
|
withdraw.Asset2 = 1234
|
||||||
|
const errorMessage = 'AMMWithdraw: Asset2 must be a Currency'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMWithdraw(withdraw),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(withdraw), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ must set Amount with Amount2`, function () {
|
||||||
|
withdraw.Amount2 = {
|
||||||
|
currency: 'ETH',
|
||||||
|
issuer: 'rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd',
|
||||||
|
value: '2.5',
|
||||||
|
}
|
||||||
|
const errorMessage = 'AMMWithdraw: must set Amount with Amount2'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMWithdraw(withdraw),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(withdraw), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ must set Amount with EPrice`, function () {
|
||||||
|
withdraw.EPrice = '25'
|
||||||
|
const errorMessage = 'AMMWithdraw: must set Amount with EPrice'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMWithdraw(withdraw),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(withdraw), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ LPTokenIn must be an IssuedCurrencyAmount`, function () {
|
||||||
|
withdraw.LPTokenIn = 1234
|
||||||
|
const errorMessage =
|
||||||
|
'AMMWithdraw: LPTokenIn must be an IssuedCurrencyAmount'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMWithdraw(withdraw),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(withdraw), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Amount must be an Amount`, function () {
|
||||||
|
withdraw.Amount = 1234
|
||||||
|
const errorMessage = 'AMMWithdraw: Amount must be an Amount'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMWithdraw(withdraw),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(withdraw), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ Amount2 must be an Amount`, function () {
|
||||||
|
withdraw.Amount = '1000'
|
||||||
|
withdraw.Amount2 = 1234
|
||||||
|
const errorMessage = 'AMMWithdraw: Amount2 must be an Amount'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMWithdraw(withdraw),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(withdraw), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ EPrice must be an Amount`, function () {
|
||||||
|
withdraw.Amount = '1000'
|
||||||
|
withdraw.EPrice = 1234
|
||||||
|
const errorMessage = 'AMMWithdraw: EPrice must be an Amount'
|
||||||
|
assert.throws(
|
||||||
|
() => validateAMMWithdraw(withdraw),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(withdraw), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user