mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-22 05:05:48 +00:00
add support for XChainClaim
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
"UInt32": 2,
|
||||
"STArray": 15,
|
||||
"Sidechain": 24,
|
||||
"XchainClaimProof": 25
|
||||
"XChainClaimProof": 25
|
||||
},
|
||||
"LEDGER_ENTRY_TYPES": {
|
||||
"Any": -3,
|
||||
|
||||
@@ -147,7 +147,8 @@ class Amount extends SerializedType {
|
||||
*/
|
||||
toJSON(): AmountObject | string {
|
||||
if (this.isNative()) {
|
||||
const bytes = this.bytes
|
||||
const bytes = Buffer.alloc(this.bytes.length)
|
||||
this.bytes.copy(bytes)
|
||||
const isPositive = bytes[0] & 0x40
|
||||
const sign = isPositive ? '' : '-'
|
||||
bytes[0] &= 0x3f
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Hash256 } from './hash-256'
|
||||
import { IssuedCurrency } from './issued-currency'
|
||||
import { PathSet } from './path-set'
|
||||
import { Sidechain } from './sidechain'
|
||||
import { Signature } from './signature'
|
||||
import { STArray } from './st-array'
|
||||
import { STObject } from './st-object'
|
||||
import { UInt16 } from './uint-16'
|
||||
@@ -21,6 +22,7 @@ import { UInt32 } from './uint-32'
|
||||
import { UInt64 } from './uint-64'
|
||||
import { UInt8 } from './uint-8'
|
||||
import { Vector256 } from './vector-256'
|
||||
import { XChainClaimProof } from './xchain-claim-proof'
|
||||
|
||||
const coreTypes = {
|
||||
AccountID,
|
||||
@@ -33,6 +35,7 @@ const coreTypes = {
|
||||
IssuedCurrency,
|
||||
PathSet,
|
||||
Sidechain,
|
||||
Signature,
|
||||
STArray,
|
||||
STObject,
|
||||
UInt8,
|
||||
@@ -40,6 +43,7 @@ const coreTypes = {
|
||||
UInt32,
|
||||
UInt64,
|
||||
Vector256,
|
||||
XChainClaimProof,
|
||||
}
|
||||
|
||||
Object.values(Field).forEach((field) => {
|
||||
|
||||
131
packages/ripple-binary-codec/src/types/signature.ts
Normal file
131
packages/ripple-binary-codec/src/types/signature.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import { BinaryParser } from '../serdes/binary-parser'
|
||||
|
||||
import { JsonObject, SerializedType } from './serialized-type'
|
||||
import { Buffer } from 'buffer/'
|
||||
import { Blob } from './blob'
|
||||
import { decodeAccountPublic, encodeAccountPublic } from 'ripple-address-codec'
|
||||
|
||||
/**
|
||||
* Interface for JSON objects that represent amounts
|
||||
*/
|
||||
interface SignatureObject extends JsonObject {
|
||||
signature: string
|
||||
signing_key: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard for AmountObject
|
||||
*/
|
||||
function isSignatureObject(arg): arg is SignatureObject {
|
||||
const keys = Object.keys(arg).sort()
|
||||
return (
|
||||
keys.length === 2 && keys[0] === 'signature' && keys[1] === 'signing_key'
|
||||
)
|
||||
}
|
||||
|
||||
function encodeVariableLength(length: number): Buffer {
|
||||
const lenBytes = Buffer.alloc(3)
|
||||
if (length <= 192) {
|
||||
lenBytes[0] = length
|
||||
return lenBytes.slice(0, 1)
|
||||
} else if (length <= 12480) {
|
||||
length -= 193
|
||||
lenBytes[0] = 193 + (length >>> 8)
|
||||
lenBytes[1] = length & 0xff
|
||||
return lenBytes.slice(0, 2)
|
||||
} else if (length <= 918744) {
|
||||
length -= 12481
|
||||
lenBytes[0] = 241 + (length >>> 16)
|
||||
lenBytes[1] = (length >> 8) & 0xff
|
||||
lenBytes[2] = length & 0xff
|
||||
return lenBytes.slice(0, 3)
|
||||
}
|
||||
throw new Error('Overflow error')
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for serializing/Deserializing Amounts
|
||||
*/
|
||||
class Signature extends SerializedType {
|
||||
static readonly ZERO_SIGNATURE: Signature = new Signature(
|
||||
Buffer.concat([Buffer.alloc(1), Buffer.from([33]), Buffer.alloc(33)]),
|
||||
)
|
||||
|
||||
constructor(bytes: Buffer) {
|
||||
super(bytes ?? Signature.ZERO_SIGNATURE.bytes)
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an amount from an IOU or string amount
|
||||
*
|
||||
* @param value An Amount, object representing an IOU, or a string
|
||||
* representing an integer amount
|
||||
* @returns An Amount object
|
||||
*/
|
||||
static from<T extends Signature | SignatureObject>(value: T): Signature {
|
||||
if (value instanceof Signature) {
|
||||
return value
|
||||
}
|
||||
|
||||
if (isSignatureObject(value)) {
|
||||
const signature = Blob.from(value.signature).toBytes()
|
||||
const signing_key = new Blob(
|
||||
Buffer.from(decodeAccountPublic(value.signing_key)),
|
||||
).toBytes()
|
||||
return new Signature(
|
||||
Buffer.concat([
|
||||
encodeVariableLength(signature.length),
|
||||
signature,
|
||||
encodeVariableLength(signing_key.length),
|
||||
signing_key,
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
||||
throw new Error('Invalid type to construct a Signature')
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an amount from a BinaryParser
|
||||
*
|
||||
* @param parser BinaryParser to read the Amount from
|
||||
* @returns An Amount object
|
||||
*/
|
||||
static fromParser(parser: BinaryParser): Signature {
|
||||
const bytes: Array<Buffer> = []
|
||||
|
||||
const signatureLength = parser.readVariableLengthLength()
|
||||
bytes.push(encodeVariableLength(signatureLength))
|
||||
bytes.push(Blob.fromParser(parser, signatureLength).toBytes())
|
||||
const signingKeyLength = parser.readVariableLengthLength()
|
||||
bytes.push(encodeVariableLength(signingKeyLength))
|
||||
bytes.push(Blob.fromParser(parser, signingKeyLength).toBytes())
|
||||
|
||||
return new Signature(Buffer.concat(bytes))
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JSON representation of this Amount
|
||||
*
|
||||
* @returns the JSON interpretation of this.bytes
|
||||
*/
|
||||
toJSON(): SignatureObject {
|
||||
const parser = new BinaryParser(this.toString())
|
||||
const signatureLength = parser.readVariableLengthLength()
|
||||
const signature = Blob.fromParser(
|
||||
parser,
|
||||
signatureLength,
|
||||
).toJSON() as string
|
||||
const signingKeyLength = parser.readVariableLengthLength()
|
||||
const signingKey = Blob.fromParser(parser, signingKeyLength)
|
||||
|
||||
return {
|
||||
signature,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
signing_key: encodeAccountPublic(signingKey.toBytes()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { Signature, SignatureObject }
|
||||
@@ -6,7 +6,7 @@ import { Buffer } from 'buffer/'
|
||||
* Derived UInt class for serializing/deserializing 32 bit UInt
|
||||
*/
|
||||
class UInt32 extends UInt {
|
||||
protected static readonly width: number = 32 / 8 // 4
|
||||
public static readonly width: number = 32 / 8 // 4
|
||||
static readonly defaultUInt32: UInt32 = new UInt32(Buffer.alloc(UInt32.width))
|
||||
|
||||
constructor(bytes: Buffer) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Buffer } from 'buffer/'
|
||||
* Derived UInt class for serializing/deserializing 8 bit UInt
|
||||
*/
|
||||
class UInt8 extends UInt {
|
||||
protected static readonly width: number = 8 / 8 // 1
|
||||
public static readonly width: number = 8 / 8 // 1
|
||||
static readonly defaultUInt8: UInt8 = new UInt8(Buffer.alloc(UInt8.width))
|
||||
|
||||
constructor(bytes: Buffer) {
|
||||
|
||||
157
packages/ripple-binary-codec/src/types/xchain-claim-proof.ts
Normal file
157
packages/ripple-binary-codec/src/types/xchain-claim-proof.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import { BinaryParser } from '../serdes/binary-parser'
|
||||
|
||||
import { JsonObject, SerializedType } from './serialized-type'
|
||||
import { Buffer } from 'buffer/'
|
||||
import { Sidechain, SidechainObject } from './sidechain'
|
||||
import { Signature, SignatureObject } from './signature'
|
||||
import { Amount } from './amount'
|
||||
import { UInt8 } from './uint-8'
|
||||
import { UInt32 } from './uint-32'
|
||||
|
||||
/**
|
||||
* Constants for separating Paths in a PathSet
|
||||
*/
|
||||
const ARRAY_END_BYTE = 0xf1
|
||||
|
||||
/**
|
||||
* Interface for JSON objects that represent amounts
|
||||
*/
|
||||
interface XChainClaimProofObject extends JsonObject {
|
||||
amount: string
|
||||
sidechain: SidechainObject
|
||||
signatures: SignatureObject[]
|
||||
was_src_chain_send: boolean
|
||||
xchain_seq: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard for AmountObject
|
||||
*/
|
||||
function isProofObject(arg): arg is XChainClaimProofObject {
|
||||
const keys = Object.keys(arg).sort()
|
||||
return (
|
||||
keys.length === 5 &&
|
||||
keys[0] === 'amount' &&
|
||||
keys[1] === 'sidechain' &&
|
||||
keys[2] === 'signatures' &&
|
||||
keys[3] === 'was_src_chain_send' &&
|
||||
keys[4] === 'xchain_seq'
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for serializing/Deserializing Amounts
|
||||
*/
|
||||
class XChainClaimProof extends SerializedType {
|
||||
static readonly ZERO_PROOF: XChainClaimProof = new XChainClaimProof(
|
||||
Buffer.concat([
|
||||
Amount.defaultAmount.toBytes(),
|
||||
Sidechain.ZERO_SIDECHAIN.toBytes(),
|
||||
Buffer.from([ARRAY_END_BYTE]),
|
||||
UInt8.defaultUInt8.toBytes(),
|
||||
UInt32.defaultUInt32.toBytes(),
|
||||
]),
|
||||
)
|
||||
|
||||
constructor(bytes: Buffer) {
|
||||
super(bytes ?? XChainClaimProof.ZERO_PROOF.bytes)
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an amount from an IOU or string amount
|
||||
*
|
||||
* @param value An Amount, object representing an IOU, or a string
|
||||
* representing an integer amount
|
||||
* @returns An Amount object
|
||||
*/
|
||||
static from<T extends XChainClaimProof | XChainClaimProofObject>(
|
||||
value: T,
|
||||
): XChainClaimProof {
|
||||
if (value instanceof XChainClaimProof) {
|
||||
return value
|
||||
}
|
||||
|
||||
if (isProofObject(value)) {
|
||||
const amount = Amount.from(value.amount).toBytes()
|
||||
const sidechain = Sidechain.from(value.sidechain).toBytes()
|
||||
const signatures: Array<Buffer> = []
|
||||
value.signatures.forEach((signature: SignatureObject) => {
|
||||
signatures.push(Signature.from(signature).toBytes())
|
||||
})
|
||||
signatures.push(Buffer.from([ARRAY_END_BYTE]))
|
||||
const was_src_chain_send = UInt8.from(
|
||||
Number(value.was_src_chain_send),
|
||||
).toBytes()
|
||||
const xchain_seq = UInt32.from(value.xchain_seq).toBytes()
|
||||
return new XChainClaimProof(
|
||||
Buffer.concat([
|
||||
amount,
|
||||
sidechain,
|
||||
...signatures,
|
||||
was_src_chain_send,
|
||||
xchain_seq,
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
||||
throw new Error('Invalid type to construct a XChainClaimProof')
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an amount from a BinaryParser
|
||||
*
|
||||
* @param parser BinaryParser to read the Amount from
|
||||
* @returns An Amount object
|
||||
*/
|
||||
static fromParser(parser: BinaryParser): XChainClaimProof {
|
||||
const bytes: Array<Buffer> = []
|
||||
|
||||
bytes.push(Amount.fromParser(parser).toBytes())
|
||||
bytes.push(Sidechain.fromParser(parser).toBytes())
|
||||
while (!parser.end()) {
|
||||
bytes.push(Signature.fromParser(parser).toBytes())
|
||||
|
||||
if (parser.peek() === ARRAY_END_BYTE) {
|
||||
bytes.push(parser.read(1))
|
||||
break
|
||||
}
|
||||
}
|
||||
bytes.push(parser.read(UInt8.width))
|
||||
bytes.push(parser.read(UInt32.width))
|
||||
|
||||
return new XChainClaimProof(Buffer.concat(bytes))
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JSON representation of this Amount
|
||||
*
|
||||
* @returns the JSON interpretation of this.bytes
|
||||
*/
|
||||
toJSON(): XChainClaimProofObject {
|
||||
const parser = new BinaryParser(this.toString())
|
||||
const amount = Amount.fromParser(parser).toJSON()
|
||||
const sidechain = Sidechain.fromParser(parser).toJSON()
|
||||
const signatures: SignatureObject[] = []
|
||||
while (!parser.end()) {
|
||||
if (parser.peek() === ARRAY_END_BYTE) {
|
||||
parser.skip(1)
|
||||
break
|
||||
}
|
||||
|
||||
signatures.push(Signature.fromParser(parser).toJSON())
|
||||
}
|
||||
const was_src_chain_send = UInt8.fromParser(parser).toJSON()
|
||||
|
||||
const xchain_seq = UInt32.fromParser(parser).toJSON()
|
||||
|
||||
return {
|
||||
amount: amount as string,
|
||||
sidechain,
|
||||
signatures,
|
||||
was_src_chain_send: Boolean(was_src_chain_send),
|
||||
xchain_seq: xchain_seq as number,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { XChainClaimProof, XChainClaimProofObject }
|
||||
Reference in New Issue
Block a user