diff --git a/packages/ripple-binary-codec/src/types/index.ts b/packages/ripple-binary-codec/src/types/index.ts index 60f4ac79..c4096d5d 100644 --- a/packages/ripple-binary-codec/src/types/index.ts +++ b/packages/ripple-binary-codec/src/types/index.ts @@ -7,7 +7,6 @@ import { import { AccountID } from './account-id' import { Amount } from './amount' import { Blob } from './blob' -import { XChainBridge } from './xchain-bridge' import { Currency } from './currency' import { Hash128 } from './hash-128' import { Hash160 } from './hash-160' @@ -21,12 +20,13 @@ import { UInt32 } from './uint-32' import { UInt64 } from './uint-64' import { UInt8 } from './uint-8' import { Vector256 } from './vector-256' +import { XChainAttestationBatch } from './xchain-attestation-batch' +import { XChainBridge } from './xchain-bridge' const coreTypes = { AccountID, Amount, Blob, - XChainBridge, Currency, Hash128, Hash160, @@ -40,6 +40,8 @@ const coreTypes = { UInt32, UInt64, Vector256, + XChainAttestationBatch, + XChainBridge, } Object.values(Field).forEach((field) => { diff --git a/packages/ripple-binary-codec/src/types/xchain-attestation-batch.ts b/packages/ripple-binary-codec/src/types/xchain-attestation-batch.ts new file mode 100644 index 00000000..fc6b0bbd --- /dev/null +++ b/packages/ripple-binary-codec/src/types/xchain-attestation-batch.ts @@ -0,0 +1,118 @@ +import { BinaryParser } from '../serdes/binary-parser' + +import { JsonObject, SerializedType } from './serialized-type' +import { Buffer } from 'buffer/' +import { XChainBridge, XChainBridgeObject } from './xchain-bridge' +import { STArray } from './st-array' + +/** + * Interface for JSON objects that represent cross-chain attestations + */ +interface XChainAttestationBatchObject extends JsonObject { + XChainBridge: XChainBridgeObject + XChainClaimAttestationBatch: JsonObject[] + XChainCreateAccountAttestationBatch: JsonObject[] +} + +/** + * Type guard for XChainAttestationBatchObject + */ +function isXChainAttestationBatchObject( + arg, +): arg is XChainAttestationBatchObject { + const keys = Object.keys(arg).sort() + return ( + keys.length === 3 && + keys[0] === 'XChainBridge' && + keys[1] === 'XChainClaimAttestationBatch' && + keys[2] === 'XChainCreateAccountAttestationBatch' + ) +} + +/** + * Class for serializing/deserializing XChainAttestationBatchs + */ +class XChainAttestationBatch extends SerializedType { + static readonly ZERO_XCHAIN_ATTESTATION_BATCH: XChainAttestationBatch = + new XChainAttestationBatch( + Buffer.concat([ + Buffer.from([0x14]), + Buffer.alloc(40), + Buffer.from([0x14]), + Buffer.alloc(40), + ]), + ) + + static readonly TYPE_ORDER: { name: string; type: typeof SerializedType }[] = + [ + { name: 'XChainBridge', type: XChainBridge }, + { name: 'XChainClaimAttestationBatch', type: STArray }, + { name: 'XChainCreateAccountAttestationBatch', type: STArray }, + ] + + constructor(bytes: Buffer) { + super(bytes ?? XChainAttestationBatch.ZERO_XCHAIN_ATTESTATION_BATCH.bytes) + } + + /** + * Construct a cross-chain bridge from a JSON + * + * @param value XChainAttestationBatch or JSON to parse into a XChainAttestationBatch + * @returns A XChainAttestationBatch object + */ + static from( + value: T, + ): XChainAttestationBatch { + if (value instanceof XChainAttestationBatch) { + return value + } + + if (isXChainAttestationBatchObject(value)) { + const bytes: Array = [] + this.TYPE_ORDER.forEach((item) => { + const { name, type } = item + const object = type.from(value[name]) + bytes.push(object.toBytes()) + }) + return new XChainAttestationBatch(Buffer.concat(bytes)) + } + + throw new Error('Invalid type to construct a XChainAttestationBatch') + } + + /** + * Read a XChainAttestationBatch from a BinaryParser + * + * @param parser BinaryParser to read the XChainAttestationBatch from + * @returns A XChainAttestationBatch object + */ + static fromParser(parser: BinaryParser): XChainAttestationBatch { + const bytes: Array = [] + + this.TYPE_ORDER.forEach((item) => { + const { type } = item + const object = type.fromParser(parser) + bytes.push(object.toBytes()) + }) + + return new XChainAttestationBatch(Buffer.concat(bytes)) + } + + /** + * Get the JSON representation of this XChainAttestationBatch + * + * @returns the JSON interpretation of this.bytes + */ + toJSON(): XChainAttestationBatchObject { + const parser = new BinaryParser(this.toString()) + const json = {} + XChainAttestationBatch.TYPE_ORDER.forEach((item) => { + const { name, type } = item + const object = type.fromParser(parser).toJSON() + json[name] = object + }) + return json as XChainAttestationBatchObject + } +} + +export { XChainAttestationBatch, XChainAttestationBatchObject } diff --git a/packages/ripple-binary-codec/src/types/xchain-bridge.ts b/packages/ripple-binary-codec/src/types/xchain-bridge.ts index ce4dc258..4870129a 100644 --- a/packages/ripple-binary-codec/src/types/xchain-bridge.ts +++ b/packages/ripple-binary-codec/src/types/xchain-bridge.ts @@ -9,10 +9,10 @@ import { IssuedCurrency, IssuedCurrencyObject } from './issued-currency' * Interface for JSON objects that represent cross-chain bridges */ interface XChainBridgeObject extends JsonObject { - dst_chain_door: string - dst_chain_issue: IssuedCurrencyObject | string - src_chain_door: string - src_chain_issue: IssuedCurrencyObject | string + LockingChainDoor: string + LockingChainIssue: IssuedCurrencyObject | string + IssuingChainDoor: string + IssuingChainIssue: IssuedCurrencyObject | string } /** diff --git a/packages/ripple-binary-codec/test/fixtures/codec-fixtures.json b/packages/ripple-binary-codec/test/fixtures/codec-fixtures.json index 006fe5b2..22f6aebe 100644 --- a/packages/ripple-binary-codec/test/fixtures/codec-fixtures.json +++ b/packages/ripple-binary-codec/test/fixtures/codec-fixtures.json @@ -4530,6 +4530,41 @@ "TxnSignature": "3045022100CA14E5FB5F30FC698119ED7E7D8F291E48A21693190A01AD89E140035476EE9D02206A642A396246C726739195D5D2CCC0635E1A67EDB84DEFBD54D42F7809F45F8B", "XChainClaimID": "0000000000000001" } + }, + { + "binary": "1200242280000000240000000468400000000000000A73210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD02074473045022100DCAC6A97BC4AA1379504FD5293FDFA46A4C216DDC13F3950F9692E0F803862A602206583360A60961E2988041E7E8589037A233771DCFB84E7A4710940A878EAFD7581142F3CC37C1D5616B3BBF1AABC49F6BFF46A920087011C14C48CAD01682D7A86296EF14523074D4852C02EA9000000000000000000000000000000000000000014CC86E58C9B58D4CF71CB8C1B41F21BB290CE13D40000000000000000000000000000000000000000E01C30140000000000000000614000000005F5E100712103DAB289CA36FF377F3F4304C7A7203FDE5EDCBFC209F430F6A4355361425526D0760361626381142F3CC37C1D5616B3BBF1AABC49F6BFF46A9200878314621D345F8F094A085132431C69C89EC05D212CC28014142F3CC37C1D5616B3BBF1AABC49F6BFF46A92008700101301E1F1F1", + "json": { + "Account" : "rnJmYAiqEVngtnb5ckRroXLtCbWC7CRUBx", + "Fee" : "10", + "Flags" : 2147483648, + "Sequence" : 4, + "SigningPubKey" : "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020", + "TransactionType" : "XChainAddAttestation", + "TxnSignature" : "3045022100DCAC6A97BC4AA1379504FD5293FDFA46A4C216DDC13F3950F9692E0F803862A602206583360A60961E2988041E7E8589037A233771DCFB84E7A4710940A878EAFD75", + "XChainAttestationBatch" : { + "XChainBridge" : { + "IssuingChainDoor" : "rKeSSvHvaMZJp9ykaxutVwkhZgWuWMLnQt", + "IssuingChainIssue" : "XRP", + "LockingChainDoor" : "rJvExveLEL4jNDEeLKCVdxaSCN9cEBnEQC", + "LockingChainIssue" : "XRP" + }, + "XChainClaimAttestationBatch" : [ + { + "XChainClaimAttestationBatchElement" : { + "Account" : "rnJmYAiqEVngtnb5ckRroXLtCbWC7CRUBx", + "Amount" : "100000000", + "AttestationRewardAccount" : "rnJmYAiqEVngtnb5ckRroXLtCbWC7CRUBx", + "Destination" : "r9A8UyNpW3X46FUc6P7JZqgn6WgAPjBwPg", + "PublicKey" : "03DAB289CA36FF377F3F4304C7A7203FDE5EDCBFC209F430F6A4355361425526D0", + "Signature" : "616263", + "WasLockingChainSend" : 1, + "XChainClaimID" : "0000000000000000" + } + } + ], + "XChainCreateAccountAttestationBatch" : [] + } + } } ], "ledgerData": [{