mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-05 05:15:48 +00:00
Compare commits
43 Commits
@transia/x
...
@transia/r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d98d2e5fdb | ||
|
|
da39e14d46 | ||
|
|
ae43c75504 | ||
|
|
4ae9839f68 | ||
|
|
f77d135bb8 | ||
|
|
720880a383 | ||
|
|
1dbf35dbcb | ||
|
|
d6411baf10 | ||
|
|
ab86bae582 | ||
|
|
cb61711298 | ||
|
|
b449a62c5b | ||
|
|
5183289719 | ||
|
|
8ae372bb08 | ||
|
|
63238773ea | ||
|
|
4aacb1160a | ||
|
|
445d0c6633 | ||
|
|
501d3158a0 | ||
|
|
e27943aa3a | ||
|
|
c7aafb2595 | ||
|
|
036312d361 | ||
|
|
3467680506 | ||
|
|
f209126364 | ||
|
|
33a8b3679a | ||
|
|
572aaa7a40 | ||
|
|
b6c11d1df8 | ||
|
|
526d1e7686 | ||
|
|
3c668f41b8 | ||
|
|
aeb29a20a1 | ||
|
|
8c814482e5 | ||
|
|
5b57ea8b77 | ||
|
|
7663e6049f | ||
|
|
420d6b2c35 | ||
|
|
02c41d2eb1 | ||
|
|
3f1a54f018 | ||
|
|
ac865e472e | ||
|
|
60c97901d2 | ||
|
|
3b234ec8ec | ||
|
|
c7a001e7e9 | ||
|
|
e24cbccc2b | ||
|
|
53310f699a | ||
|
|
46de80131a | ||
|
|
7981faf92f | ||
|
|
0cf024cab1 |
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -29,7 +29,7 @@
|
||||
"enable": true
|
||||
},
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimFinalNewlines": true,
|
||||
|
||||
@@ -32,19 +32,19 @@ All of which works in Node.js (tested for v14+) & web browsers (tested for Chrom
|
||||
In an existing project (with package.json), install xrpl.js with:
|
||||
|
||||
```
|
||||
$ npm install --save xrpl
|
||||
$ npm install --save @transia/xrpl
|
||||
```
|
||||
|
||||
Or with `yarn`:
|
||||
|
||||
```
|
||||
$ yarn add xrpl
|
||||
$ yarn add @transia/xrpl
|
||||
```
|
||||
|
||||
Example usage:
|
||||
|
||||
```js
|
||||
const xrpl = require("xrpl");
|
||||
const xrpl = require("@transia/xrpl");
|
||||
async function main() {
|
||||
const client = new xrpl.Client("wss://s.altnet.rippletest.net:51233");
|
||||
await client.connect();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@transia/ripple-binary-codec",
|
||||
"version": "1.4.6-alpha.3",
|
||||
"version": "1.4.6-alpha.10",
|
||||
"description": "XRP Ledger binary codec",
|
||||
"files": [
|
||||
"dist/*",
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"LedgerHashes": 104,
|
||||
"Amendments": 102,
|
||||
"FeeSettings": 115,
|
||||
"ImportVlseq": 73,
|
||||
"ImportVLSequence": 73,
|
||||
"Escrow": 117,
|
||||
"PayChannel": 120,
|
||||
"Check": 67,
|
||||
@@ -46,6 +46,7 @@
|
||||
"NFTokenPage": 80,
|
||||
"NFTokenOffer": 55,
|
||||
"URIToken": 85,
|
||||
"UNLReport": 82,
|
||||
"Any": -3,
|
||||
"Child": -2,
|
||||
"Nickname": 110,
|
||||
@@ -140,40 +141,40 @@
|
||||
[
|
||||
"LedgerEntry",
|
||||
{
|
||||
"nth": 1,
|
||||
"nth": 257,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": false,
|
||||
"isSigningField": true,
|
||||
"isSigningField": false,
|
||||
"type": "LedgerEntry"
|
||||
}
|
||||
],
|
||||
[
|
||||
"Transaction",
|
||||
{
|
||||
"nth": 1,
|
||||
"nth": 257,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": false,
|
||||
"isSigningField": true,
|
||||
"isSigningField": false,
|
||||
"type": "Transaction"
|
||||
}
|
||||
],
|
||||
[
|
||||
"Validation",
|
||||
{
|
||||
"nth": 1,
|
||||
"nth": 257,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": false,
|
||||
"isSigningField": true,
|
||||
"isSigningField": false,
|
||||
"type": "Validation"
|
||||
}
|
||||
],
|
||||
[
|
||||
"Metadata",
|
||||
{
|
||||
"nth": 1,
|
||||
"nth": 257,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"isSerialized": false,
|
||||
"isSigningField": false,
|
||||
"type": "Metadata"
|
||||
}
|
||||
],
|
||||
@@ -1997,6 +1998,16 @@
|
||||
"type": "AccountID"
|
||||
}
|
||||
],
|
||||
[
|
||||
"Inform",
|
||||
{
|
||||
"nth": 99,
|
||||
"isVLEncoded": true,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "AccountID"
|
||||
}
|
||||
],
|
||||
[
|
||||
"Indexes",
|
||||
{
|
||||
@@ -2047,6 +2058,16 @@
|
||||
"type": "Vector256"
|
||||
}
|
||||
],
|
||||
[
|
||||
"URITokenIDs",
|
||||
{
|
||||
"nth": 99,
|
||||
"isVLEncoded": true,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "Vector256"
|
||||
}
|
||||
],
|
||||
[
|
||||
"Paths",
|
||||
{
|
||||
@@ -2307,6 +2328,26 @@
|
||||
"type": "STObject"
|
||||
}
|
||||
],
|
||||
[
|
||||
"MintURIToken",
|
||||
{
|
||||
"nth": 92,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "STObject"
|
||||
}
|
||||
],
|
||||
[
|
||||
"AmountEntry",
|
||||
{
|
||||
"nth": 91,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "STObject"
|
||||
}
|
||||
],
|
||||
[
|
||||
"Signers",
|
||||
{
|
||||
@@ -2486,6 +2527,16 @@
|
||||
"isSigningField": true,
|
||||
"type": "STArray"
|
||||
}
|
||||
],
|
||||
[
|
||||
"Amounts",
|
||||
{
|
||||
"nth": 92,
|
||||
"isVLEncoded": false,
|
||||
"isSerialized": true,
|
||||
"isSigningField": true,
|
||||
"type": "STArray"
|
||||
}
|
||||
]
|
||||
],
|
||||
"TRANSACTION_RESULTS": {
|
||||
@@ -2520,11 +2571,11 @@
|
||||
"temBAD_PATH": -291,
|
||||
"temBAD_PATH_LOOP": -290,
|
||||
"temBAD_REGKEY": -289,
|
||||
"temBAD_SEND_XRP_LIMIT": -288,
|
||||
"temBAD_SEND_XRP_MAX": -287,
|
||||
"temBAD_SEND_XRP_NO_DIRECT": -286,
|
||||
"temBAD_SEND_XRP_PARTIAL": -285,
|
||||
"temBAD_SEND_XRP_PATHS": -284,
|
||||
"temBAD_SEND_NATIVE_LIMIT": -288,
|
||||
"temBAD_SEND_NATIVE_MAX": -287,
|
||||
"temBAD_SEND_NATIVE_NO_DIRECT": -286,
|
||||
"temBAD_SEND_NATIVE_PARTIAL": -285,
|
||||
"temBAD_SEND_NATIVE_PATHS": -284,
|
||||
"temBAD_SEQUENCE": -283,
|
||||
"temBAD_SIGNATURE": -282,
|
||||
"temBAD_SRC_ACCOUNT": -281,
|
||||
@@ -2556,7 +2607,6 @@
|
||||
"temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT": -255,
|
||||
"temXCHAIN_TOO_MANY_ATTESTATIONS": -254,
|
||||
"temHOOK_DATA_TOO_LARGE": -253,
|
||||
"temHOOK_REJECTED": -252,
|
||||
|
||||
"tefFAILURE": -199,
|
||||
"tefALREADY": -198,
|
||||
@@ -2581,6 +2631,7 @@
|
||||
"tefNFTOKEN_IS_NOT_TRANSFERABLE": -179,
|
||||
"tefPAST_IMPORT_SEQ": -178,
|
||||
"tefPAST_IMPORT_VL_SEQ": -177,
|
||||
"tefNONDIR_EMIT": -176,
|
||||
|
||||
"terRETRY": -99,
|
||||
"terFUNDS_SPENT": -98,
|
||||
@@ -2598,6 +2649,7 @@
|
||||
"terNO_HOOK": -86,
|
||||
|
||||
"tesSUCCESS": 0,
|
||||
"tesPARTIAL": 1,
|
||||
|
||||
"tecCLAIM": 100,
|
||||
"tecPATH_PARTIAL": 101,
|
||||
@@ -2609,7 +2661,7 @@
|
||||
"tecINSUF_RESERVE_LINE": 122,
|
||||
"tecINSUF_RESERVE_OFFER": 123,
|
||||
"tecNO_DST": 124,
|
||||
"tecNO_DST_INSUF_XRP": 125,
|
||||
"tecNO_DST_INSUF_NATIVE": 125,
|
||||
"tecNO_LINE_INSUF_RESERVE": 126,
|
||||
"tecNO_LINE_REDUNDANT": 127,
|
||||
"tecPATH_DRY": 128,
|
||||
@@ -2671,6 +2723,7 @@
|
||||
"tecXCHAIN_PAYMENT_FAILED": 184,
|
||||
"tecXCHAIN_SELF_COMMIT": 185,
|
||||
"tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR": 186,
|
||||
"tecINSUF_RESERVE_SELLER": 187,
|
||||
"tecLAST_POSSIBLE_ENTRY": 255
|
||||
},
|
||||
"TRANSACTION_TYPES": {
|
||||
@@ -2708,6 +2761,7 @@
|
||||
"URITokenBuy": 47,
|
||||
"URITokenCreateSellOffer": 48,
|
||||
"URITokenCancelSellOffer": 49,
|
||||
"Remit": 95,
|
||||
"GenesisMint": 96,
|
||||
"Import": 97,
|
||||
"ClaimReward": 98,
|
||||
|
||||
@@ -12,7 +12,7 @@ const STANDARD_FORMAT_HEX_REGEX = /^0{24}[\x00-\x7F]{6}0{10}$/
|
||||
*/
|
||||
function isoToBytes(iso: string): Buffer {
|
||||
const bytes = Buffer.alloc(20)
|
||||
if (iso !== 'XRP') {
|
||||
if (iso !== 'XAH') {
|
||||
const isoBytes = iso.split('').map((c) => c.charCodeAt(0))
|
||||
bytes.set(isoBytes, 12)
|
||||
}
|
||||
@@ -28,7 +28,7 @@ function isIsoCode(iso: string): boolean {
|
||||
|
||||
function isoCodeFromHex(code: Buffer): string | null {
|
||||
const iso = code.toString()
|
||||
if (iso === 'XRP') {
|
||||
if (iso === 'XAH') {
|
||||
return null
|
||||
}
|
||||
if (isIsoCode(iso)) {
|
||||
@@ -89,7 +89,7 @@ class Currency extends Hash160 {
|
||||
const hex = this.bytes.toString('hex')
|
||||
|
||||
if (XRP_HEX_REGEX.test(hex)) {
|
||||
this._iso = 'XRP'
|
||||
this._iso = 'XAH'
|
||||
} else if (STANDARD_FORMAT_HEX_REGEX.test(hex)) {
|
||||
this._iso = isoCodeFromHex(this.bytes.slice(12, 15))
|
||||
} else {
|
||||
|
||||
@@ -369,7 +369,7 @@ function pathSetBinaryTests() {
|
||||
currency: 'BTC',
|
||||
issuer: 'r3AWbdp2jQLXLywJypdoNwVSvr81xs3uhn',
|
||||
},
|
||||
{ currency: 'XRP' },
|
||||
{ currency: 'XAH' },
|
||||
{
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
|
||||
@@ -105,6 +105,16 @@ let json_omitted = {
|
||||
}
|
||||
|
||||
const NegativeUNL = require('./fixtures/negative-unl.json')
|
||||
const UNLReport = {
|
||||
tx: require('./fixtures/unl-report.json'),
|
||||
binary: require('./fixtures/unl-report-binary.json'),
|
||||
meta: require('./fixtures/unl-report-meta-binary.json'),
|
||||
}
|
||||
|
||||
const Remit = {
|
||||
tx: require('./fixtures/remit-tx.json'),
|
||||
binary: require('./fixtures/remit-binary.json'),
|
||||
}
|
||||
|
||||
function bytesListTest() {
|
||||
const list = new BytesList()
|
||||
@@ -229,6 +239,18 @@ function NegativeUNLTest() {
|
||||
})
|
||||
}
|
||||
|
||||
function UNLReportTest() {
|
||||
test('can serialize UNLReport', () => {
|
||||
expect(encode(UNLReport.tx)).toEqual(UNLReport.binary)
|
||||
})
|
||||
test('can serialize UNLReport metadata', () => {
|
||||
expect(encode(UNLReport.tx.meta)).toEqual(UNLReport.meta)
|
||||
})
|
||||
test('can deserialize UNLReport metadata', () => {
|
||||
expect(decode(UNLReport.meta)).toEqual(UNLReport.tx.meta)
|
||||
})
|
||||
}
|
||||
|
||||
function omitUndefinedTest() {
|
||||
test('omits fields with undefined value', () => {
|
||||
let encodedOmitted = encode(json_omitted)
|
||||
@@ -274,6 +296,12 @@ function nfTokenTest() {
|
||||
}
|
||||
}
|
||||
|
||||
function RemitTest() {
|
||||
test('can serialize Remit', () => {
|
||||
expect(encode(Remit.tx)).toEqual(Remit.binary)
|
||||
})
|
||||
}
|
||||
|
||||
describe('Binary Serialization', function () {
|
||||
describe('nestedObjectTests', nestedObjectTests)
|
||||
describe('BytesList', bytesListTest)
|
||||
@@ -286,4 +314,6 @@ describe('Binary Serialization', function () {
|
||||
describe('OmitUndefined', omitUndefinedTest)
|
||||
describe('TicketTest', ticketTest)
|
||||
describe('NFToken', nfTokenTest)
|
||||
describe('UNLReport', UNLReportTest)
|
||||
describe('Remit', RemitTest)
|
||||
})
|
||||
|
||||
@@ -2904,7 +2904,7 @@
|
||||
"type_id": 6,
|
||||
"is_native": true,
|
||||
"type": "Amount",
|
||||
"error": "1000000000000 absolute XRP is bigger than max native value 100000000000.0",
|
||||
"error": "1000000000000 absolute XAH is bigger than max native value 100000000000.0",
|
||||
"is_negative": false
|
||||
},
|
||||
{
|
||||
@@ -2912,7 +2912,7 @@
|
||||
"type_id": 6,
|
||||
"is_native": true,
|
||||
"type": "Amount",
|
||||
"error": "10000000000000000000 absolute XRP is bigger than max native value 100000000000.0",
|
||||
"error": "10000000000000000000 absolute XAH is bigger than max native value 100000000000.0",
|
||||
"is_negative": true
|
||||
}
|
||||
]
|
||||
|
||||
1
packages/ripple-binary-codec/test/fixtures/remit-binary.json
vendored
Normal file
1
packages/ripple-binary-codec/test/fixtures/remit-binary.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
"12005F22000000002403EDEB4A2E00000001201B03EE5D3150116F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B68400000000000000C732102F9E33F16DF9507705EC954E3F94EB5F10D1FC4A354606DBE6297DBB1096FE65474473045022100E3FAE0EDEC3D6A8FF6D81BC9CF8288A61B7EEDE8071E90FF9314CB4621058D10022043545CF631706D700CEE65A1DB83EFDD185413808292D9D90F14D87D3DC2D8CB701A04DEADBEEF81147990EC5D1D8DF69E070A968D4B186986FDF06ED0831449FF0C73CA6AF9733DA805F76CA2C37776B7C46B806314757C4A9ED08284D61F3D8807280795F858BAB61DE05C220000000150156F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B7504DEADBEEFE1F05CE05B6140000000000003E8E1E05B61D4838D7EA4C68000000000000000000000000000555344000000000006B80F0F1D98AEDA846ED981F741C398FB2C4FD1E1F100136320AED08CC1F50DD5F23A1948AF86153A3F3B7593E5EC77D65A02BB1B29E05AB6AE"
|
||||
39
packages/ripple-binary-codec/test/fixtures/remit-tx.json
vendored
Normal file
39
packages/ripple-binary-codec/test/fixtures/remit-tx.json
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"TransactionType": "Remit",
|
||||
"Account": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo",
|
||||
"Destination": "rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy",
|
||||
"DestinationTag": 1,
|
||||
"Fee": "12",
|
||||
"Flags": 0,
|
||||
"LastLedgerSequence": 65953073,
|
||||
"Sequence": 65923914,
|
||||
"SigningPubKey": "02F9E33F16DF9507705EC954E3F94EB5F10D1FC4A354606DBE6297DBB1096FE654",
|
||||
"TxnSignature": "3045022100E3FAE0EDEC3D6A8FF6D81BC9CF8288A61B7EEDE8071E90FF9314CB4621058D10022043545CF631706D700CEE65A1DB83EFDD185413808292D9D90F14D87D3DC2D8CB",
|
||||
"Amounts": [
|
||||
{
|
||||
"AmountEntry": {
|
||||
"Amount": "1000"
|
||||
}
|
||||
},
|
||||
{
|
||||
"AmountEntry": {
|
||||
"Amount": {
|
||||
"currency": "USD",
|
||||
"issuer": "rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX",
|
||||
"value": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"MintURIToken": {
|
||||
"URI": "DEADBEEF",
|
||||
"Digest": "6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B",
|
||||
"Flags": 1
|
||||
},
|
||||
"URITokenIDs": [
|
||||
"AED08CC1F50DD5F23A1948AF86153A3F3B7593E5EC77D65A02BB1B29E05AB6AE"
|
||||
],
|
||||
"InvoiceID": "6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B",
|
||||
"Blob": "DEADBEEF",
|
||||
"Inform": "rB5Ux4Lv2nRx6eeoAAsZmtctnBQ2LiACnk"
|
||||
}
|
||||
1
packages/ripple-binary-codec/test/fixtures/unl-report-binary.json
vendored
Normal file
1
packages/ripple-binary-codec/test/fixtures/unl-report-binary.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
"120068240000000026006D2E00684000000000000000730081140000000000000000000000000000000000000000E05F7121ED93B2BE467CAD2F9F56FB3A82BDFF17F84B09E34232DDE8FAF2FC72382F142655E1"
|
||||
1
packages/ripple-binary-codec/test/fixtures/unl-report-meta-binary.json
vendored
Normal file
1
packages/ripple-binary-codec/test/fixtures/unl-report-meta-binary.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
"201C00000000F8E51100525661E32E7A24A238F1C619D5F9DDCC41A94B33B66C0163F7EFCC8A19C9FD6F28DCE6F05FE05F7121ED3ABC6740983BFB13FFD9728EBCC365A2877877D368FC28990819522300C92A698114A53F8465478D79DC0C764F0FB2B67AE92465FD5EE1E05F7121ED49F82B2FFD537F224A1E0A10DEEFC3C25CE3882979E6B327C9F18603D21F0A2281142BF2A77E25382EC1DEF521D81D24BC0FDD35BC9BE1E05F7121ED79EB0F6A9F01A039235E536D19F812B55ACF540C9E22CF62C271E0D42BFF51748114C45147960400DB6B763110CBCE8D641E9365F24EE1E05F7121ED93B2BE467CAD2F9F56FB3A82BDFF17F84B09E34232DDE8FAF2FC72382F142655811408BCFB092DEE1BF0F2662AECE4DCC62C4AECCB8AE1E05F7121ED96F581FED430E8CBE1F08B37408857001D4118D49FBB594B0BE007C2DBFFD3678114A4EF485B50A7D91DF45450A680FAC31C53367B2DE1E05F7121EDCF31B8F683345E1C49B4A1D85BF2731E55E7D6781F3D4BF45EE7ADF2D2FB340281144D854497B48F1A41EF04E09DB656A11AAD01A703E1E05F7121EDDF197FC59A7FAA09EB1AD60A4638BA6201DD51497B5C08A1745115098E229E0E811446550CBD2B655081662AE3159B0488DE27EC0592E1F1E1E72200000000F05EE05E7121ED264807102805220DA0F312E71FC2C69E1552C9C5790F6C25E3729DEB573D5860811478339DD5880A994A5CB6E56CB7ED13FEEF201928E1F1F05FE05F7121ED93B2BE467CAD2F9F56FB3A82BDFF17F84B09E34232DDE8FAF2FC72382F142655811408BCFB092DEE1BF0F2662AECE4DCC62C4AECCB8AE1F1E1E1F1031000"
|
||||
89
packages/ripple-binary-codec/test/fixtures/unl-report.json
vendored
Normal file
89
packages/ripple-binary-codec/test/fixtures/unl-report.json
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"Account": "",
|
||||
"ActiveValidator": {
|
||||
"PublicKey": "ED93B2BE467CAD2F9F56FB3A82BDFF17F84B09E34232DDE8FAF2FC72382F142655"
|
||||
},
|
||||
"Fee": "0",
|
||||
"LedgerSequence": 7155200,
|
||||
"Sequence": 0,
|
||||
"SigningPubKey": "",
|
||||
"TransactionType": "UNLReport",
|
||||
"hash": "0878863F758F74A5CBD35691CDAB625A3BCD35B21B440E20545C4757DDB0CA43",
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"ActiveValidators": [
|
||||
{
|
||||
"ActiveValidator": {
|
||||
"Account": "roUo3ygV92bdhfE1v9LGpPETXvJv2kQv5",
|
||||
"PublicKey": "ED93B2BE467CAD2F9F56FB3A82BDFF17F84B09E34232DDE8FAF2FC72382F142655"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Flags": 0,
|
||||
"ImportVLKeys": [
|
||||
{
|
||||
"ImportVLKey": {
|
||||
"Account": "rBxZvQBY551DJ21g9AC1Qc9ASQowqcskbF",
|
||||
"PublicKey": "ED264807102805220DA0F312E71FC2C69E1552C9C5790F6C25E3729DEB573D5860"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"LedgerEntryType": "UNLReport",
|
||||
"LedgerIndex": "61E32E7A24A238F1C619D5F9DDCC41A94B33B66C0163F7EFCC8A19C9FD6F28DC",
|
||||
"PreviousFields": {
|
||||
"ActiveValidators": [
|
||||
{
|
||||
"ActiveValidator": {
|
||||
"Account": "rGhk2uLd8ShzX2Zrcgn8sQk1LWBG4jjEwf",
|
||||
"PublicKey": "ED3ABC6740983BFB13FFD9728EBCC365A2877877D368FC28990819522300C92A69"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ActiveValidator": {
|
||||
"Account": "rnr4kwS1VkJhvjVRuq2fbWZtEdN2HbpVVu",
|
||||
"PublicKey": "ED49F82B2FFD537F224A1E0A10DEEFC3C25CE3882979E6B327C9F18603D21F0A22"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ActiveValidator": {
|
||||
"Account": "rJupFrPPYgUNFBdoSqhMEJ22hiHKiZSHXQ",
|
||||
"PublicKey": "ED79EB0F6A9F01A039235E536D19F812B55ACF540C9E22CF62C271E0D42BFF5174"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ActiveValidator": {
|
||||
"Account": "roUo3ygV92bdhfE1v9LGpPETXvJv2kQv5",
|
||||
"PublicKey": "ED93B2BE467CAD2F9F56FB3A82BDFF17F84B09E34232DDE8FAF2FC72382F142655"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ActiveValidator": {
|
||||
"Account": "rGsa7f4arJ8JE9ok9LCht6jCu5xBKUKVMq",
|
||||
"PublicKey": "ED96F581FED430E8CBE1F08B37408857001D4118D49FBB594B0BE007C2DBFFD367"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ActiveValidator": {
|
||||
"Account": "r3htgPchiR2r8kMGzPK3Wfv3WTrpaRKjtU",
|
||||
"PublicKey": "EDCF31B8F683345E1C49B4A1D85BF2731E55E7D6781F3D4BF45EE7ADF2D2FB3402"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ActiveValidator": {
|
||||
"Account": "rfQtB8m51sdbWgcmddRX2mMjMpSxzX1AGr",
|
||||
"PublicKey": "EDDF197FC59A7FAA09EB1AD60A4638BA6201DD51497B5C08A1745115098E229E0E"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 0,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ describe('Hash256', function () {
|
||||
|
||||
describe('Currency', function () {
|
||||
test('Decoding allows dodgy XRP without throwing', function () {
|
||||
const currencyCode = '0000000000000000000000005852500000000000'
|
||||
const currencyCode = '0000000000000000000000005841480000000000'
|
||||
expect(Currency.from(currencyCode).toJSON()).toBe(currencyCode)
|
||||
})
|
||||
test('Currency code with lowercase letters decodes to ISO code', () => {
|
||||
@@ -113,7 +113,7 @@ describe('Currency', function () {
|
||||
|
||||
test('can be constructed from a Buffer', function () {
|
||||
const xrp = new Currency(Buffer.alloc(20))
|
||||
expect(xrp.iso()).toBe('XRP')
|
||||
expect(xrp.iso()).toBe('XAH')
|
||||
})
|
||||
test('Can handle non-standard currency codes', () => {
|
||||
const currency = '015841551A748AD2C1F76FF6ECB0CCCD00000000'
|
||||
|
||||
@@ -58,7 +58,7 @@ describe('encoding and decoding tx_json', function () {
|
||||
Sequence: 19,
|
||||
LimitAmount: {
|
||||
value: '200',
|
||||
currency: '0000000000000000000000005852500000000000',
|
||||
currency: '0000000000000000000000005841480000000000',
|
||||
issuer: 'r9hEDb4xBGRfBCcX3E4FirDWQBAYtpxC8K',
|
||||
},
|
||||
Fee: '10',
|
||||
|
||||
25
packages/xrpl-models/package.json
Normal file
25
packages/xrpl-models/package.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "@transia/xahau-models",
|
||||
"version": "2.7.3-alpha.29",
|
||||
"description": "",
|
||||
"private": false,
|
||||
"main": "dist/models/index.js",
|
||||
"files": [
|
||||
"dist/**/*"
|
||||
],
|
||||
"author": {
|
||||
"name": "Denis Angell",
|
||||
"url": "https://github.com/dangell7"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {},
|
||||
"dependencies": {
|
||||
"@types/node": "^20.4.2",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0",
|
||||
"npm": ">=7.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1698,7 +1698,7 @@ __OTHER CHANGES__
|
||||
parseBinary: false
|
||||
}
|
||||
```
|
||||
+ Added full currency name support, e.g. `Currency.from_json('XRP').to_human({full_name:'Ripples'})` will return `XRP - Ripples`
|
||||
+ Added full currency name support, e.g. `Currency.from_json('XAH').to_human({full_name:'Ripples'})` will return `XAH - Ripples`
|
||||
+ Improved interest bearing currency support, e.g. `Currency.from_human('USD - US Dollar (2.5%pa)')`
|
||||
+ Improve test coverage
|
||||
+ Added blob vault client. The vault client facilitates interaction with ripple's namespace and blob vault or 3rd party blob vaults using ripple's blob vault software (https://github.com/ripple/ripple-blobvault). A list of the available functions can be found at [docs/VAULTCLIENT.md](docs/VAULTCLIENT.md)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@transia/xrpl",
|
||||
"version": "2.7.3-alpha.14",
|
||||
"version": "2.7.3-alpha.28",
|
||||
"license": "ISC",
|
||||
"description": "A TypeScript/JavaScript API for interacting with the XRP Ledger in Node.js and the browser",
|
||||
"files": [
|
||||
@@ -23,7 +23,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@transia/ripple-address-codec": "^4.2.8-alpha.0",
|
||||
"@transia/ripple-binary-codec": "^1.4.6-alpha.3",
|
||||
"@transia/ripple-binary-codec": "^1.4.6-alpha.10",
|
||||
"@transia/ripple-keypairs": "^1.1.8-alpha.0",
|
||||
"bignumber.js": "^9.0.0",
|
||||
"bip32": "^2.0.6",
|
||||
@@ -54,6 +54,7 @@
|
||||
"build": "run-s build:lib build:snippets build:web",
|
||||
"build:snippets": "tsc --build ./snippets/tsconfig.json",
|
||||
"build:lib": "tsc --build tsconfig.build.json",
|
||||
"build:models": "tsc --build tsconfig.models.json",
|
||||
"build:web": "webpack",
|
||||
"build:browserTests": "webpack --config ./test/webpack.config.js",
|
||||
"analyze": "run-s build:web --analyze",
|
||||
@@ -80,5 +81,6 @@
|
||||
"readmeFilename": "README.md",
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"gitHead": "3b234ec8ec1c677e0f3f534fd2985c985871c87e"
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ async function createTxWithPaths(): Promise<void> {
|
||||
source_account: wallet.classicAddress,
|
||||
source_currencies: [
|
||||
{
|
||||
currency: 'XRP',
|
||||
currency: 'XAH',
|
||||
},
|
||||
],
|
||||
destination_account,
|
||||
|
||||
@@ -485,10 +485,10 @@ class Wallet {
|
||||
|
||||
if (
|
||||
txCurrency.length === standard_currency_code_len &&
|
||||
txCurrency.toUpperCase() === 'XRP'
|
||||
txCurrency.toUpperCase() === 'XAH'
|
||||
) {
|
||||
throw new XrplError(
|
||||
`Trying to sign an issued currency with a similar standard code to XRP (received '${txCurrency}'). XRP is not an issued currency.`,
|
||||
`Trying to sign an issued currency with a similar standard code to XAH (received '${txCurrency}'). XAH is not an issued currency.`,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -575,7 +575,7 @@ function removeTrailingZeros(tx: Transaction): void {
|
||||
/* eslint-disable @typescript-eslint/no-magic-numbers -- Magic numbers are from rippleds of currency code encoding */
|
||||
function isoToHex(iso: string): string {
|
||||
const bytes = Buffer.alloc(20)
|
||||
if (iso !== 'XRP') {
|
||||
if (iso !== 'XAH') {
|
||||
const isoBytes = iso.split('').map((chr) => chr.charCodeAt(0))
|
||||
bytes.set(isoBytes, 12)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export type LedgerIndex = number | ('validated' | 'closed' | 'current')
|
||||
|
||||
interface XRP {
|
||||
currency: 'XRP'
|
||||
currency: 'XAH'
|
||||
}
|
||||
|
||||
interface IssuedCurrency {
|
||||
@@ -17,6 +17,8 @@ export interface IssuedCurrencyAmount extends IssuedCurrency {
|
||||
|
||||
export type Amount = IssuedCurrencyAmount | string
|
||||
|
||||
export type AmountEntry = Amount
|
||||
|
||||
export interface Signer {
|
||||
Signer: {
|
||||
Account: string
|
||||
@@ -205,3 +207,21 @@ export interface EmitDetails {
|
||||
EmitHookHash: string
|
||||
EmitParentTxnID: string
|
||||
}
|
||||
|
||||
/**
|
||||
* The object that describes the uritoken in MintURIToken.
|
||||
*/
|
||||
export interface MintURIToken {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
URI: string
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Digest?: string
|
||||
/**
|
||||
* The flags that are set on the uritoken.
|
||||
*/
|
||||
Flags?: number
|
||||
}
|
||||
|
||||
@@ -72,6 +72,16 @@ export default interface AccountRoot extends BaseLedgerEntry {
|
||||
* account to each other.
|
||||
*/
|
||||
TransferRate?: number
|
||||
NFTokenMinter?: string
|
||||
MintedNFTokens?: number
|
||||
BurnedNFTokens?: number
|
||||
HookStateCount?: number
|
||||
HookNamespaces?: string[]
|
||||
RewardLgrFirst?: number
|
||||
RewardLgrLast?: number
|
||||
RewardTime?: number
|
||||
RewardAccumulator?: number
|
||||
FirstNFTokenSequence?: number
|
||||
ImportSequence?: string
|
||||
GovernanceFlags?: string
|
||||
GovernanceMarks?: string
|
||||
@@ -136,6 +146,10 @@ export interface AccountRootFlagsInterface {
|
||||
* Disallow incoming Trustlines from other accounts.
|
||||
*/
|
||||
lsfDisallowIncomingTrustline?: boolean
|
||||
/**
|
||||
* Disallow incoming Trustlines from other accounts.
|
||||
*/
|
||||
lsfDisallowIncomingRemit?: boolean
|
||||
}
|
||||
|
||||
export enum AccountRootFlags {
|
||||
@@ -192,4 +206,12 @@ export enum AccountRootFlags {
|
||||
* Disallow incoming Trustlines from other accounts.
|
||||
*/
|
||||
lsfDisallowIncomingTrustline = 0x20000000,
|
||||
/**
|
||||
* The account has issued a URIToken.
|
||||
*/
|
||||
lsfURITokenIssuer = 0x40000000,
|
||||
/**
|
||||
* Disallow incoming Remits from other accounts.
|
||||
*/
|
||||
lsfDisallowIncomingRemit = 0x80000000,
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import BaseLedgerEntry from './BaseLedgerEntry'
|
||||
|
||||
interface ImportVLKey {
|
||||
PublicKey: string
|
||||
Account?: string
|
||||
ImportVLKey: {
|
||||
PublicKey: string
|
||||
Account?: string
|
||||
}
|
||||
}
|
||||
interface ActiveValidators {
|
||||
PublicKey: string
|
||||
Account?: string
|
||||
interface ActiveValidator {
|
||||
ActiveValidator: {
|
||||
PublicKey: string
|
||||
Account?: string
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -24,7 +28,7 @@ export default interface UNLReport extends BaseLedgerEntry {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
ActiveValidators?: ActiveValidators[]
|
||||
ActiveValidators?: ActiveValidator[]
|
||||
/**
|
||||
* The identifying hash of the transaction that most recently modified this
|
||||
* object.
|
||||
|
||||
46
packages/xrpl/src/models/methods/accountNamespace.ts
Normal file
46
packages/xrpl/src/models/methods/accountNamespace.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { HookState } from '../ledger'
|
||||
|
||||
import { BaseRequest, BaseResponse } from './baseMethod'
|
||||
|
||||
/**
|
||||
* The `account_namespace` command retrieves the account namespace. All information retrieved is relative to a
|
||||
* particular version of the ledger. Returns an {@link AccountNamespaceResponse}.
|
||||
*
|
||||
* @category Requests
|
||||
*/
|
||||
export interface AccountNamespaceRequest extends BaseRequest {
|
||||
command: 'account_namespace'
|
||||
/** A unique identifier for the account, most commonly the account's address. */
|
||||
account: string
|
||||
/** The hex namespace. */
|
||||
namespace_id?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Response expected from an {@link AccountNamespaceRequest}.
|
||||
*
|
||||
* @category Responses
|
||||
*/
|
||||
export interface AccountNamespaceResponse extends BaseResponse {
|
||||
result: {
|
||||
/**
|
||||
* The account requested.
|
||||
*/
|
||||
account: string
|
||||
/**
|
||||
* The namespace_id requested.
|
||||
*/
|
||||
namespace_id: string
|
||||
/**
|
||||
* A list of HookStates for the specified account namespace_id.
|
||||
*/
|
||||
namespace_entries: HookState[]
|
||||
/**
|
||||
* The ledger index of the current open ledger, which was used when
|
||||
* retrieving this information.
|
||||
*/
|
||||
ledger_current_index: number
|
||||
/** If true, this data comes from a validated ledger. */
|
||||
validated: boolean
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,10 @@ import {
|
||||
} from './accountCurrencies'
|
||||
import { AccountInfoRequest, AccountInfoResponse } from './accountInfo'
|
||||
import { AccountLinesRequest, AccountLinesResponse } from './accountLines'
|
||||
import {
|
||||
AccountNamespaceRequest,
|
||||
AccountNamespaceResponse,
|
||||
} from './accountNamespace'
|
||||
import { AccountNFTsRequest, AccountNFTsResponse } from './accountNFTs'
|
||||
import { AccountObjectsRequest, AccountObjectsResponse } from './accountObjects'
|
||||
import {
|
||||
@@ -83,6 +87,7 @@ type Request =
|
||||
| AccountCurrenciesRequest
|
||||
| AccountInfoRequest
|
||||
| AccountLinesRequest
|
||||
| AccountNamespaceRequest
|
||||
| AccountNFTsRequest
|
||||
| AccountObjectsRequest
|
||||
| AccountOffersRequest
|
||||
@@ -133,6 +138,7 @@ type Response =
|
||||
| AccountCurrenciesResponse
|
||||
| AccountInfoResponse
|
||||
| AccountLinesResponse
|
||||
| AccountNamespaceResponse
|
||||
| AccountNFTsResponse
|
||||
| AccountObjectsResponse
|
||||
| AccountOffersResponse
|
||||
|
||||
@@ -57,6 +57,8 @@ export enum AccountSetAsfFlags {
|
||||
asfDisallowIncomingPayChan = 14,
|
||||
/** Disallow other accounts from creating incoming Trustlines */
|
||||
asfDisallowIncomingTrustline = 15,
|
||||
/** Disallow other accounts from sending incoming Remits */
|
||||
asfDisallowIncomingRemit = 16,
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
import { ValidationError } from '../../errors'
|
||||
|
||||
import { BaseTransaction, validateBaseTransaction } from './common'
|
||||
/**
|
||||
* Transaction Flags for an ClaimReward Transaction.
|
||||
*
|
||||
* @category Transaction Flags
|
||||
*/
|
||||
export enum ClaimRewardFlags {
|
||||
/**
|
||||
* If set, indicates that the user would like to opt out of rewards.
|
||||
*/
|
||||
tfOptOut = 0x00000001,
|
||||
}
|
||||
|
||||
/**
|
||||
* ClaimReward is a transaction model that allows an account to claim rewards.
|
||||
@@ -9,6 +20,7 @@ import { BaseTransaction, validateBaseTransaction } from './common'
|
||||
*/
|
||||
export interface ClaimReward extends BaseTransaction {
|
||||
TransactionType: 'ClaimReward'
|
||||
Flags?: number | ClaimRewardFlags
|
||||
/** The unique address of the issuer where the reward.c hook is installed. */
|
||||
Issuer?: string
|
||||
}
|
||||
|
||||
@@ -170,6 +170,10 @@ export interface BaseTransaction {
|
||||
* The network id of the transaction.
|
||||
*/
|
||||
NetworkID?: number
|
||||
/**
|
||||
*
|
||||
*/
|
||||
FirstLedgerSequence?: number
|
||||
/**
|
||||
* The hook parameters of the transaction.
|
||||
*/
|
||||
|
||||
@@ -15,7 +15,12 @@ export interface EscrowCancel extends BaseTransaction {
|
||||
* Transaction sequence (or Ticket number) of EscrowCreate transaction that.
|
||||
* created the escrow to cancel.
|
||||
*/
|
||||
OfferSequence: number
|
||||
OfferSequence?: number
|
||||
/**
|
||||
* The ID of the Escrow ledger object to cancel as a 64-character hexadecimal
|
||||
* string.
|
||||
*/
|
||||
EscrowID?: string
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,11 +40,17 @@ export function validateEscrowCancel(tx: Record<string, unknown>): void {
|
||||
throw new ValidationError('EscrowCancel: Owner must be a string')
|
||||
}
|
||||
|
||||
if (tx.OfferSequence === undefined) {
|
||||
throw new ValidationError('EscrowCancel: missing OfferSequence')
|
||||
if (tx.OfferSequence === undefined && tx.EscrowID === undefined) {
|
||||
throw new ValidationError(
|
||||
'EscrowCancel: must include OfferSequence or EscrowID',
|
||||
)
|
||||
}
|
||||
|
||||
if (typeof tx.OfferSequence !== 'number') {
|
||||
throw new ValidationError('EscrowCancel: OfferSequence must be a number')
|
||||
if (tx.OfferSequence !== undefined && typeof tx.OfferSequence !== 'number') {
|
||||
throw new ValidationError('EscrowCancel: invalid OfferSequence')
|
||||
}
|
||||
|
||||
if (tx.EscrowID !== undefined && typeof tx.EscrowID !== 'string') {
|
||||
throw new ValidationError('EscrowCancel: invalid EscrowID')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,8 +44,9 @@ export {
|
||||
} from './paymentChannelClaim'
|
||||
export { PaymentChannelCreate } from './paymentChannelCreate'
|
||||
export { PaymentChannelFund } from './paymentChannelFund'
|
||||
export { SetRegularKey } from './setRegularKey'
|
||||
export { Remit } from './remit'
|
||||
export { SetHookFlagsInterface, SetHookFlags, SetHook } from './setHook'
|
||||
export { SetRegularKey } from './setRegularKey'
|
||||
export { SignerListSet } from './signerListSet'
|
||||
export { TicketCreate } from './ticketCreate'
|
||||
export { TrustSetFlagsInterface, TrustSetFlags, TrustSet } from './trustSet'
|
||||
|
||||
@@ -11,6 +11,16 @@ export interface HookExecution {
|
||||
HookReturnCode: string
|
||||
HookReturnString: string
|
||||
HookStateChangeCount: number
|
||||
Flags: number
|
||||
}
|
||||
}
|
||||
|
||||
export interface HookEmission {
|
||||
HookEmission: {
|
||||
EmittedTxnID: string
|
||||
HookAccount: string
|
||||
HookHash: string
|
||||
EmitNonce: string
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +85,7 @@ export function isDeletedNode(node: Node): node is DeletedNode {
|
||||
|
||||
export interface TransactionMetadata {
|
||||
HookExecutions?: HookExecution[]
|
||||
HookEmissions?: HookEmission[]
|
||||
AffectedNodes: Node[]
|
||||
DeliveredAmount?: Amount
|
||||
// "unavailable" possible for transactions before 2014-01-20
|
||||
|
||||
@@ -15,7 +15,12 @@ export interface OfferCancel extends BaseTransaction {
|
||||
* created by that transaction. It is not considered an error if the offer.
|
||||
* specified does not exist.
|
||||
*/
|
||||
OfferSequence: number
|
||||
OfferSequence?: number
|
||||
/**
|
||||
* The ID of the Escrow ledger object to cancel as a 64-character hexadecimal
|
||||
* string.
|
||||
*/
|
||||
OfferID?: string
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -27,11 +32,17 @@ export interface OfferCancel extends BaseTransaction {
|
||||
export function validateOfferCancel(tx: Record<string, unknown>): void {
|
||||
validateBaseTransaction(tx)
|
||||
|
||||
if (tx.OfferSequence === undefined) {
|
||||
throw new ValidationError('OfferCancel: missing field OfferSequence')
|
||||
if (tx.OfferSequence === undefined && tx.OfferID === undefined) {
|
||||
throw new ValidationError(
|
||||
'OfferCancel: must include OfferSequence or OfferID',
|
||||
)
|
||||
}
|
||||
|
||||
if (typeof tx.OfferSequence !== 'number') {
|
||||
throw new ValidationError('OfferCancel: OfferSequence must be a number')
|
||||
if (tx.OfferSequence !== undefined && typeof tx.OfferSequence !== 'number') {
|
||||
throw new ValidationError('OfferCancel: invalid OfferSequence')
|
||||
}
|
||||
|
||||
if (tx.OfferID !== undefined && typeof tx.OfferID !== 'string') {
|
||||
throw new ValidationError('OfferCancel: invalid OfferID')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,11 @@ export interface OfferCreate extends BaseTransaction {
|
||||
Expiration?: number
|
||||
/** An offer to delete first, specified in the same way as OfferCancel. */
|
||||
OfferSequence?: number
|
||||
/**
|
||||
* The ID of the Offer ledger object to cancel as a 64-character hexadecimal
|
||||
* string.
|
||||
*/
|
||||
OfferID?: string
|
||||
/** The amount and type of currency being provided by the offer creator. */
|
||||
TakerGets: Amount
|
||||
/** The amount and type of currency being requested by the offer creator. */
|
||||
@@ -141,4 +146,8 @@ export function validateOfferCreate(tx: Record<string, unknown>): void {
|
||||
if (tx.OfferSequence !== undefined && typeof tx.OfferSequence !== 'number') {
|
||||
throw new ValidationError('OfferCreate: invalid OfferSequence')
|
||||
}
|
||||
|
||||
if (tx.OfferID !== undefined && typeof tx.OfferID !== 'string') {
|
||||
throw new ValidationError('OfferCreate: invalid OfferID')
|
||||
}
|
||||
}
|
||||
|
||||
204
packages/xrpl/src/models/transactions/remit.ts
Normal file
204
packages/xrpl/src/models/transactions/remit.ts
Normal file
@@ -0,0 +1,204 @@
|
||||
import { ValidationError } from '../../errors'
|
||||
import { AmountEntry, MintURIToken } from '../common'
|
||||
import { isHex } from '../utils'
|
||||
|
||||
import { BaseTransaction, validateBaseTransaction } from './common'
|
||||
|
||||
const MAX_URI_LENGTH = 512
|
||||
const DIGEST_LENGTH = 64
|
||||
const MAX_ARRAY_LENGTH = 32
|
||||
const MAX_BLOB_LENGTH = 1024
|
||||
|
||||
/**
|
||||
* A Remit transaction represents a transfer of value from one account to
|
||||
* another.
|
||||
*
|
||||
* @category Transaction Models
|
||||
*/
|
||||
export interface Remit extends BaseTransaction {
|
||||
TransactionType: 'Remit'
|
||||
/** The unique address of the account receiving the payment. */
|
||||
Destination: string
|
||||
/**
|
||||
* Arbitrary tag that identifies the reason for the payment to the
|
||||
* destination, or a hosted recipient to pay.
|
||||
*/
|
||||
DestinationTag?: number
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Amounts?: AmountEntry[]
|
||||
/**
|
||||
*
|
||||
*/
|
||||
MintURIToken?: MintURIToken
|
||||
/**
|
||||
*
|
||||
*/
|
||||
URITokenIDs?: string[]
|
||||
/**
|
||||
* Arbitrary 256-bit hash representing a specific reason or identifier for
|
||||
* this payment.
|
||||
*/
|
||||
InvoiceID?: string
|
||||
/**
|
||||
* Hex value representing a VL Blob.
|
||||
*/
|
||||
Blob?: string
|
||||
/** The unique address of the account to inform */
|
||||
Inform?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the form and type of a Remit at runtime.
|
||||
*
|
||||
* @param tx - A Remit Transaction.
|
||||
* @throws When the Remit is malformed.
|
||||
*/
|
||||
// eslint-disable-next-line complexity -- ignore
|
||||
export function validateRemit(tx: Record<string, unknown>): void {
|
||||
validateBaseTransaction(tx)
|
||||
|
||||
if (tx.Amounts !== undefined) {
|
||||
checkAmounts(tx)
|
||||
}
|
||||
if (tx.URITokenIDs !== undefined) {
|
||||
checkURITokenIDs(tx)
|
||||
}
|
||||
if (tx.Destination === tx.Account) {
|
||||
throw new ValidationError(
|
||||
'Remit: Destination must not be equal to the account',
|
||||
)
|
||||
}
|
||||
if (tx.DestinationTag != null && typeof tx.DestinationTag !== 'number') {
|
||||
throw new ValidationError('Remit: DestinationTag must be a number')
|
||||
}
|
||||
if (tx.Inform === tx.Account || tx.Inform === tx.Destination) {
|
||||
throw new ValidationError(
|
||||
'Remit: Inform must not be equal to the account or destination',
|
||||
)
|
||||
}
|
||||
|
||||
if (tx.MintURIToken !== undefined) {
|
||||
checkMintURIToken(tx)
|
||||
}
|
||||
|
||||
if (tx.Blob !== undefined && typeof tx.Blob !== 'string') {
|
||||
throw new ValidationError('Remit: Blob must be a string')
|
||||
}
|
||||
|
||||
if (tx.Blob !== undefined && typeof tx.Blob === 'string') {
|
||||
if (!isHex(tx.Blob)) {
|
||||
throw new ValidationError('Remit: Blob must be a hex string')
|
||||
}
|
||||
if (tx.Blob.length > MAX_BLOB_LENGTH) {
|
||||
throw new ValidationError('Remit: max size Blob')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkAmounts(tx: Record<string, unknown>): void {
|
||||
if (!Array.isArray(tx.Amounts)) {
|
||||
throw new ValidationError('Remit: Amounts must be an array')
|
||||
}
|
||||
if (tx.Amounts.length < 1) {
|
||||
throw new ValidationError('Remit: empty field Amounts')
|
||||
}
|
||||
if (tx.Amounts.length > MAX_ARRAY_LENGTH) {
|
||||
throw new ValidationError('Remit: max field Amounts')
|
||||
}
|
||||
const seen = new Set<string>()
|
||||
let seenXrp = false
|
||||
for (const amount of tx.Amounts) {
|
||||
if (
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- ignore
|
||||
amount.AmountEntry === undefined ||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- ignore
|
||||
typeof amount.AmountEntry !== 'object'
|
||||
) {
|
||||
throw new ValidationError('Remit: invalid Amounts.AmountEntry')
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- ignore
|
||||
if (typeof amount.AmountEntry.Amount === 'string') {
|
||||
// eslint-disable-next-line max-depth -- ignore
|
||||
if (seenXrp) {
|
||||
throw new ValidationError(
|
||||
'Remit: Duplicate Native amounts are not allowed',
|
||||
)
|
||||
}
|
||||
seenXrp = true
|
||||
} else {
|
||||
// eslint-disable-next-line max-len -- ignore
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-member-access -- ignore
|
||||
const amountKey = `${amount.AmountEntry.Amount.currency}:${amount.AmountEntry.Amount.issuer}`
|
||||
// eslint-disable-next-line max-depth -- ingore
|
||||
if (seen.has(amountKey)) {
|
||||
throw new ValidationError('Remit: Duplicate amounts are not allowed')
|
||||
}
|
||||
seen.add(amountKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkURITokenIDs(tx: Record<string, unknown>): void {
|
||||
if (!Array.isArray(tx.URITokenIDs)) {
|
||||
throw new ValidationError('Remit: invalid field URITokenIDs')
|
||||
}
|
||||
if (tx.URITokenIDs.length < 1) {
|
||||
throw new ValidationError('Remit: empty field URITokenIDs')
|
||||
}
|
||||
if (tx.URITokenIDs.length > MAX_ARRAY_LENGTH) {
|
||||
throw new ValidationError('Remit: max field URITokenIDs')
|
||||
}
|
||||
const seen = new Set<string>()
|
||||
for (const token of tx.URITokenIDs) {
|
||||
if (typeof token !== 'string' || !isHex(token)) {
|
||||
throw new ValidationError('Remit: URITokenID must be a hex string')
|
||||
}
|
||||
if (token.length !== DIGEST_LENGTH) {
|
||||
throw new ValidationError(
|
||||
`Remit: URITokenID must be exactly ${DIGEST_LENGTH} characters`,
|
||||
)
|
||||
}
|
||||
if (seen.has(token)) {
|
||||
throw new ValidationError('Remit: Duplicate URITokens are not allowed')
|
||||
}
|
||||
seen.add(token)
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line complexity -- ignore
|
||||
function checkMintURIToken(tx: Record<string, unknown>): void {
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return value !== null && typeof value === 'object'
|
||||
}
|
||||
if (!isRecord(tx.MintURIToken)) {
|
||||
throw new ValidationError('Remit: invalid MintURIToken')
|
||||
}
|
||||
if (tx.MintURIToken.URI === undefined) {
|
||||
throw new ValidationError('Remit: missing field MintURIToken.URI')
|
||||
}
|
||||
if (typeof tx.MintURIToken.URI !== 'string' || !isHex(tx.MintURIToken.URI)) {
|
||||
throw new ValidationError('Remit: MintURIToken.URI must be a hex string')
|
||||
}
|
||||
if (tx.MintURIToken.URI.length > MAX_URI_LENGTH) {
|
||||
throw new ValidationError(
|
||||
`Remit: URI must be less than ${MAX_URI_LENGTH} characters`,
|
||||
)
|
||||
}
|
||||
if (
|
||||
tx.MintURIToken.Digest !== undefined &&
|
||||
typeof tx.MintURIToken.Digest !== 'string'
|
||||
) {
|
||||
throw new ValidationError(`Remit: MintURIToken.Digest must be a string`)
|
||||
}
|
||||
if (
|
||||
tx.MintURIToken.Digest !== undefined &&
|
||||
!isHex(tx.MintURIToken.Digest) &&
|
||||
tx.MintURIToken.Digest.length !== DIGEST_LENGTH
|
||||
) {
|
||||
throw new ValidationError(
|
||||
`Remit: Digest must be exactly ${DIGEST_LENGTH} characters`,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ import {
|
||||
PaymentChannelFund,
|
||||
validatePaymentChannelFund,
|
||||
} from './paymentChannelFund'
|
||||
import { Remit, validateRemit } from './remit'
|
||||
import { SetHook, validateSetHook } from './setHook'
|
||||
import { SetRegularKey, validateSetRegularKey } from './setRegularKey'
|
||||
import { SignerListSet, validateSignerListSet } from './signerListSet'
|
||||
@@ -90,6 +91,7 @@ export type Transaction =
|
||||
| PaymentChannelClaim
|
||||
| PaymentChannelCreate
|
||||
| PaymentChannelFund
|
||||
| Remit
|
||||
| SetHook
|
||||
| SetRegularKey
|
||||
| SignerListSet
|
||||
@@ -220,14 +222,18 @@ export function validate(transaction: Record<string, unknown>): void {
|
||||
validatePaymentChannelFund(tx)
|
||||
break
|
||||
|
||||
case 'SetRegularKey':
|
||||
validateSetRegularKey(tx)
|
||||
case 'Remit':
|
||||
validateRemit(tx)
|
||||
break
|
||||
|
||||
case 'SetHook':
|
||||
validateSetHook(tx)
|
||||
break
|
||||
|
||||
case 'SetRegularKey':
|
||||
validateSetRegularKey(tx)
|
||||
break
|
||||
|
||||
case 'SignerListSet':
|
||||
validateSignerListSet(tx)
|
||||
break
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ValidationError } from '../../errors'
|
||||
import { Amount } from '../common'
|
||||
import { isHex } from '../utils'
|
||||
|
||||
import { BaseTransaction, GlobalFlags, validateBaseTransaction } from './common'
|
||||
@@ -74,6 +75,23 @@ export interface URITokenMint extends BaseTransaction {
|
||||
*/
|
||||
URI: string
|
||||
|
||||
/**
|
||||
* Indicates the amount expected or offered for the Token.
|
||||
*
|
||||
* The amount must be non-zero, except when this is a sell
|
||||
* offer and the asset is XRP. This would indicate that the current
|
||||
* owner of the token is giving it away free, either to anyone at all,
|
||||
* or to the account identified by the Destination field.
|
||||
*/
|
||||
Amount?: Amount
|
||||
|
||||
/**
|
||||
* If present, indicates that this offer may only be
|
||||
* accepted by the specified account. Attempts by other
|
||||
* accounts to accept this offer MUST fail.
|
||||
*/
|
||||
Destination?: string
|
||||
|
||||
Digest?: string
|
||||
}
|
||||
|
||||
|
||||
@@ -2,16 +2,15 @@ import {
|
||||
xAddressToClassicAddress,
|
||||
isValidXAddress,
|
||||
} from '@transia/ripple-address-codec'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { encode } from '@transia/ripple-binary-codec'
|
||||
|
||||
import type { Client } from '..'
|
||||
import { ValidationError, XrplError } from '../errors'
|
||||
import { AccountInfoRequest, AccountObjectsRequest } from '../models/methods'
|
||||
import { Transaction } from '../models/transactions'
|
||||
import { setTransactionFlagsToNumber } from '../models/utils/flags'
|
||||
import { xrpToDrops } from '../utils'
|
||||
|
||||
import { getFeeXrp } from './getFeeXrp'
|
||||
import { getFeeEstimateXrp } from './getFeeXrp'
|
||||
|
||||
// Expire unconfirmed transactions after 20 ledger versions, approximately 1 minute, by default
|
||||
const LEDGER_OFFSET = 20
|
||||
@@ -50,17 +49,18 @@ async function autofill<T extends Transaction>(
|
||||
if (tx.Sequence == null) {
|
||||
promises.push(setNextValidSequenceNumber(this, tx))
|
||||
}
|
||||
if (tx.Fee == null) {
|
||||
promises.push(calculateFeePerTransactionType(this, tx, signersCount))
|
||||
}
|
||||
if (tx.LastLedgerSequence == null) {
|
||||
promises.push(setLatestValidatedLedgerSequence(this, tx))
|
||||
}
|
||||
if (tx.TransactionType === 'AccountDelete') {
|
||||
promises.push(checkAccountDeleteBlockers(this, tx))
|
||||
}
|
||||
await Promise.all(promises).then(() => tx)
|
||||
|
||||
return Promise.all(promises).then(() => tx)
|
||||
if (tx.Fee == null) {
|
||||
await calculateFeePerTransactionType(this, tx, signersCount)
|
||||
}
|
||||
return tx
|
||||
}
|
||||
|
||||
function setValidAddresses(tx: Transaction): void {
|
||||
@@ -146,64 +146,17 @@ async function setNextValidSequenceNumber(
|
||||
tx.Sequence = data.result.account_data.Sequence
|
||||
}
|
||||
|
||||
async function fetchAccountDeleteFee(client: Client): Promise<BigNumber> {
|
||||
const response = await client.request({ command: 'server_state' })
|
||||
const fee = response.result.state.validated_ledger?.reserve_inc
|
||||
|
||||
if (fee == null) {
|
||||
return Promise.reject(new Error('Could not fetch Owner Reserve.'))
|
||||
}
|
||||
|
||||
return new BigNumber(fee)
|
||||
}
|
||||
|
||||
async function calculateFeePerTransactionType(
|
||||
client: Client,
|
||||
tx: Transaction,
|
||||
signersCount = 0,
|
||||
): Promise<void> {
|
||||
// netFee is usually 0.00001 XRP (10 drops)
|
||||
const netFeeXRP = await getFeeXrp(client)
|
||||
const netFeeDrops = xrpToDrops(netFeeXRP)
|
||||
let baseFee = new BigNumber(netFeeDrops)
|
||||
|
||||
// EscrowFinish Transaction with Fulfillment
|
||||
if (tx.TransactionType === 'EscrowFinish' && tx.Fulfillment != null) {
|
||||
const fulfillmentBytesSize: number = Math.ceil(tx.Fulfillment.length / 2)
|
||||
// 10 drops × (33 + (Fulfillment size in bytes / 16))
|
||||
const product = new BigNumber(
|
||||
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- expected use of magic numbers
|
||||
scaleValue(netFeeDrops, 33 + fulfillmentBytesSize / 16),
|
||||
)
|
||||
baseFee = product.dp(0, BigNumber.ROUND_CEIL)
|
||||
}
|
||||
|
||||
// AccountDelete Transaction
|
||||
if (tx.TransactionType === 'AccountDelete') {
|
||||
baseFee = await fetchAccountDeleteFee(client)
|
||||
}
|
||||
|
||||
/*
|
||||
* Multi-signed Transaction
|
||||
* 10 drops × (1 + Number of Signatures Provided)
|
||||
*/
|
||||
if (signersCount > 0) {
|
||||
baseFee = BigNumber.sum(baseFee, scaleValue(netFeeDrops, 1 + signersCount))
|
||||
}
|
||||
|
||||
const maxFeeDrops = xrpToDrops(client.maxFeeXRP)
|
||||
const totalFee =
|
||||
tx.TransactionType === 'AccountDelete'
|
||||
? baseFee
|
||||
: BigNumber.min(baseFee, maxFeeDrops)
|
||||
|
||||
// Round up baseFee and return it as a string
|
||||
// eslint-disable-next-line no-param-reassign, @typescript-eslint/no-magic-numbers -- param reassign is safe, base 10 magic num
|
||||
tx.Fee = totalFee.dp(0, BigNumber.ROUND_CEIL).toString(10)
|
||||
}
|
||||
|
||||
function scaleValue(value, multiplier): string {
|
||||
return new BigNumber(value).times(multiplier).toString()
|
||||
const copyTx = { ...tx }
|
||||
copyTx.SigningPubKey = ``
|
||||
copyTx.Fee = `0`
|
||||
const tx_blob = encode(copyTx)
|
||||
// eslint-disable-next-line require-atomic-updates, no-param-reassign -- ignore
|
||||
tx.Fee = await getFeeEstimateXrp(client, tx_blob, signersCount)
|
||||
}
|
||||
|
||||
async function setLatestValidatedLedgerSequence(
|
||||
|
||||
@@ -115,7 +115,7 @@ async function getBalances(
|
||||
formatBalances(response.result.lines),
|
||||
)
|
||||
if (xrpBalance !== '') {
|
||||
balances.push({ currency: 'XRP', value: xrpBalance })
|
||||
balances.push({ currency: 'XAH', value: xrpBalance })
|
||||
}
|
||||
balances.push(...accountLinesBalance)
|
||||
},
|
||||
|
||||
@@ -50,15 +50,20 @@ export async function getFeeXrp(
|
||||
*
|
||||
* @param client - The Client used to connect to the ledger.
|
||||
* @param txBlob - The encoded transaction to estimate the fee for.
|
||||
* @param signersCount - The number of multisigners.
|
||||
* @returns The transaction fee.
|
||||
*/
|
||||
export async function getFeeEstimateXrp(
|
||||
client: Client,
|
||||
txBlob: string,
|
||||
signersCount = 0,
|
||||
): Promise<string> {
|
||||
const response = await client.request({
|
||||
command: 'fee',
|
||||
tx_blob: txBlob,
|
||||
})
|
||||
return response.result.drops.base_fee
|
||||
const openLedgerFee = response.result.drops.open_ledger_fee
|
||||
const baseFee = new BigNumber(response.result.drops.base_fee)
|
||||
const totalFee = BigNumber.sum(openLedgerFee, Number(baseFee) * signersCount)
|
||||
return new BigNumber(totalFee.toFixed(NUM_DECIMAL_PLACES)).toString(BASE_10)
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ function getXRPQuantity(
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- okay here
|
||||
account: (node.FinalFields?.Account ?? node.NewFields?.Account) as string,
|
||||
balance: {
|
||||
currency: 'XRP',
|
||||
currency: 'XAH',
|
||||
value: dropsToXrp(value).toString(),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
"issuer": "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw"
|
||||
},
|
||||
"takerGets": {
|
||||
"currency": "XRP"
|
||||
"currency": "XAH"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[
|
||||
{
|
||||
"value": "922.913243",
|
||||
"currency": "XRP"
|
||||
"currency": "XAH"
|
||||
},
|
||||
{
|
||||
"value": "0",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -25,7 +25,7 @@ describe('book_offers', function () {
|
||||
const bookOffer: BookOffersRequest = {
|
||||
command: 'book_offers',
|
||||
taker_gets: {
|
||||
currency: 'XRP',
|
||||
currency: 'XAH',
|
||||
},
|
||||
taker_pays: {
|
||||
currency: 'USD',
|
||||
|
||||
369
packages/xrpl/test/models/remit.test.ts
Normal file
369
packages/xrpl/test/models/remit.test.ts
Normal file
@@ -0,0 +1,369 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { validate, ValidationError } from '../../src'
|
||||
import { validateRemit } from '../../src/models/transactions/remit'
|
||||
|
||||
/**
|
||||
* Remit Verification Testing.
|
||||
*
|
||||
* Providing runtime verification testing for each specific transaction type.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line max-statements -- ignore
|
||||
describe('Remit', function () {
|
||||
let remit
|
||||
|
||||
beforeEach(function () {
|
||||
remit = {
|
||||
TransactionType: 'Remit',
|
||||
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
Destination: 'rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy',
|
||||
DestinationTag: 1,
|
||||
Fee: '12',
|
||||
Flags: 0,
|
||||
LastLedgerSequence: 65953073,
|
||||
Sequence: 65923914,
|
||||
SigningPubKey:
|
||||
'02F9E33F16DF9507705EC954E3F94EB5F10D1FC4A354606DBE6297DBB1096FE654',
|
||||
TxnSignature:
|
||||
'3045022100E3FAE0EDEC3D6A8FF6D81BC9CF8288A61B7EEDE8071E90FF9314CB4621058D10022043545CF631706D700CEE65A1DB83EFDD185413808292D9D90F14D87D3DC2D8CB',
|
||||
Amounts: [
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{
|
||||
AmountEntry: {
|
||||
Amount: {
|
||||
currency: 'USD',
|
||||
issuer: 'rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX',
|
||||
value: '1',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
MintURIToken: {
|
||||
URI: 'DEADBEEF',
|
||||
Digest:
|
||||
'6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B',
|
||||
Flags: 1,
|
||||
},
|
||||
URITokenIDs: [
|
||||
'AED08CC1F50DD5F23A1948AF86153A3F3B7593E5EC77D65A02BB1B29E05AB6AE',
|
||||
],
|
||||
InvoiceID:
|
||||
'6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B',
|
||||
Blob: 'DEADBEEF',
|
||||
Inform: 'rB5Ux4Lv2nRx6eeoAAsZmtctnBQ2LiACnk',
|
||||
} as any
|
||||
})
|
||||
|
||||
it(`verifies valid Remit`, function () {
|
||||
assert.doesNotThrow(() => validateRemit(remit))
|
||||
assert.doesNotThrow(() => validate(remit))
|
||||
})
|
||||
|
||||
it(`throws w/ Bad Amounts`, function () {
|
||||
remit.Amounts = {}
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: Amounts must be an array',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Empty Amounts`, function () {
|
||||
remit.Amounts = []
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: empty field Amounts',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Max Amounts`, function () {
|
||||
remit.Amounts = [
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
]
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: max field Amounts',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Duplicate native amounts`, function () {
|
||||
remit.Amounts = [
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
{ AmountEntry: { Amount: '1000' } },
|
||||
]
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: Duplicate Native amounts are not allowed',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Duplicate amounts`, function () {
|
||||
remit.Amounts = [
|
||||
{
|
||||
AmountEntry: {
|
||||
Amount: {
|
||||
currency: 'USD',
|
||||
issuer: 'rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX',
|
||||
value: '1',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
AmountEntry: {
|
||||
Amount: {
|
||||
currency: 'USD',
|
||||
issuer: 'rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX',
|
||||
value: '1',
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: Duplicate amounts are not allowed',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Bad URITokenIDs`, function () {
|
||||
remit.URITokenIDs = {}
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: invalid field URITokenIDs',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Empty URITokenIDs`, function () {
|
||||
remit.URITokenIDs = []
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: empty field URITokenIDs',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Empty URITokenIDs`, function () {
|
||||
remit.URITokenIDs = [
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
'DEADBEEF',
|
||||
]
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: max field URITokenIDs',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Invalid URITokenID`, function () {
|
||||
remit.URITokenIDs = [1]
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: URITokenID must be a hex string',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Invalid URITokenID`, function () {
|
||||
remit.URITokenIDs = ['ZZ11']
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: URITokenID must be a hex string',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Duplicate URITokenIDs`, function () {
|
||||
remit.URITokenIDs = ['DEADBEEF']
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: URITokenID must be exactly 64 characters',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Duplicate URITokenIDs`, function () {
|
||||
remit.URITokenIDs = [
|
||||
'AED08CC1F50DD5F23A1948AF86153A3F3B7593E5EC77D65A02BB1B29E05AB6AE',
|
||||
'AED08CC1F50DD5F23A1948AF86153A3F3B7593E5EC77D65A02BB1B29E05AB6AE',
|
||||
]
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: Duplicate URITokens are not allowed',
|
||||
)
|
||||
})
|
||||
// it(`throws w/ Bad MintURIToken`, function () {
|
||||
// remit.MintURIToken = []
|
||||
// assert.throws(
|
||||
// () => validateRemit(remit),
|
||||
// ValidationError,
|
||||
// 'Remit: invalid MintURIToken',
|
||||
// )
|
||||
// })
|
||||
it(`throws w/ Missing MintURIToken.URI`, function () {
|
||||
remit.MintURIToken = {}
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: missing field MintURIToken.URI',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Bad MintURIToken.URI`, function () {
|
||||
remit.MintURIToken = {
|
||||
URI: 1,
|
||||
}
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: MintURIToken.URI must be a hex string',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Bad MintURIToken.URI`, function () {
|
||||
remit.MintURIToken = {
|
||||
URI: 'ZZ11',
|
||||
}
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: MintURIToken.URI must be a hex string',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Bad MintURIToken Less than 1`, function () {
|
||||
remit.MintURIToken = {
|
||||
URI: '',
|
||||
}
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: MintURIToken.URI must be a hex string',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Bad MintURIToken.Digest`, function () {
|
||||
remit.MintURIToken = {
|
||||
URI: 'DEADBEEF',
|
||||
Digest: 1,
|
||||
}
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: MintURIToken.Digest must be a string',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Bad MintURIToken.Digest`, function () {
|
||||
remit.MintURIToken = {
|
||||
URI: 'DEADBEEF',
|
||||
Digest: 'ZZ11',
|
||||
}
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: Digest must be exactly 64 characters',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Bad Destination`, function () {
|
||||
remit.Destination = 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo'
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: Destination must not be equal to the account',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Bad Destination Tag`, function () {
|
||||
remit.DestinationTag = '1'
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: DestinationTag must be a number',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Bad Inform`, function () {
|
||||
remit.Inform = 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo'
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: Inform must not be equal to the account or destination',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Bad Blob Type`, function () {
|
||||
remit.Blob = 1
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: Blob must be a string',
|
||||
)
|
||||
})
|
||||
it(`throws w/ Bad Blob Not Hex`, function () {
|
||||
remit.Blob = 'ZZ11'
|
||||
assert.throws(
|
||||
() => validateRemit(remit),
|
||||
ValidationError,
|
||||
'Remit: Blob must be a hex string',
|
||||
)
|
||||
})
|
||||
// it(`throws w/ Bad Blob Max Size`, function () {
|
||||
// remit.Blob = ''
|
||||
// assert.throws(
|
||||
// () => validateRemit(remit),
|
||||
// ValidationError,
|
||||
// 'Remit: Blob must be a hex string',
|
||||
// )
|
||||
// })
|
||||
})
|
||||
@@ -16,7 +16,7 @@ describe('TrustSet', function () {
|
||||
TransactionType: 'TrustSet',
|
||||
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
LimitAmount: {
|
||||
currency: 'XRP',
|
||||
currency: 'XAH',
|
||||
issuer: 'rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX',
|
||||
value: '4329.23',
|
||||
},
|
||||
|
||||
@@ -118,7 +118,7 @@ describe('Models Utils', function () {
|
||||
TransactionType: 'TrustSet',
|
||||
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||
LimitAmount: {
|
||||
currency: 'XRP',
|
||||
currency: 'XAH',
|
||||
issuer: 'rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX',
|
||||
value: '4329.23',
|
||||
},
|
||||
@@ -166,7 +166,8 @@ describe('Models Utils', function () {
|
||||
AccountRootFlags.lsfDisallowIncomingNFTokenOffer |
|
||||
AccountRootFlags.lsfDisallowIncomingCheck |
|
||||
AccountRootFlags.lsfDisallowIncomingPayChan |
|
||||
AccountRootFlags.lsfDisallowIncomingTrustline
|
||||
AccountRootFlags.lsfDisallowIncomingTrustline |
|
||||
AccountRootFlags.lsfDisallowIncomingRemit
|
||||
|
||||
const parsed = parseAccountRootFlags(accountRootFlags)
|
||||
|
||||
@@ -183,7 +184,8 @@ describe('Models Utils', function () {
|
||||
parsed.lsfDisallowIncomingNFTokenOffer &&
|
||||
parsed.lsfDisallowIncomingCheck &&
|
||||
parsed.lsfDisallowIncomingPayChan &&
|
||||
parsed.lsfDisallowIncomingTrustline,
|
||||
parsed.lsfDisallowIncomingTrustline &&
|
||||
parsed.lsfDisallowIncomingRemit,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -203,6 +205,7 @@ describe('Models Utils', function () {
|
||||
assert.isUndefined(parsed.lsfDisallowIncomingCheck)
|
||||
assert.isUndefined(parsed.lsfDisallowIncomingPayChan)
|
||||
assert.isUndefined(parsed.lsfDisallowIncomingTrustline)
|
||||
assert.isUndefined(parsed.lsfDisallowIncomingRemit)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -15,16 +15,16 @@ import trustlineSetLimit2 from '../fixtures/utils/trustlineSetLimit2.json'
|
||||
import trustlineSetLimitZero from '../fixtures/utils/trustlineSetLimitZero.json'
|
||||
|
||||
describe('getBalanceChanges', function () {
|
||||
it('XRP create account', function () {
|
||||
it('XAH create account', function () {
|
||||
const result = getBalanceChanges(paymentXrpCreateAccount.metadata)
|
||||
const expected = [
|
||||
{
|
||||
account: 'rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K',
|
||||
balances: [{ currency: 'XRP', value: '100' }],
|
||||
balances: [{ currency: 'XAH', value: '100' }],
|
||||
},
|
||||
{
|
||||
account: 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc',
|
||||
balances: [{ currency: 'XRP', value: '-100.012' }],
|
||||
balances: [{ currency: 'XAH', value: '-100.012' }],
|
||||
},
|
||||
]
|
||||
assert.deepStrictEqual(result, expected)
|
||||
@@ -43,7 +43,7 @@ describe('getBalanceChanges', function () {
|
||||
},
|
||||
{
|
||||
value: '-0.012',
|
||||
currency: 'XRP',
|
||||
currency: 'XAH',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -114,7 +114,7 @@ describe('getBalanceChanges', function () {
|
||||
},
|
||||
{
|
||||
value: '-0.012',
|
||||
currency: 'XRP',
|
||||
currency: 'XAH',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -136,7 +136,7 @@ describe('getBalanceChanges', function () {
|
||||
},
|
||||
{
|
||||
value: '-0.012',
|
||||
currency: 'XRP',
|
||||
currency: 'XAH',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -177,7 +177,7 @@ describe('getBalanceChanges', function () {
|
||||
balances: [
|
||||
{
|
||||
value: '-0.012',
|
||||
currency: 'XRP',
|
||||
currency: 'XAH',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -197,7 +197,7 @@ describe('getBalanceChanges', function () {
|
||||
value: '10',
|
||||
},
|
||||
{
|
||||
currency: 'XRP',
|
||||
currency: 'XAH',
|
||||
value: '-0.012',
|
||||
},
|
||||
],
|
||||
@@ -224,7 +224,7 @@ describe('getBalanceChanges', function () {
|
||||
balances: [
|
||||
{
|
||||
value: '-0.012',
|
||||
currency: 'XRP',
|
||||
currency: 'XAH',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -239,7 +239,7 @@ describe('getBalanceChanges', function () {
|
||||
account: 'rsApBGKJmMfExxZBrGnzxEXyq7TMhMRg4e',
|
||||
balances: [
|
||||
{
|
||||
currency: 'XRP',
|
||||
currency: 'XAH',
|
||||
value: '-0.00001',
|
||||
},
|
||||
],
|
||||
@@ -286,7 +286,7 @@ describe('getBalanceChanges', function () {
|
||||
},
|
||||
{
|
||||
value: '-0.012',
|
||||
currency: 'XRP',
|
||||
currency: 'XAH',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -316,7 +316,7 @@ describe('getBalanceChanges', function () {
|
||||
value: '-100',
|
||||
},
|
||||
{
|
||||
currency: 'XRP',
|
||||
currency: 'XAH',
|
||||
value: '-0.00001',
|
||||
},
|
||||
],
|
||||
@@ -347,7 +347,7 @@ describe('getBalanceChanges', function () {
|
||||
value: '-200',
|
||||
},
|
||||
{
|
||||
currency: 'XRP',
|
||||
currency: 'XAH',
|
||||
value: '-0.00001',
|
||||
},
|
||||
],
|
||||
@@ -383,7 +383,7 @@ describe('getBalanceChanges', function () {
|
||||
value: '-100',
|
||||
},
|
||||
{
|
||||
currency: 'XRP',
|
||||
currency: 'XAH',
|
||||
value: '-0.00001',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -757,13 +757,13 @@ describe('Wallet', function () {
|
||||
it('sign throws when a payment contains an issued currency like XRP', async function () {
|
||||
const payment: Payment = { ...issuedCurrencyPayment }
|
||||
payment.Amount = {
|
||||
currency: 'xrp',
|
||||
currency: 'xah',
|
||||
issuer: 'rnURbz5HLbvqEq69b1B4TX6cUTNMmcrBqi',
|
||||
value: '123.40',
|
||||
}
|
||||
assert.throws(() => {
|
||||
wallet.sign(payment)
|
||||
}, /^Trying to sign an issued currency with a similar standard code to XRP \(received 'xrp'\)\. XRP is not an issued currency\./u)
|
||||
}, /^Trying to sign an issued currency with a similar standard code to XAH \(received 'xah'\)\. XAH is not an issued currency\./u)
|
||||
})
|
||||
|
||||
it('sign does NOT throw when a payment contains an issued currency like xrp in hex string format', async function () {
|
||||
|
||||
8
packages/xrpl/tsconfig.models.json
Normal file
8
packages/xrpl/tsconfig.models.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "../xrpl-models/dist"
|
||||
},
|
||||
"include": ["./src/models/**/*.ts", "./src/errors.ts"],
|
||||
}
|
||||
Reference in New Issue
Block a user