@radixdlt/tx-parser
Version:
Parsing of Radix Engine transactions and instructions
504 lines (454 loc) • 25.6 kB
text/typescript
import {
BaseInstructionWithSubState,
InstructionType,
SYSCALL_TX_FEE_RESERVE_PUT,
SYSCALL_TX_FEE_RESERVE_TAKE,
Transaction,
TransactionT,
Ins_SYSCALL,
Ins_UP,
InstructionT,
REAddressType,
SubStateType,
TokensT,
REAddressPublicKey,
} from '../src'
import { sha256Twice } from '@radixdlt/crypto'
import { UInt256 } from '@radixdlt/uint256'
import { err, ok, Result } from 'neverthrow'
import { msgFromError } from '@radixdlt/util'
let c_unit_tests_string = ''
export type TestVector = Readonly<{
blobHex: string
expected: {
parsedTX: string
// Used for total XRD amount calculation
myPublicKeyHex: string
txFee: string
totalXRDAmount: string
hash: string
}
}>
const generate_ledger_app_unit_test_c_code_from_test_vector = (
input: Readonly<{
testVector: TestVector
testName: string
testDescription?: string
}>,
): string => {
const { testVector, testName, testDescription } = input
const expectedHashHex = testVector.expected.hash
const expectedTxFee = testVector.expected.txFee
const expectedTotalXRDAmount = testVector.expected.totalXRDAmount
const myPublicKeyHex = testVector.expected.myPublicKeyHex
const chunkSubstr = (str: string, size: number): string[] => {
const numChunks = Math.ceil(str.length / size)
const chunks = new Array(numChunks)
for (let i = 0, o = 0; i < numChunks; ++i, o += size) {
chunks[i] = str.substr(o, size)
}
return chunks
}
const tx = Transaction.fromBuffer(
Buffer.from(testVector.blobHex, 'hex'),
)._unsafeUnwrap()
const descriptionOfTest =
testDescription ??
`Test of successful parsing of TX with #${
tx.toBuffer().length
} bytes and #${tx.instructions.length} instructions.`
const c_code_test_doc = `
/**
* @brief ${descriptionOfTest}.
*
* Test parsing transaction with blob:
* ${chunkSubstr(testVector.blobHex, 80).join('\n\t')}
*
* Deserializes into these instructions:
* ${chunkSubstr(tx.toString(), 80).join('\n\t')}
*
* Expected hash of transaction:
* ${testVector.expected.hash}
*
*/`
const c_code_test_header = `static void test_success_${testName}(void **state) {`
const sstOrIrrelevant = (instruction: InstructionT): string => {
const it = instruction.instructionType
if (!(it === InstructionType.UP)) {
return 'IRRELEVANT'
}
const substate = (instruction as BaseInstructionWithSubState<InstructionType>)
.substate
return `SUBSTATE_TYPE_${SubStateType[substate.substateType]}`
}
const c_code_body_expected_instructions_obj_strings = tx.instructions
.map(
(ins): string =>
`{
\t\t// clang-format off
\t\t.ins_hex = "${ins.toBuffer().toString('hex')}",
\t\t// clang-format on
\t\t.instruction_type = INS_${InstructionType[
ins.instructionType
].toUpperCase()},
\t\t.substate_type = ${sstOrIrrelevant(ins)},
}`,
)
.join(',\n')
const c_code_body_expected_instructions = [
'expected_instruction_t expected_instructions[] = {',
c_code_body_expected_instructions_obj_strings,
'}',
].join('\n')
const chunkArray = <T>(myArray: T[], chunk_size: number): T[][] => {
const results: T[][] = [] as T[][]
while (myArray.length) {
results.push(myArray.splice(0, chunk_size))
}
return results
}
const expectedHashAsUInt8ArrayString: string = chunkArray(
// @ts-ignore
[...Buffer.from(expectedHashHex, 'hex')],
8,
)
.map(array =>
array.map((byte: number) => `0x${byte.toString(16)}`).join(', '),
)
.join(',\n\t\t\t')
const c_code_test_vector = `
test_vector_t test_vector = (test_vector_t){
.total_number_of_instructions = ${tx.instructions.length},
.expected_instructions = expected_instructions,
.expected_result = EXPECTED_RESULT_SUCCESS,
.expected_success = {
.my_public_key_hex =
"${myPublicKeyHex}",
.expected_tx_fee = "${expectedTxFee}",
.expected_total_xrd_amount = "${expectedTotalXRDAmount}",
.expected_hash = { // clang-format off
\t\t\t${expectedHashAsUInt8ArrayString}
}, // clang-format on
}
}
`
const c_code_body = [
'\t(void) state',
c_code_body_expected_instructions,
c_code_test_vector,
'\tdo_test_parse_tx(test_vector);',
].join(';\n\n')
const c_code = [c_code_test_doc, c_code_test_header, c_code_body, '}'].join(
'\n',
)
return c_code
}
/*
Tx fee is calculated like so
=====================================================
Also a new syscall was added `FEE_RESERVE_TAKE (0x01)`, apart from old `FEE_RESERVE_PUT (0x00)` to be able
to claim back unused fees in the fee reserve. A general user transaction will look like:
```
DOWN <substate_id>
SYSCALL FEE_RESERVE_PUT <put_amt>
...
SYSCALL FEE_RESERVE_TAKE <take_amt0>
...
SYSCALL FEE_RESERVE_TAKE <take_amt1>
END
SIG <signature>
```
The corresponding fee paid in the transaction is then:
```
fee_paid = put_amt - sum(take_amt*)
```
There should only be one and only one put_amt value. There may be 0 or more take_amt values.
*/
const calculateFeeOfTransaction = (
transaction: TransactionT,
): Result<UInt256, Error> => {
const txFeeSysCallInsWithPrefix = (
prefix:
| typeof SYSCALL_TX_FEE_RESERVE_PUT
| typeof SYSCALL_TX_FEE_RESERVE_TAKE,
): Ins_SYSCALL[] =>
transaction.instructions
.filter(ins => ins.instructionType === InstructionType.SYSCALL)
.map(ins => ins as Ins_SYSCALL)
.filter(ins => ins.callData.data[0] === prefix)
const txFeePutInstructions = txFeeSysCallInsWithPrefix(
SYSCALL_TX_FEE_RESERVE_PUT,
)
if (txFeePutInstructions.length !== 1) {
const errMsg = `ERROR transaction fee did not contain one, and exacly one, SYSCALL with 'TX_FEE_RESERVE_PUT' (0x01 + UInt256), but that is required.`
return err(new Error(errMsg))
}
const amountFromIns = (instruction: Ins_SYSCALL): UInt256 =>
new UInt256(
instruction.callData.data
.slice(1) // we skip first byte, specifying that this is either TX_FEE_RESERVE_PUT or SYSCALL_TX_FEE_RESERVE_TAKE
.toString('hex'),
16,
)
// Earler asserted that we have one, and exactly one element.
const txFeePut = amountFromIns(txFeePutInstructions[0])
const txFeeTakenSum = txFeeSysCallInsWithPrefix(SYSCALL_TX_FEE_RESERVE_TAKE)
.map(amountFromIns)
.reduce((prev, cur) => prev.add(cur), UInt256.valueOf(0))
if (txFeeTakenSum.gt(txFeePut)) {
const errMsg = `ERROR: Sum of 'txFeeTakenSum' exceeds 'txFeePut', which is not allowed.`
return err(new Error(errMsg))
}
return ok(txFeePut.sub(txFeeTakenSum))
}
const amountOfXRDTransferredOutInTX = (
transaction: TransactionT,
myPublicKeyHex: string,
): UInt256 =>
transaction.instructions
.filter(ins => ins.instructionType === InstructionType.UP)
.map(ins => ins as Ins_UP)
.filter(insUp => insUp.substate.substateType === SubStateType.TOKENS)
.map(insUp => insUp.substate as TokensT)
.filter(
tokens =>
tokens.resource.reAddressType ===
REAddressType.RADIX_NATIVE_TOKEN,
)
.filter((xrdTokens): boolean => {
const lhs = (xrdTokens.owner as REAddressPublicKey).publicKey.toString(
true,
)
const isChangeBackToMe = lhs === myPublicKeyHex
return !isChangeBackToMe
})
.map(xrdTokens => xrdTokens.amount)
.reduce((prev, cur) => prev.add(cur), UInt256.valueOf(0))
const doTestParseTX = (testVector: TestVector): void => {
const { blobHex, expected } = testVector
const blob = Buffer.from(blobHex, 'hex')
const txRes = Transaction.fromBuffer(blob)
if (txRes.isErr()) {
throw txRes.error
}
const parsedTx: TransactionT = txRes.value
// console.log(parsedTx.toString())
expect(parsedTx.toString()).toBe(expected.parsedTX)
const hash = sha256Twice(blob)
expect(hash.toString('hex')).toBe(expected.hash)
const txFeeResult = calculateFeeOfTransaction(parsedTx)
if (txFeeResult.isErr()) {
console.error(
`Failed to calculated tx fee, underlying error: ${msgFromError(
txFeeResult.error,
)}`,
)
return
}
const txFee = txFeeResult.value
const xrdSentOut = amountOfXRDTransferredOutInTX(
parsedTx,
expected.myPublicKeyHex,
)
const totalXRDCost = txFee.add(xrdSentOut)
expect(txFee.toString(10)).toBe(expected.txFee)
expect(totalXRDCost.toString(10)).toBe(expected.totalXRDAmount)
const c_unit_test_code_string_from_vector = generate_ledger_app_unit_test_c_code_from_test_vector(
{
testVector,
testName: expect.getState().currentTestName.split(' ')[1],
},
)
c_unit_tests_string = `${c_unit_tests_string}\n\n${c_unit_test_code_string_from_vector}`
}
describe('txParser', () => {
afterAll(() => {
// Use log below to output C unit tests string.
// console.log(c_unit_tests_string)
})
it('xrd_transfer', () => {
doTestParseTX({
blobHex:
'0d000107b4bfd245c716b406cccdb58596b965e6951af29571702270a9eba8e3362d150b00000000010021000000000000000000000000000000000000000000000000000101ed50bab1800002004506000403309a4981ca993d79ca165de3895fd9e44f809a03c977172884548112d139a73a0100000000000000000000000000000000000000000000d38be090e7bccda580000008000002004506000403309a4981ca993d79ca165de3895fd9e44f809a03c977172884548112d139a73a0100000000000000000000000000000000000000000000d355aac739f6ef0580000200450600040385be69c03154ba40a0a3ea8d06d31e256b1bdb4f6753543db88d2b173f4b5dfd0100000000000000000000000000000000000000000000003635c9adc5dea00000000b00234e8e56bb04ab91222579e882d7571418f8e97f03d280e84af6261a6873524e17a0f80f937701d36f51128947e117b18cb52b42350655ddb10a4b3c3415f224',
expected: {
parsedTX: `Instructions:
|- HEADER(0, 1)
|- DOWN(SubstateId { hash: 0xb4bfd245c716b406cccdb58596b965e6951af29571702270a9eba8e3362d150b, index: 0 })
|- SYSCALL(0x000000000000000000000000000000000000000000000000000101ed50bab18000)
|- UP(Tokens { reserved: 0, owner: 0x0403309a4981ca993d79ca165de3895fd9e44f809a03c977172884548112d139a73a, resource: 0x01, amount: U256 { raw: 998999607000000000000000 } })
|- END
|- LDOWN(0)
|- UP(Tokens { reserved: 0, owner: 0x0403309a4981ca993d79ca165de3895fd9e44f809a03c977172884548112d139a73a, resource: 0x01, amount: U256 { raw: 997999607000000000000000 } })
|- UP(Tokens { reserved: 0, owner: 0x040385be69c03154ba40a0a3ea8d06d31e256b1bdb4f6753543db88d2b173f4b5dfd, resource: 0x01, amount: U256 { raw: 1000000000000000000000 } })
|- END
|- SIG(0x00234e8e56bb04ab91222579e882d7571418f8e97f03d280e84af6261a6873524e17a0f80f937701d36f51128947e117b18cb52b42350655ddb10a4b3c3415f224)`,
hash:
'ba49cfd87e82f91ee9f0e968475322bb7941006b7f3ef4753925a657dd38d286',
myPublicKeyHex:
'0356959464545aa2787984fe4ac76496721a22f150c0076724ad7190fe3a597bb7',
txFee: '72600000000000000',
totalXRDAmount: '1997999286600000000000000',
},
})
})
it('xrd_transfer_with_msg', () => {
doTestParseTX({
blobHex:
'0d000107ba49cfd87e82f91ee9f0e968475322bb7941006b7f3ef4753925a657dd38d286000000010100210000000000000000000000000000000000000000000000000001079c81c255800002004506000403309a4981ca993d79ca165de3895fd9e44f809a03c977172884548112d139a73a0100000000000000000000000000000000000000000000d355a9bf9d752cb000000008000002004506000403309a4981ca993d79ca165de3895fd9e44f809a03c977172884548112d139a73a0100000000000000000000000000000000000000000000d355645c0bf2e7bc00000200450600040385be69c03154ba40a0a3ea8d06d31e256b1bdb4f6753543db88d2b173f4b5dfd010000000000000000000000000000000000000000000000004563918244f40000000c000548656c6c6f0b001695e237a5d7a0ffba78dee7163e8c6b8c4596fb95f376a07cbb4aa08bf6ba1d599d27f8ca1aa2b13d2c7172aa2684b0687ea211495890688fc19b9975510a7d',
expected: {
parsedTX: `Instructions:
|- HEADER(0, 1)
|- DOWN(SubstateId { hash: 0xba49cfd87e82f91ee9f0e968475322bb7941006b7f3ef4753925a657dd38d286, index: 1 })
|- SYSCALL(0x0000000000000000000000000000000000000000000000000001079c81c2558000)
|- UP(Tokens { reserved: 0, owner: 0x0403309a4981ca993d79ca165de3895fd9e44f809a03c977172884548112d139a73a, resource: 0x01, amount: U256 { raw: 997999532800000000000000 } })
|- END
|- LDOWN(0)
|- UP(Tokens { reserved: 0, owner: 0x0403309a4981ca993d79ca165de3895fd9e44f809a03c977172884548112d139a73a, resource: 0x01, amount: U256 { raw: 997994532800000000000000 } })
|- UP(Tokens { reserved: 0, owner: 0x040385be69c03154ba40a0a3ea8d06d31e256b1bdb4f6753543db88d2b173f4b5dfd, resource: 0x01, amount: U256 { raw: 5000000000000000000 } })
|- END
|- MSG(0x48656c6c6f)
|- SIG(0x001695e237a5d7a0ffba78dee7163e8c6b8c4596fb95f376a07cbb4aa08bf6ba1d599d27f8ca1aa2b13d2c7172aa2684b0687ea211495890688fc19b9975510a7d)`,
hash:
'0a44ddfbad1047458561e1d09489ac7666314c1f6d77c9523cf20c445a5dcf56',
myPublicKeyHex:
'0356959464545aa2787984fe4ac76496721a22f150c0076724ad7190fe3a597bb7',
txFee: '74200000000000000',
totalXRDAmount: '1995999139800000000000000',
},
})
})
it('other_transfer_mixed_tokens', () => {
doTestParseTX({
blobHex:
'0d000107d71f8018869fb932ed4a463678d9c4e650c7e1f72cb7c61d82e16983d14a5f8c000000010100210000000000000000000000000000000000000000000000000001a831aada2e8000020045060004029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa0100000000000000000000000000000000000000000000d34a4147716d5def000000080000020045060004029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa0100000000000000000000000000000000000000000000d349fbe3dfeb18fb0000020045060004036af8f04dbb33483c1625465aa2b1401209fa11df02562e695f47bfe4a665e685010000000000000000000000000000000000000000000000004563918244f400000007bb2296555f1f1fc25dc85aeacc0feab2aef286d951e827e3b9d7b18538308cd00000000102005f060004029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa03cafbe65ab9e445ff25cdf9b4534a8dc6bdfa44c880758ce6c35b000000000000000000000000000000000000000000000000000000000000000502005f060004036af8f04dbb33483c1625465aa2b1401209fa11df02562e695f47bfe4a665e68503cafbe65ab9e445ff25cdf9b4534a8dc6bdfa44c880758ce6c35b0000000000000000000000000000000000000000000000000000000000000002000b0019edc25a02deff61e8eee3f2519cfaf751935c7c98ce0ed6b1c877a5903c79b158b530ebe4d3680ab7a14895169bd73620bea2372a52ca8afe7de210f12f2ff6',
expected: {
parsedTX: `Instructions:
|- HEADER(0, 1)
|- DOWN(SubstateId { hash: 0xd71f8018869fb932ed4a463678d9c4e650c7e1f72cb7c61d82e16983d14a5f8c, index: 1 })
|- SYSCALL(0x0000000000000000000000000000000000000000000000000001a831aada2e8000)
|- UP(Tokens { reserved: 0, owner: 0x04029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa, resource: 0x01, amount: U256 { raw: 997789090800000000000000 } })
|- END
|- LDOWN(0)
|- UP(Tokens { reserved: 0, owner: 0x04029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa, resource: 0x01, amount: U256 { raw: 997784090800000000000000 } })
|- UP(Tokens { reserved: 0, owner: 0x04036af8f04dbb33483c1625465aa2b1401209fa11df02562e695f47bfe4a665e685, resource: 0x01, amount: U256 { raw: 5000000000000000000 } })
|- END
|- DOWN(SubstateId { hash: 0xbb2296555f1f1fc25dc85aeacc0feab2aef286d951e827e3b9d7b18538308cd0, index: 1 })
|- UP(Tokens { reserved: 0, owner: 0x04029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa, resource: 0x03cafbe65ab9e445ff25cdf9b4534a8dc6bdfa44c880758ce6c35b, amount: U256 { raw: 5 } })
|- UP(Tokens { reserved: 0, owner: 0x04036af8f04dbb33483c1625465aa2b1401209fa11df02562e695f47bfe4a665e685, resource: 0x03cafbe65ab9e445ff25cdf9b4534a8dc6bdfa44c880758ce6c35b, amount: U256 { raw: 2 } })
|- END
|- SIG(0x0019edc25a02deff61e8eee3f2519cfaf751935c7c98ce0ed6b1c877a5903c79b158b530ebe4d3680ab7a14895169bd73620bea2372a52ca8afe7de210f12f2ff6)`,
hash:
'9335840aa4d08ed3691d1d6c641c0bdea9dfc707fdd0a984e078203a73493ef6',
myPublicKeyHex:
'0356959464545aa2787984fe4ac76496721a22f150c0076724ad7190fe3a597bb7',
txFee: '119400000000000000',
totalXRDAmount: '1995578301000000000000000',
},
})
})
it('other_transfer_to_self', () => {
doTestParseTX({
blobHex:
'0d0001071c5adcb82ecf26e963e76dec2f38fff11ae377f7c28f9f731d9540c1aa86a53100000000010021000000000000000000000000000000000000000000000000000101ed50bab18000020045060004029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa0100000000000000000000000000000000000000000000d34a8853349a7d11800000080000020045060004029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa0100000000000000000000000000000000000000000000d34a42efa318381d8000020045060004029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa010000000000000000000000000000000000000000000000004563918244f40000000b0099a36704279db19e3b13b13a49895eb572a02479383616eecb26d16864c4abcf5397a9c12776902b62ac48c29ed8dc334f03a990bb8515a6db78e56a1f27d721',
expected: {
parsedTX: `Instructions:
|- HEADER(0, 1)
|- DOWN(SubstateId { hash: 0x1c5adcb82ecf26e963e76dec2f38fff11ae377f7c28f9f731d9540c1aa86a531, index: 0 })
|- SYSCALL(0x000000000000000000000000000000000000000000000000000101ed50bab18000)
|- UP(Tokens { reserved: 0, owner: 0x04029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa, resource: 0x01, amount: U256 { raw: 997794210200000000000000 } })
|- END
|- LDOWN(0)
|- UP(Tokens { reserved: 0, owner: 0x04029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa, resource: 0x01, amount: U256 { raw: 997789210200000000000000 } })
|- UP(Tokens { reserved: 0, owner: 0x04029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa, resource: 0x01, amount: U256 { raw: 5000000000000000000 } })
|- END
|- SIG(0x0099a36704279db19e3b13b13a49895eb572a02479383616eecb26d16864c4abcf5397a9c12776902b62ac48c29ed8dc334f03a990bb8515a6db78e56a1f27d721)`,
hash:
'd71f8018869fb932ed4a463678d9c4e650c7e1f72cb7c61d82e16983d14a5f8c',
myPublicKeyHex:
'02935deebcad35bcf27d05b431276be8fcba26312cd1d54c33ac6748a72fe427ca',
txFee: '72600000000000000',
totalXRDAmount: '1995588493000000000000000',
},
})
})
it('token_transfer_and_stake', () => {
doTestParseTX({
blobHex:
'0d0001076a950e22681f3db30ab6fd4714815443fb680249ea07d65adee004a46a80daac0000000001002100000000000000000000000000000000000000000000000000017efb8762c980000200450600040385be69c03154ba40a0a3ea8d06d31e256b1bdb4f6753543db88d2b173f4b5dfd01000000000000000000000000000000000000000000000036326a5e8f76348000000800000200450600040385be69c03154ba40a0a3ea8d06d31e256b1bdb4f6753543db88d2b173f4b5dfd0100000000000000000000000000000000000000000000002b5adba234b014800005004529f251379200c559e01b8e3fb7b4c7cf9bf23279dc6ebd26ba20a5f4e88c772e000000050385be69c03154ba40a0a3ea8d06d31e256b1bdb4f6753543db88d2b173f4b5dfd05004529f251379200c559e01b8e3fb7b4c7cf9bf23279dc6ebd26ba20a5f4e88c772e000000080385be69c03154ba40a0a3ea8d06d31e256b1bdb4f6753543db88d2b173f4b5dfd02006507000385be69c03154ba40a0a3ea8d06d31e256b1bdb4f6753543db88d2b173f4b5dfd040385be69c03154ba40a0a3ea8d06d31e256b1bdb4f6753543db88d2b173f4b5dfd00000000000000000000000000000000000000000000000ad78ebc5ac6200000000b0094a8feb4342b299349a89e2c3829dd594a6c8bafed54f710490a676ad558d0f40892c5d0bbac5849b0fe814e0cb578367178bf297a9114686a1e967da1e7e8e1',
expected: {
parsedTX: `Instructions:
|- HEADER(0, 1)
|- DOWN(SubstateId { hash: 0x6a950e22681f3db30ab6fd4714815443fb680249ea07d65adee004a46a80daac, index: 0 })
|- SYSCALL(0x00000000000000000000000000000000000000000000000000017efb8762c98000)
|- UP(Tokens { reserved: 0, owner: 0x040385be69c03154ba40a0a3ea8d06d31e256b1bdb4f6753543db88d2b173f4b5dfd, resource: 0x01, amount: U256 { raw: 999757000000000000000 } })
|- END
|- LDOWN(0)
|- UP(Tokens { reserved: 0, owner: 0x040385be69c03154ba40a0a3ea8d06d31e256b1bdb4f6753543db88d2b173f4b5dfd, resource: 0x01, amount: U256 { raw: 799757000000000000000 } })
|- VREAD(0x29f251379200c559e01b8e3fb7b4c7cf9bf23279dc6ebd26ba20a5f4e88c772e000000050385be69c03154ba40a0a3ea8d06d31e256b1bdb4f6753543db88d2b173f4b5dfd)
|- VREAD(0x29f251379200c559e01b8e3fb7b4c7cf9bf23279dc6ebd26ba20a5f4e88c772e000000080385be69c03154ba40a0a3ea8d06d31e256b1bdb4f6753543db88d2b173f4b5dfd)
|- UP(PreparedStake { reserved: 0, validator: 0x0385be69c03154ba40a0a3ea8d06d31e256b1bdb4f6753543db88d2b173f4b5dfd, owner: 0x040385be69c03154ba40a0a3ea8d06d31e256b1bdb4f6753543db88d2b173f4b5dfd, amount: U256 { raw: 200000000000000000000 } })
|- END
|- SIG(0x0094a8feb4342b299349a89e2c3829dd594a6c8bafed54f710490a676ad558d0f40892c5d0bbac5849b0fe814e0cb578367178bf297a9114686a1e967da1e7e8e1)`,
hash:
'72189a80b2abee07ba570c0a1beb917b47270ea8522a49e1e96524ed9112f271',
myPublicKeyHex:
'0356959464545aa2787984fe4ac76496721a22f150c0076724ad7190fe3a597bb7',
txFee: '107800000000000000',
totalXRDAmount: '1799621800000000000000',
},
})
})
it('xrd_unstake1', () => {
doTestParseTX({
blobHex:
'0d000107a2cefec04d21ff7b6ea946a4d7a11e26777102e0dad02b6281cb21b2389733d2000000010100210000000000000000000000000000000000000000000000000001478f69584a8000020045060004029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa0100000000000000000000000000000000000000000000d34a8a52cbd72cb98000000735175589cb15e07085a1d5b767a7a37c78b288a0ce3ffdd44b55bd1ea75a01fa000000010200650800036af8f04dbb33483c1625465aa2b1401209fa11df02562e695f47bfe4a665e68504029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa0000000000000000000000000000000000000000000000056bc75e2d631000000200650900036af8f04dbb33483c1625465aa2b1401209fa11df02562e695f47bfe4a665e68504029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa0000000000000000000000000000000000000000000000056bc75e2d63100000000b0117adf57ee50349481c963ce2085c9f1d6352328b325ba602fde904cb76c300dc51c602387642a9cddb852db06789bd23beaf0ccfa2766fe942c51cbad7a26147',
expected: {
parsedTX: `Instructions:
|- HEADER(0, 1)
|- DOWN(SubstateId { hash: 0xa2cefec04d21ff7b6ea946a4d7a11e26777102e0dad02b6281cb21b2389733d2, index: 1 })
|- SYSCALL(0x0000000000000000000000000000000000000000000000000001478f69584a8000)
|- UP(Tokens { reserved: 0, owner: 0x04029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa, resource: 0x01, amount: U256 { raw: 997794354200000000000000 } })
|- END
|- DOWN(SubstateId { hash: 0x35175589cb15e07085a1d5b767a7a37c78b288a0ce3ffdd44b55bd1ea75a01fa, index: 1 })
|- UP(StakeOwnership { reserved: 0, validator: 0x036af8f04dbb33483c1625465aa2b1401209fa11df02562e695f47bfe4a665e685, owner: 0x04029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa, amount: U256 { raw: 100000000000000000000 } })
|- UP(PreparedUnstake { reserved: 0, validator: 0x036af8f04dbb33483c1625465aa2b1401209fa11df02562e695f47bfe4a665e685, owner: 0x04029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa, amount: U256 { raw: 100000000000000000000 } })
|- END
|- SIG(0x0117adf57ee50349481c963ce2085c9f1d6352328b325ba602fde904cb76c300dc51c602387642a9cddb852db06789bd23beaf0ccfa2766fe942c51cbad7a26147)`,
hash:
'200eb974d933c1d67daee117b996fc9e63f24666bf58479bf2a9b8168b28c5d3',
myPublicKeyHex:
'0356959464545aa2787984fe4ac76496721a22f150c0076724ad7190fe3a597bb7',
txFee: '92200000000000000',
totalXRDAmount: '997794446400000000000000',
},
})
})
it('complex_fee', () => {
doTestParseTX({
blobHex:
'0d0001079335840aa4d08ed3691d1d6c641c0bdea9dfc707fdd0a984e078203a73493ef600000001010021000000000000000000000000000000000000000000000000004563918244f40000020045060004029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa0100000000000000000000000000000000000000000000d349b6804e68d407000000079335840aa4d08ed3691d1d6c641c0bdea9dfc707fdd0a984e078203a73493ef60000000302005f060004029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa03cafbe65ab9e445ff25cdf9b4534a8dc6bdfa44c880758ce6c35b000000000000000000000000000000000000000000000000000000000000000302005f060004036af8f04dbb33483c1625465aa2b1401209fa11df02562e695f47bfe4a665e68503cafbe65ab9e445ff25cdf9b4534a8dc6bdfa44c880758ce6c35b0000000000000000000000000000000000000000000000000000000000000002000100210100000000000000000000000000000000000000000000000043d715e670050000020045060004029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa0100000000000000000000000000000000000000000000000043d715e670050000000b002732c2213648ba2edad9d69560d50be7f497ec7a6d010c155e9a8b552235718502aa68fc2b82fb384a2252c5f3c18e93b71c893b07911cbe569c5caf3aea0509',
expected: {
parsedTX: `Instructions:
|- HEADER(0, 1)
|- DOWN(SubstateId { hash: 0x9335840aa4d08ed3691d1d6c641c0bdea9dfc707fdd0a984e078203a73493ef6, index: 1 })
|- SYSCALL(0x000000000000000000000000000000000000000000000000004563918244f40000)
|- UP(Tokens { reserved: 0, owner: 0x04029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa, resource: 0x01, amount: U256 { raw: 997779090800000000000000 } })
|- END
|- DOWN(SubstateId { hash: 0x9335840aa4d08ed3691d1d6c641c0bdea9dfc707fdd0a984e078203a73493ef6, index: 3 })
|- UP(Tokens { reserved: 0, owner: 0x04029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa, resource: 0x03cafbe65ab9e445ff25cdf9b4534a8dc6bdfa44c880758ce6c35b, amount: U256 { raw: 3 } })
|- UP(Tokens { reserved: 0, owner: 0x04036af8f04dbb33483c1625465aa2b1401209fa11df02562e695f47bfe4a665e685, resource: 0x03cafbe65ab9e445ff25cdf9b4534a8dc6bdfa44c880758ce6c35b, amount: U256 { raw: 2 } })
|- END
|- SYSCALL(0x0100000000000000000000000000000000000000000000000043d715e670050000)
|- UP(Tokens { reserved: 0, owner: 0x04029f41bb89ffa243e86fb05d15c6e67c4b48f1bb2a19cd3ea1650bc50287cc0ffa, resource: 0x01, amount: U256 { raw: 4888400000000000000 } })
|- END
|- SIG(0x002732c2213648ba2edad9d69560d50be7f497ec7a6d010c155e9a8b552235718502aa68fc2b82fb384a2252c5f3c18e93b71c893b07911cbe569c5caf3aea0509)`,
hash:
'37c8199ff479cdb53063af2f281b7a9c2a809df6ebd74ea11dc30c14d5a9b05d',
myPublicKeyHex:
'0356959464545aa2787984fe4ac76496721a22f150c0076724ad7190fe3a597bb7',
txFee: '111600000000000000',
totalXRDAmount: '997784090800000000000000',
},
})
})
})