mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-26 23:25:49 +00:00
X-address compatibility (#90)
ripple-binary-codec can encode transactions with X-Addresses
This commit is contained in:
@@ -42,6 +42,11 @@ Encode a transaction object into a hex-string.
|
|||||||
'1100612200000000240000000125000000072D0000000055DF530FB14C5304852F20080B0A8EEF3A6BDD044F41F4EBBD68B8B321145FE4FF6240000002540BE4008114D0F5430B66E06498D4CEEC816C7B3337F9982337'
|
'1100612200000000240000000125000000072D0000000055DF530FB14C5304852F20080B0A8EEF3A6BDD044F41F4EBBD68B8B321145FE4FF6240000002540BE4008114D0F5430B66E06498D4CEEC816C7B3337F9982337'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### X-Address Compatibility
|
||||||
|
* ripple-binary-codec handles X-addresses by looking for a few specific files (Account/SourceTag, Destination/DestinationTag).
|
||||||
|
* If other fields (in the future) must to support X-addresses with tags, this library will need to be updated.
|
||||||
|
* When decoding rippled binary, the output will always output classic address + tag, with no X-addresses. X-address support only applies when encoding to binary.
|
||||||
|
|
||||||
### encodeForSigning(json: object): string
|
### encodeForSigning(json: object): string
|
||||||
|
|
||||||
Encode the transaction object for signing.
|
Encode the transaction object for signing.
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { decodeAccountID, encodeAccountID } from "ripple-address-codec";
|
import { decodeAccountID, encodeAccountID } from "ripple-address-codec";
|
||||||
import { Hash160 } from "./hash-160";
|
import { Hash160 } from "./hash-160";
|
||||||
|
|
||||||
|
const HEX_REGEX = /^[A-F0-9]{40}$/;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class defining how to encode and decode an AccountID
|
* Class defining how to encode and decode an AccountID
|
||||||
*/
|
*/
|
||||||
@@ -27,9 +29,9 @@ class AccountID extends Hash160 {
|
|||||||
return new AccountID();
|
return new AccountID();
|
||||||
}
|
}
|
||||||
|
|
||||||
return /^r/.test(value)
|
return HEX_REGEX.test(value)
|
||||||
? this.fromBase58(value)
|
? new AccountID(Buffer.from(value, "hex"))
|
||||||
: new AccountID(Buffer.from(value, "hex"));
|
: this.fromBase58(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error("Cannot construct AccountID from value given");
|
throw new Error("Cannot construct AccountID from value given");
|
||||||
|
|||||||
@@ -1,11 +1,53 @@
|
|||||||
import { Field, FieldInstance } from "../enums";
|
import { Field, FieldInstance } from "../enums";
|
||||||
import { SerializedType, JsonObject } from "./serialized-type";
|
import { SerializedType, JsonObject } from "./serialized-type";
|
||||||
|
import {
|
||||||
|
xAddressToClassicAddress,
|
||||||
|
isValidXAddress,
|
||||||
|
} from "ripple-address-codec";
|
||||||
import { BinaryParser } from "../serdes/binary-parser";
|
import { BinaryParser } from "../serdes/binary-parser";
|
||||||
import { BinarySerializer, BytesList } from "../serdes/binary-serializer";
|
import { BinarySerializer, BytesList } from "../serdes/binary-serializer";
|
||||||
|
|
||||||
const OBJECT_END_MARKER = Buffer.from([0xe1]);
|
const OBJECT_END_MARKER_BYTE = Buffer.from([0xe1]);
|
||||||
const OBJECT_END_MARKER_NAME = "ObjectEndMarker";
|
const OBJECT_END_MARKER = "ObjectEndMarker";
|
||||||
const OBJECT_FIELD_TYPE_NAME = "STObject";
|
const ST_OBJECT = "STObject";
|
||||||
|
const DESTINATION = "Destination";
|
||||||
|
const ACCOUNT = "Account";
|
||||||
|
const SOURCE_TAG = "SourceTag";
|
||||||
|
const DEST_TAG = "DestinationTag";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Break down an X-Address into an account and a tag
|
||||||
|
*
|
||||||
|
* @param field Name of field
|
||||||
|
* @param xAddress X-Address corresponding to the field
|
||||||
|
*/
|
||||||
|
function handleXAddress(field: string, xAddress: string): JsonObject {
|
||||||
|
const decoded = xAddressToClassicAddress(xAddress);
|
||||||
|
|
||||||
|
let tagName;
|
||||||
|
if (field === DESTINATION) tagName = DEST_TAG;
|
||||||
|
else if (field === ACCOUNT) tagName = SOURCE_TAG;
|
||||||
|
else if (decoded.tag !== false)
|
||||||
|
throw new Error(`${field} cannot have an associated tag`);
|
||||||
|
|
||||||
|
return decoded.tag !== false
|
||||||
|
? { [field]: decoded.classicAddress, [tagName]: decoded.tag }
|
||||||
|
: { [field]: decoded.classicAddress };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate that two objects don't both have the same tag fields
|
||||||
|
*
|
||||||
|
* @param obj1 First object to check for tags
|
||||||
|
* @param obj2 Second object to check for tags
|
||||||
|
* @throws When both objects have SourceTag or DestinationTag
|
||||||
|
*/
|
||||||
|
function checkForDuplicateTags(obj1: JsonObject, obj2: JsonObject): void {
|
||||||
|
if (!(obj1[SOURCE_TAG] === undefined || obj2[SOURCE_TAG] === undefined))
|
||||||
|
throw new Error("Cannot have Account X-Address and SourceTag");
|
||||||
|
if (!(obj1[DEST_TAG] === undefined || obj2[DEST_TAG] === undefined))
|
||||||
|
throw new Error("Cannot have Destination X-Address and DestinationTag");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for Serializing/Deserializing objects
|
* Class for Serializing/Deserializing objects
|
||||||
@@ -23,15 +65,15 @@ class STObject extends SerializedType {
|
|||||||
|
|
||||||
while (!parser.end()) {
|
while (!parser.end()) {
|
||||||
const field = parser.readField();
|
const field = parser.readField();
|
||||||
if (field.name === OBJECT_END_MARKER_NAME) {
|
if (field.name === OBJECT_END_MARKER) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const associatedValue = parser.readFieldValue(field);
|
const associatedValue = parser.readFieldValue(field);
|
||||||
|
|
||||||
bytes.writeFieldAndValue(field, associatedValue);
|
bytes.writeFieldAndValue(field, associatedValue);
|
||||||
if (field.type.name === OBJECT_FIELD_TYPE_NAME) {
|
if (field.type.name === ST_OBJECT) {
|
||||||
bytes.put(OBJECT_END_MARKER);
|
bytes.put(OBJECT_END_MARKER_BYTE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +98,16 @@ class STObject extends SerializedType {
|
|||||||
const list: BytesList = new BytesList();
|
const list: BytesList = new BytesList();
|
||||||
const bytes: BinarySerializer = new BinarySerializer(list);
|
const bytes: BinarySerializer = new BinarySerializer(list);
|
||||||
|
|
||||||
let sorted = Object.keys(value)
|
const xAddressDecoded = Object.entries(value).reduce((acc, [key, val]) => {
|
||||||
|
let handled: JsonObject | undefined = undefined;
|
||||||
|
if (isValidXAddress(val)) {
|
||||||
|
handled = handleXAddress(key, val);
|
||||||
|
checkForDuplicateTags(handled, value as JsonObject);
|
||||||
|
}
|
||||||
|
return Object.assign(acc, handled ?? { [key]: val });
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
let sorted = Object.keys(xAddressDecoded)
|
||||||
.map((f: string): FieldInstance => Field[f] as FieldInstance)
|
.map((f: string): FieldInstance => Field[f] as FieldInstance)
|
||||||
.filter((f: FieldInstance): boolean => f !== undefined && f.isSerialized)
|
.filter((f: FieldInstance): boolean => f !== undefined && f.isSerialized)
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
@@ -68,11 +119,13 @@ class STObject extends SerializedType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sorted.forEach((field) => {
|
sorted.forEach((field) => {
|
||||||
const associatedValue = field.associatedType.from(value[field.name]);
|
const associatedValue = field.associatedType.from(
|
||||||
|
xAddressDecoded[field.name]
|
||||||
|
);
|
||||||
|
|
||||||
bytes.writeFieldAndValue(field, associatedValue);
|
bytes.writeFieldAndValue(field, associatedValue);
|
||||||
if (field.type.name === OBJECT_FIELD_TYPE_NAME) {
|
if (field.type.name === ST_OBJECT) {
|
||||||
bytes.put(OBJECT_END_MARKER);
|
bytes.put(OBJECT_END_MARKER_BYTE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -90,7 +143,7 @@ class STObject extends SerializedType {
|
|||||||
|
|
||||||
while (!objectParser.end()) {
|
while (!objectParser.end()) {
|
||||||
const field = objectParser.readField();
|
const field = objectParser.readField();
|
||||||
if (field.name === OBJECT_END_MARKER_NAME) {
|
if (field.name === OBJECT_END_MARKER) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
accumulator[field.name] = objectParser.readFieldValue(field).toJSON();
|
accumulator[field.name] = objectParser.readFieldValue(field).toJSON();
|
||||||
|
|||||||
188
packages/ripple-binary-codec/test/fixtures/x-codec-fixtures.json
vendored
Normal file
188
packages/ripple-binary-codec/test/fixtures/x-codec-fixtures.json
vendored
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
{
|
||||||
|
"transactions": [{
|
||||||
|
"rjson": {
|
||||||
|
"Account": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||||
|
"Destination": "rLQBHVhFnaC5gLEkgr6HgBJJ3bgeZHg9cj",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"TxnSignature": "3045022022EB32AECEF7C644C891C19F87966DF9C62B1F34BABA6BE774325E4BB8E2DD62022100A51437898C28C2B297112DF8131F2BB39EA5FE613487DDD611525F1796264639",
|
||||||
|
"SigningPubKey": "034AADB09CFF4A4804073701EC53C3510CDC95917C2BB0150FB742D0C66E6CEE9E",
|
||||||
|
"Amount": "10000000000",
|
||||||
|
"DestinationTag": 1010,
|
||||||
|
"SourceTag": 84854,
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 0,
|
||||||
|
"Sequence": 62
|
||||||
|
},
|
||||||
|
"xjson": {
|
||||||
|
"Account": "X7tFPvjMH7nDxP8nTGkeeggcUpCZj8UbyT2QoiRHGDfjqrB",
|
||||||
|
"Destination": "XVYmGpJqHS95ir411XvanwY1xt5Z2314WsamHPVgUNABUGV",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"TxnSignature": "3045022022EB32AECEF7C644C891C19F87966DF9C62B1F34BABA6BE774325E4BB8E2DD62022100A51437898C28C2B297112DF8131F2BB39EA5FE613487DDD611525F1796264639",
|
||||||
|
"SigningPubKey": "034AADB09CFF4A4804073701EC53C3510CDC95917C2BB0150FB742D0C66E6CEE9E",
|
||||||
|
"Amount": "10000000000",
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 0,
|
||||||
|
"Sequence": 62
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rjson": {
|
||||||
|
"Account": "r4DymtkgUAh2wqRxVfdd3Xtswzim6eC6c5",
|
||||||
|
"Amount": "199000000",
|
||||||
|
"Destination": "rsekGH9p9neiPxym2TMJhqaCzHFuokenTU",
|
||||||
|
"DestinationTag": 3663729509,
|
||||||
|
"Fee": "6335",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"LastLedgerSequence": 57313352,
|
||||||
|
"Sequence": 105791,
|
||||||
|
"SigningPubKey": "02053A627976CE1157461336AC65290EC1571CAAD1B327339980F7BF65EF776F83",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"TxnSignature": "30440220086D3330CD6CE01D891A26BA0355D8D5A5D28A5C9A1D0C5E06E321C81A02318A0220027C3F6606E41FEA35103EDE5224CC489B6514ACFE27543185B0419DD02E301C"
|
||||||
|
},
|
||||||
|
"xjson": {
|
||||||
|
"Account": "r4DymtkgUAh2wqRxVfdd3Xtswzim6eC6c5",
|
||||||
|
"Amount": "199000000",
|
||||||
|
"Destination": "X7cBoj6a5xSEfPCr6AStN9YPhbMAA2yaN2XYWwRJKAKb3y5",
|
||||||
|
"Fee": "6335",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"LastLedgerSequence": 57313352,
|
||||||
|
"Sequence": 105791,
|
||||||
|
"SigningPubKey": "02053A627976CE1157461336AC65290EC1571CAAD1B327339980F7BF65EF776F83",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"TxnSignature": "30440220086D3330CD6CE01D891A26BA0355D8D5A5D28A5C9A1D0C5E06E321C81A02318A0220027C3F6606E41FEA35103EDE5224CC489B6514ACFE27543185B0419DD02E301C"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rjson": {
|
||||||
|
"Account": "rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv",
|
||||||
|
"Amount": "105302107",
|
||||||
|
"Destination": "r33hypJXDs47LVpmvta7hMW9pR8DYeBtkW",
|
||||||
|
"DestinationTag": 1658156118,
|
||||||
|
"Fee": "60000",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"LastLedgerSequence": 57313566,
|
||||||
|
"Sequence": 1113196,
|
||||||
|
"SigningPubKey": "03D847C2DBED3ABF0453F71DCD7641989136277218DF516AD49519C9693F32727E",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"TxnSignature": "3045022100FCA10FBAC65EA60C115A970CD52E6A526B1F9DDB6C4F843DA3DE7A97DFF9492D022037824D0FC6F663FB08BE0F2812CBADE1F61836528D44945FC37F10CC03215111"
|
||||||
|
},
|
||||||
|
"xjson": {
|
||||||
|
"Account": "rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv",
|
||||||
|
"Amount": "105302107",
|
||||||
|
"Destination": "X7ikFY5asEwp6ikt2AJdTfBLALEs5JN35kkeqKVeT1GdvY1",
|
||||||
|
"Fee": "60000",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"LastLedgerSequence": 57313566,
|
||||||
|
"Sequence": 1113196,
|
||||||
|
"SigningPubKey": "03D847C2DBED3ABF0453F71DCD7641989136277218DF516AD49519C9693F32727E",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"TxnSignature": "3045022100FCA10FBAC65EA60C115A970CD52E6A526B1F9DDB6C4F843DA3DE7A97DFF9492D022037824D0FC6F663FB08BE0F2812CBADE1F61836528D44945FC37F10CC03215111"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rjson": {
|
||||||
|
"Account": "rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv",
|
||||||
|
"Amount": "3899911571",
|
||||||
|
"Destination": "rU2mEJSLqBRkYLVTv55rFTgQajkLTnT6mA",
|
||||||
|
"DestinationTag": 255406,
|
||||||
|
"Fee": "60000",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"LastLedgerSequence": 57313566,
|
||||||
|
"Sequence": 1113197,
|
||||||
|
"SigningPubKey": "03D847C2DBED3ABF0453F71DCD7641989136277218DF516AD49519C9693F32727E",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"TxnSignature": "3044022077642D94BB3C49BF3CB4C804255EC830D2C6009EA4995E38A84602D579B8AAD702206FAD977C49980226E8B495BF03C8D9767380F1546BBF5A4FD47D604C0D2CCF9B"
|
||||||
|
},
|
||||||
|
"xjson": {
|
||||||
|
"Account": "rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv",
|
||||||
|
"Amount": "3899911571",
|
||||||
|
"Destination": "XVfH8gwNWVbB5Kft16jmTNgGTqgw1dzA8ZTBkNjSLw6JdXS",
|
||||||
|
"Fee": "60000",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"LastLedgerSequence": 57313566,
|
||||||
|
"Sequence": 1113197,
|
||||||
|
"SigningPubKey": "03D847C2DBED3ABF0453F71DCD7641989136277218DF516AD49519C9693F32727E",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"TxnSignature": "3044022077642D94BB3C49BF3CB4C804255EC830D2C6009EA4995E38A84602D579B8AAD702206FAD977C49980226E8B495BF03C8D9767380F1546BBF5A4FD47D604C0D2CCF9B"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rjson": {
|
||||||
|
"Account": "r4eEbLKZGbVSBHnSUBZW8i5XaMjGLdqT4a",
|
||||||
|
"Amount": "820370849",
|
||||||
|
"Destination": "rDhmyBh4JwDAtXyRZDarNgg52UcLLRoGje",
|
||||||
|
"DestinationTag": 2017780486,
|
||||||
|
"Fee": "6000",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"LastLedgerSequence": 57315579,
|
||||||
|
"Sequence": 234254,
|
||||||
|
"SigningPubKey": "038CF47114672A12B269AEE015BF7A8438609B994B0640E4B28B2F56E93D948B15",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"TxnSignature": "3044022015004653B1CBDD5CCA1F7B38555F1B37FE3F811E9D5070281CCC6C8A93460D870220679E9899184901EA69750C8A9325768490B1B9C1A733842446727653FF3D1DC0"
|
||||||
|
},
|
||||||
|
"xjson": {
|
||||||
|
"Account": "r4eEbLKZGbVSBHnSUBZW8i5XaMjGLdqT4a",
|
||||||
|
"Amount": "820370849",
|
||||||
|
"Destination": "XV31huWNJQXsAJFwgE6rnC8uf8jRx4H4waq4MyGUxz5CXzS",
|
||||||
|
"Fee": "6000",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"LastLedgerSequence": 57315579,
|
||||||
|
"Sequence": 234254,
|
||||||
|
"SigningPubKey": "038CF47114672A12B269AEE015BF7A8438609B994B0640E4B28B2F56E93D948B15",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"TxnSignature": "3044022015004653B1CBDD5CCA1F7B38555F1B37FE3F811E9D5070281CCC6C8A93460D870220679E9899184901EA69750C8A9325768490B1B9C1A733842446727653FF3D1DC0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rjson": {
|
||||||
|
"Account": "rsGeDwS4rpocUumu9smpXomzaaeG4Qyifz",
|
||||||
|
"Amount": "1500000000",
|
||||||
|
"Destination": "rDxfhNRgCDNDckm45zT5ayhKDC4Ljm7UoP",
|
||||||
|
"DestinationTag": 1000635172,
|
||||||
|
"Fee": "5000",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"Sequence": 55741075,
|
||||||
|
"SigningPubKey": "02ECB814477DF9D8351918878E235EE6AF147A2A5C20F1E71F291F0F3303357C36",
|
||||||
|
"SourceTag": 1000635172,
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"TxnSignature": "304402202A90972E21823214733082E1977F9EA2D6B5101902F108E7BDD7D128CEEA7AF3022008852C8DAD746A7F18E66A47414FABF551493674783E8EA7409C501D3F05F99A"
|
||||||
|
},
|
||||||
|
"xjson": {
|
||||||
|
"Account": "rsGeDwS4rpocUumu9smpXomzaaeG4Qyifz",
|
||||||
|
"Amount": "1500000000",
|
||||||
|
"Destination": "XVBkK1yLutMqFGwTm6hykn7YXGDUrjsZSkpzMgRveZrMbHs",
|
||||||
|
"Fee": "5000",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"Sequence": 55741075,
|
||||||
|
"SigningPubKey": "02ECB814477DF9D8351918878E235EE6AF147A2A5C20F1E71F291F0F3303357C36",
|
||||||
|
"SourceTag": 1000635172,
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"TxnSignature": "304402202A90972E21823214733082E1977F9EA2D6B5101902F108E7BDD7D128CEEA7AF3022008852C8DAD746A7F18E66A47414FABF551493674783E8EA7409C501D3F05F99A"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rjson": {
|
||||||
|
"Account": "rHWcuuZoFvDS6gNbmHSdpb7u1hZzxvCoMt",
|
||||||
|
"Amount": "48918500000",
|
||||||
|
"Destination": "rEb8TK3gBgk5auZkwc6sHnwrGVJH8DuaLh",
|
||||||
|
"DestinationTag": 105959914,
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"Sequence": 32641,
|
||||||
|
"SigningPubKey": "02E98DA545CCCC5D14C82594EE9E6CCFCF5171108E2410B3E784183E1068D33429",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"TxnSignature": "304502210091DCA7AF189CD9DC93BDE24DEAE87381FBF16789C43113EE312241D648982B2402201C6055FEFFF1F119640AAC0B32C4F37375B0A96033E0527A21C1366920D6A524"
|
||||||
|
},
|
||||||
|
"xjson": {
|
||||||
|
"Account": "rHWcuuZoFvDS6gNbmHSdpb7u1hZzxvCoMt",
|
||||||
|
"Amount": "48918500000",
|
||||||
|
"Destination": "XVH3aqvbYGhRhrD1FYSzGooNuxdzbG3VR2fuM47oqbXxQr7",
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"Sequence": 32641,
|
||||||
|
"SigningPubKey": "02E98DA545CCCC5D14C82594EE9E6CCFCF5171108E2410B3E784183E1068D33429",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"TxnSignature": "304502210091DCA7AF189CD9DC93BDE24DEAE87381FBF16789C43113EE312241D648982B2402201C6055FEFFF1F119640AAC0B32C4F37375B0A96033E0527A21C1366920D6A524"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
@@ -16,10 +16,14 @@ describe('Hash160', function () {
|
|||||||
expect(h1.lt(h2)).toBe(true)
|
expect(h1.lt(h2)).toBe(true)
|
||||||
expect(h3.lt(h2)).toBe(true)
|
expect(h3.lt(h2)).toBe(true)
|
||||||
})
|
})
|
||||||
|
test('throws when constructed from invalid hash length', () => {
|
||||||
|
expect(() => Hash160.from('10000000000000000000000000000000000000')).toThrow('Invalid Hash length 19')
|
||||||
|
expect(() => Hash160.from('100000000000000000000000000000000000000000')).toThrow('Invalid Hash length 21')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Hash256', function () {
|
describe('Hash256', function () {
|
||||||
test('has a static width membmer', function () {
|
test('has a static width member', function () {
|
||||||
expect(Hash256.width).toBe(32)
|
expect(Hash256.width).toBe(32)
|
||||||
})
|
})
|
||||||
test('has a ZERO_256 member', function () {
|
test('has a ZERO_256 member', function () {
|
||||||
|
|||||||
137
packages/ripple-binary-codec/test/x-address.test.js
Normal file
137
packages/ripple-binary-codec/test/x-address.test.js
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
const { encode, decode } = require("./../dist/index");
|
||||||
|
const fixtures = require('./fixtures/x-codec-fixtures.json')
|
||||||
|
|
||||||
|
let json_x1 = {
|
||||||
|
OwnerCount: 0,
|
||||||
|
Account: "XVXdn5wEVm5G4UhEHWDPqjvdeH361P7BsapL4m2D2XnPSwT",
|
||||||
|
PreviousTxnLgrSeq: 7,
|
||||||
|
LedgerEntryType: "AccountRoot",
|
||||||
|
PreviousTxnID: "DF530FB14C5304852F20080B0A8EEF3A6BDD044F41F4EBBD68B8B321145FE4FF",
|
||||||
|
Flags: 0,
|
||||||
|
Sequence: 1,
|
||||||
|
Balance: "10000000000"
|
||||||
|
}
|
||||||
|
|
||||||
|
let json_r1 = {
|
||||||
|
OwnerCount: 0,
|
||||||
|
Account: 'rLs1MzkFWCxTbuAHgjeTZK4fcCDDnf2KRv',
|
||||||
|
PreviousTxnLgrSeq: 7,
|
||||||
|
LedgerEntryType: 'AccountRoot',
|
||||||
|
PreviousTxnID: 'DF530FB14C5304852F20080B0A8EEF3A6BDD044F41F4EBBD68B8B321145FE4FF',
|
||||||
|
Flags: 0,
|
||||||
|
Sequence: 1,
|
||||||
|
Balance: '10000000000',
|
||||||
|
SourceTag: 12345,
|
||||||
|
}
|
||||||
|
|
||||||
|
let json_null_x = {
|
||||||
|
"OwnerCount": 0,
|
||||||
|
"Account": "rLs1MzkFWCxTbuAHgjeTZK4fcCDDnf2KRv",
|
||||||
|
"Destination": "rLs1MzkFWCxTbuAHgjeTZK4fcCDDnf2KRv",
|
||||||
|
"Issuer": "XVXdn5wEVm5G4UhEHWDPqjvdeH361P4GETfNyyXGaoqBj71",
|
||||||
|
"PreviousTxnLgrSeq": 7,
|
||||||
|
"LedgerEntryType": "AccountRoot",
|
||||||
|
"PreviousTxnID": "DF530FB14C5304852F20080B0A8EEF3A6BDD044F41F4EBBD68B8B321145FE4FF",
|
||||||
|
"Flags": 0,
|
||||||
|
"Sequence": 1,
|
||||||
|
"Balance": "10000000000"
|
||||||
|
}
|
||||||
|
|
||||||
|
let json_invalid_x = {
|
||||||
|
"OwnerCount": 0,
|
||||||
|
"Account": "rLs1MzkFWCxTbuAHgjeTZK4fcCDDnf2KRv",
|
||||||
|
"Destination": "rLs1MzkFWCxTbuAHgjeTZK4fcCDDnf2KRv",
|
||||||
|
"Issuer": "XVXdn5wEVm5g4UhEHWDPqjvdeH361P4GETfNyyXGaoqBj71",
|
||||||
|
"PreviousTxnLgrSeq": 7,
|
||||||
|
"LedgerEntryType": "AccountRoot",
|
||||||
|
"PreviousTxnID": "DF530FB14C5304852F20080B0A8EEF3A6BDD044F41F4EBBD68B8B321145FE4FF",
|
||||||
|
"Flags": 0,
|
||||||
|
"Sequence": 1,
|
||||||
|
"Balance": "10000000000"
|
||||||
|
}
|
||||||
|
|
||||||
|
let json_null_r = {
|
||||||
|
"OwnerCount": 0,
|
||||||
|
"Account": "rLs1MzkFWCxTbuAHgjeTZK4fcCDDnf2KRv",
|
||||||
|
"Destination": "rLs1MzkFWCxTbuAHgjeTZK4fcCDDnf2KRv",
|
||||||
|
"Issuer": "rLs1MzkFWCxTbuAHgjeTZK4fcCDDnf2KRv",
|
||||||
|
"PreviousTxnLgrSeq": 7,
|
||||||
|
"LedgerEntryType": "AccountRoot",
|
||||||
|
"PreviousTxnID": "DF530FB14C5304852F20080B0A8EEF3A6BDD044F41F4EBBD68B8B321145FE4FF",
|
||||||
|
"Flags": 0,
|
||||||
|
"Sequence": 1,
|
||||||
|
"Balance": "10000000000"
|
||||||
|
}
|
||||||
|
|
||||||
|
let invalid_json_issuer_tagged = {
|
||||||
|
"OwnerCount": 0,
|
||||||
|
"Account": "rLs1MzkFWCxTbuAHgjeTZK4fcCDDnf2KRv",
|
||||||
|
"Destination": "rLs1MzkFWCxTbuAHgjeTZK4fcCDDnf2KRv",
|
||||||
|
"Issuer": "XVXdn5wEVm5G4UhEHWDPqjvdeH361P7BsapL4m2D2XnPSwT",
|
||||||
|
"PreviousTxnLgrSeq": 7,
|
||||||
|
"LedgerEntryType": "AccountRoot",
|
||||||
|
"PreviousTxnID": "DF530FB14C5304852F20080B0A8EEF3A6BDD044F41F4EBBD68B8B321145FE4FF",
|
||||||
|
"Flags": 0,
|
||||||
|
"Sequence": 1,
|
||||||
|
"Balance": "10000000000"
|
||||||
|
}
|
||||||
|
|
||||||
|
let invalid_json_x_and_tagged = {
|
||||||
|
OwnerCount: 0,
|
||||||
|
Account: 'XVXdn5wEVm5G4UhEHWDPqjvdeH361P7BsapL4m2D2XnPSwT',
|
||||||
|
PreviousTxnLgrSeq: 7,
|
||||||
|
LedgerEntryType: 'AccountRoot',
|
||||||
|
PreviousTxnID: 'DF530FB14C5304852F20080B0A8EEF3A6BDD044F41F4EBBD68B8B321145FE4FF',
|
||||||
|
Flags: 0,
|
||||||
|
Sequence: 1,
|
||||||
|
Balance: '10000000000',
|
||||||
|
SourceTag: 12345,
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("X-Address Account is equivalent to a classic address w/ SourceTag", () => {
|
||||||
|
let encoded_x = encode(json_x1);
|
||||||
|
let encoded_r = encode(json_r1);
|
||||||
|
test("Can encode with x-Address", () => {
|
||||||
|
expect(encoded_x).toEqual(encoded_r);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("decoded X-address is object w/ source and tag", () => {
|
||||||
|
let decoded_x = decode(encoded_x);
|
||||||
|
expect(decoded_x).toEqual(json_r1);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Encoding issuer X-Address w/ undefined destination tag", () => {
|
||||||
|
expect(encode(json_null_x)).toEqual(encode(json_null_r));
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Throws when X-Address is invalid", () => {
|
||||||
|
expect(() => encode(json_invalid_x)).toThrow("checksum_invalid");
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("Invalid X-Address behavior", () => {
|
||||||
|
test("X-Address with tag throws value for invalid field",() => {
|
||||||
|
expect(() => encode(invalid_json_issuer_tagged)).toThrow(new Error("Issuer cannot have an associated tag"))
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Throws when Account has both X-Addr and Destination Tag", () => {
|
||||||
|
expect(() => encode(invalid_json_x_and_tagged)).toThrow(new Error("Cannot have Account X-Address and SourceTag"));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('ripple-binary-codec x-address test', function () {
|
||||||
|
function makeSuite (name, entries) {
|
||||||
|
describe(name, function () {
|
||||||
|
entries.forEach((t, testN) => {
|
||||||
|
test(`${name}[${testN}] encodes X-address json equivalent to classic address json`,
|
||||||
|
() => {
|
||||||
|
expect(encode(t.rjson)).toEqual(encode(t.xjson))
|
||||||
|
})
|
||||||
|
test(`${name}[${testN}] decodes X-address json equivalent to classic address json`, () => {
|
||||||
|
expect(decode(encode(t.xjson))).toEqual(t.rjson);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
makeSuite('transactions', fixtures.transactions)
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user