diff --git a/src/tx/builder/field-types/array.ts b/src/tx/builder/field-types/array.ts
index ab6ae3dee1..ede6bb42e7 100644
--- a/src/tx/builder/field-types/array.ts
+++ b/src/tx/builder/field-types/array.ts
@@ -4,7 +4,7 @@ export default function genArrayField(
deserialize: (value: Binary, params: unknown) => Output;
},
): {
- serialize: (value: Input[], params: unknown) => Binary[];
+ serialize: (value: readonly Input[], params: unknown) => Binary[];
deserialize: (value: Binary[], params: unknown) => Output[];
} {
return {
diff --git a/src/tx/builder/field-types/entry.ts b/src/tx/builder/field-types/entry.ts
index 25ca0c614a..5507853ffe 100644
--- a/src/tx/builder/field-types/entry.ts
+++ b/src/tx/builder/field-types/entry.ts
@@ -7,14 +7,14 @@ import type { unpackTx as unpackTxType, buildTx as buildTxType } from '../index'
export default function genEntryField(tag?: T): {
serialize: (
- // TODO: replace with `Parameters>[0]`,
+ // TODO: replace with `TxParams & { tag: T }`,
// but fix TS2502 value is referenced directly or indirectly in its own type annotation
value: any,
options: { buildTx: typeof buildTxType },
) => Buffer;
deserialize: (
value: Buffer, options: { unpackTx: typeof unpackTxType },
- // TODO: replace with `ReturnType>`,
+ // TODO: replace with `TxUnpacked & { tag: T }`,
// TS2577 Return type annotation circularly references itself
) => any;
} {
diff --git a/src/tx/builder/field-types/index.ts b/src/tx/builder/field-types/index.ts
index 02bc29746e..2f6d1d4ac5 100644
--- a/src/tx/builder/field-types/index.ts
+++ b/src/tx/builder/field-types/index.ts
@@ -12,6 +12,7 @@ import _fee from './fee';
import _field from './field';
import _gasLimit from './gas-limit';
import _gasPrice from './gas-price';
+import _map from './map';
import _mptree from './mptree';
import _name from './name';
import _nameFee from './name-fee';
@@ -24,6 +25,7 @@ import _shortUIntConst from './short-u-int-const';
import _string from './string';
import _ttl from './ttl';
import _uInt from './u-int';
+import _wrapped from './wrapped';
// TODO: remove after fixing https://github.com/Gerrit0/typedoc-plugin-missing-exports/issues/15
const abiVersion = _abiVersion;
@@ -40,6 +42,7 @@ const fee = _fee;
const field = _field;
const gasLimit = _gasLimit;
const gasPrice = _gasPrice;
+const map = _map;
const mptree = _mptree;
const name = _name;
const nameFee = _nameFee;
@@ -52,6 +55,7 @@ const shortUIntConst = _shortUIntConst;
const string = _string;
const ttl = _ttl;
const uInt = _uInt;
+const wrapped = _wrapped;
export type BinaryData = Buffer | Buffer[] | Buffer[][]
| Array<[Buffer, Array<[Buffer, Buffer[]]>]>;
@@ -77,6 +81,7 @@ export {
field,
gasLimit,
gasPrice,
+ map,
mptree,
name,
nameFee,
@@ -89,4 +94,5 @@ export {
string,
ttl,
uInt,
+ wrapped,
};
diff --git a/src/tx/builder/field-types/map.ts b/src/tx/builder/field-types/map.ts
new file mode 100644
index 0000000000..f1e4519700
--- /dev/null
+++ b/src/tx/builder/field-types/map.ts
@@ -0,0 +1,45 @@
+import { Tag } from '../constants';
+import {
+ encode, Encoding, Encoded, decode,
+} from '../../../utils/encoder';
+import type { unpackTx as unpackTxType, buildTx as buildTxType } from '../index';
+
+export default function genMapField(encoding: E, tag: T): {
+ serialize: (
+ // TODO: replace with `TxParams & { tag: T }`,
+ // but fix TS2502 value is referenced directly or indirectly in its own type annotation
+ value: Record, any>, options: { buildTx: typeof buildTxType }
+ ) => Buffer;
+ deserialize: (
+ value: Buffer, options: { unpackTx: typeof unpackTxType },
+ // TODO: replace with `TxUnpacked & { tag: T }`,
+ // TS2577 Return type annotation circularly references itself
+ ) => Record, any>;
+ recursiveType: true;
+} {
+ return {
+ serialize(object, { buildTx }) {
+ return decode(buildTx({
+ tag: Tag.Mtree,
+ values: Object.entries(object).map(([key, value]) => ({
+ tag: Tag.MtreeValue,
+ key: decode(key as Encoded.Generic),
+ value: decode(buildTx({ ...value as any, tag })),
+ })),
+ }));
+ },
+
+ deserialize(buffer, { unpackTx }) {
+ const { values } = unpackTx(encode(buffer, Encoding.Transaction), Tag.Mtree);
+ return Object.fromEntries(values
+ // TODO: remove after resolving https://github.com/aeternity/aeternity/issues/4066
+ .filter(({ key }) => encoding !== Encoding.ContractAddress || key.length === 32)
+ .map(({ key, value }) => [
+ encode(key, encoding),
+ unpackTx(encode(value, Encoding.Transaction), tag),
+ ])) as Record, any>;
+ },
+
+ recursiveType: true,
+ };
+}
diff --git a/src/tx/builder/field-types/wrapped.ts b/src/tx/builder/field-types/wrapped.ts
new file mode 100644
index 0000000000..373c13a98c
--- /dev/null
+++ b/src/tx/builder/field-types/wrapped.ts
@@ -0,0 +1,32 @@
+import { Tag } from '../constants';
+import { encode, Encoding, decode } from '../../../utils/encoder';
+import type { unpackTx as unpackTxType, buildTx as buildTxType } from '../index';
+
+type TagWrapping = Tag.AccountsMtree | Tag.CallsMtree | Tag.ChannelsMtree | Tag.ContractsMtree
+| Tag.NameserviceMtree | Tag.OraclesMtree;
+
+export default function genWrappedField(tag: T): {
+ serialize: (
+ // TODO: replace with `(TxParams & { tag: T })['payload']`,
+ // but fix TS2502 value is referenced directly or indirectly in its own type annotation
+ value: any, options: { buildTx: typeof buildTxType }
+ ) => Buffer;
+ deserialize: (
+ value: Buffer, options: { unpackTx: typeof unpackTxType },
+ // TODO: replace with `(TxUnpacked & { tag: T })['payload']`,
+ // TS2577 Return type annotation circularly references itself
+ ) => any;
+ recursiveType: true;
+} {
+ return {
+ serialize(payload, { buildTx }) {
+ return decode(buildTx({ tag, payload }));
+ },
+
+ deserialize(buffer, { unpackTx }) {
+ return unpackTx(encode(buffer, Encoding.Transaction), tag).payload;
+ },
+
+ recursiveType: true,
+ };
+}
diff --git a/src/tx/builder/index.ts b/src/tx/builder/index.ts
index 7ebcb533bb..c8568dfbfb 100644
--- a/src/tx/builder/index.ts
+++ b/src/tx/builder/index.ts
@@ -93,7 +93,7 @@ export async function buildTxAsync(params: TxParamsAsync): Promise(
- encodedTx: Encoded.Transaction | Encoded.Poi,
+ encodedTx: Encoded.Transaction | Encoded.Poi | Encoded.StateTrees | Encoded.CallStateTree,
txType?: TxType,
): TxUnpacked & { tag: TxType } {
const binary = rlpDecode(decode(encodedTx));
diff --git a/src/tx/builder/schema.ts b/src/tx/builder/schema.ts
index a0c0a6db7d..61822b2f25 100644
--- a/src/tx/builder/schema.ts
+++ b/src/tx/builder/schema.ts
@@ -9,7 +9,7 @@ import SchemaTypes from './SchemaTypes';
import {
uInt, shortUInt, coinAmount, name, nameId, nameFee, deposit, gasLimit, gasPrice, fee,
address, pointers, entry, enumeration, mptree, shortUIntConst, string, encoded, raw,
- array, boolean, ctVersion, abiVersion, ttl, nonce,
+ array, boolean, ctVersion, abiVersion, ttl, nonce, map, wrapped,
} from './field-types';
import { Encoded, Encoding } from '../../utils/encoder';
import { idTagToEncoding } from './field-types/address';
@@ -43,21 +43,88 @@ interface EntryAny {
recursiveType: true;
}
-interface EntryAnyArray {
- serialize: (value: Array) => Buffer[];
- deserialize: (value: Buffer[]) => TxUnpacked[];
+const entryAny = entry() as unknown as EntryAny;
+
+interface EntryMtreeValueArray {
+ serialize: (
+ value: Array,
+ ) => Buffer[];
+ deserialize: (value: Buffer[]) => Array;
recursiveType: true;
}
+const entryMtreeValueArray = array(entry(Tag.MtreeValue)) as unknown as EntryMtreeValueArray;
+
interface EntryTreesPoi {
serialize: (value: TxParams & { tag: Tag.TreesPoi } | Uint8Array | Encoded.Transaction) => Buffer;
deserialize: (value: Buffer) => TxUnpacked & { tag: Tag.TreesPoi };
recursiveType: true;
}
-const entryAny = entry() as unknown as EntryAny;
const entryTreesPoi = entry(Tag.TreesPoi) as unknown as EntryTreesPoi;
+interface MapContracts {
+ serialize: (
+ value: Record,
+ ) => Buffer;
+ deserialize: (
+ value: Buffer,
+ ) => Record;
+ recursiveType: true;
+}
+
+const mapContracts = map(Encoding.ContractAddress, Tag.Contract) as unknown as MapContracts;
+
+interface MapAccounts {
+ serialize: (
+ value: Record,
+ ) => Buffer;
+ deserialize: (value: Buffer) => Record;
+ recursiveType: true;
+}
+
+const mapAccounts = map(Encoding.AccountAddress, Tag.Account) as unknown as MapAccounts;
+
+interface MapCalls {
+ serialize: (
+ value: Record,
+ ) => Buffer;
+ deserialize: (value: Buffer) => Record;
+ recursiveType: true;
+}
+
+const mapCalls = map(Encoding.Bytearray, Tag.ContractCall) as unknown as MapCalls;
+
+interface MapChannels {
+ serialize: (
+ value: Record,
+ ) => Buffer;
+ deserialize: (value: Buffer) => Record;
+ recursiveType: true;
+}
+
+const mapChannels = map(Encoding.Channel, Tag.Channel) as unknown as MapChannels;
+
+interface MapNames {
+ serialize: (
+ value: Record,
+ ) => Buffer;
+ deserialize: (value: Buffer) => Record;
+ recursiveType: true;
+}
+
+const mapNames = map(Encoding.Name, Tag.Name) as unknown as MapNames;
+
+interface MapOracles {
+ serialize: (
+ value: Record,
+ ) => Buffer;
+ deserialize: (value: Buffer) => Record;
+ recursiveType: true;
+}
+
+const mapOracles = map(Encoding.OracleAddress, Tag.Oracle) as unknown as MapOracles;
+
/**
* @see {@link https://github.com/aeternity/protocol/blob/c007deeac4a01e401238412801ac7084ac72d60e/serializations.md#accounts-version-1-basic-accounts}
*/
@@ -182,18 +249,19 @@ export const txSchema = [{
callData: encoded(Encoding.ContractBytearray),
}, {
tag: shortUIntConst(Tag.ContractCall),
- version: shortUIntConst(1, true),
+ version: shortUIntConst(2, true),
callerId: address(Encoding.AccountAddress),
callerNonce: shortUInt,
height: shortUInt,
contractId: address(Encoding.ContractAddress),
- gasPrice,
+ // TODO: rename after resolving https://github.com/aeternity/protocol/issues/506
+ gasPrice: uInt,
gasUsed: shortUInt,
returnValue: encoded(Encoding.ContractBytearray),
returnType: enumeration(CallReturnType),
// TODO: add serialization for
// :: [ { :: id, [ :: binary() }, :: binary() } ]
- log: raw,
+ log: array(raw),
}, {
tag: shortUIntConst(Tag.Oracle),
version: shortUIntConst(1, true),
@@ -418,6 +486,7 @@ export const txSchema = [{
}, {
tag: shortUIntConst(Tag.TreesPoi),
version: shortUIntConst(1, true),
+ // TODO: inline an extra wrapping array after resolving https://github.com/aeternity/protocol/issues/505
accounts: array(mptree(Encoding.AccountAddress, Tag.Account)),
calls: array(mptree(Encoding.Bytearray, Tag.ContractCall)),
channels: array(mptree(Encoding.Channel, Tag.Channel)),
@@ -426,17 +495,17 @@ export const txSchema = [{
oracles: array(mptree(Encoding.OracleAddress, Tag.Oracle)),
}, {
tag: shortUIntConst(Tag.StateTrees),
- version: shortUIntConst(1, true),
- contracts: entryAny,
- calls: entryAny,
- channels: entryAny,
- ns: entryAny,
- oracles: entryAny,
- accounts: entryAny,
+ version: shortUIntConst(0, true),
+ contracts: wrapped(Tag.ContractsMtree) as unknown as MapContracts,
+ calls: wrapped(Tag.CallsMtree) as unknown as MapCalls,
+ channels: wrapped(Tag.ChannelsMtree) as unknown as MapChannels,
+ ns: wrapped(Tag.NameserviceMtree) as unknown as MapNames,
+ oracles: wrapped(Tag.OraclesMtree) as unknown as MapOracles,
+ accounts: wrapped(Tag.AccountsMtree) as unknown as MapAccounts,
}, {
tag: shortUIntConst(Tag.Mtree),
version: shortUIntConst(1, true),
- values: array(entry()) as unknown as EntryAnyArray,
+ values: entryMtreeValueArray,
}, {
tag: shortUIntConst(Tag.MtreeValue),
version: shortUIntConst(1, true),
@@ -445,27 +514,27 @@ export const txSchema = [{
}, {
tag: shortUIntConst(Tag.ContractsMtree),
version: shortUIntConst(1, true),
- contracts: entryAny,
+ payload: mapContracts,
}, {
tag: shortUIntConst(Tag.CallsMtree),
version: shortUIntConst(1, true),
- calls: entryAny,
+ payload: mapCalls,
}, {
tag: shortUIntConst(Tag.ChannelsMtree),
version: shortUIntConst(1, true),
- channels: entryAny,
+ payload: mapChannels,
}, {
tag: shortUIntConst(Tag.NameserviceMtree),
version: shortUIntConst(1, true),
- mtree: entryAny,
+ payload: mapNames,
}, {
tag: shortUIntConst(Tag.OraclesMtree),
version: shortUIntConst(1, true),
- otree: entryAny,
+ payload: mapOracles,
}, {
tag: shortUIntConst(Tag.AccountsMtree),
version: shortUIntConst(1, true),
- accounts: entryAny,
+ payload: mapAccounts,
}, {
tag: shortUIntConst(Tag.GaAttachTx),
version: shortUIntConst(1, true),
diff --git a/test/unit/tx.ts b/test/unit/tx.ts
index f73734ac3a..2048edd7e1 100644
--- a/test/unit/tx.ts
+++ b/test/unit/tx.ts
@@ -154,26 +154,26 @@ describe('Tx', () => {
const address = 'ak_i9svRuk9SJfAponRnCYVnVWN9HVLdBEd8ZdGREJMaUiTn4S4D';
const account = {
- tag: 10, version: 1, nonce: 0, balance: '99999999999999998997',
+ tag: Tag.Account, version: 1, nonce: 0, balance: '99999999999999998997',
};
expect(unpackedPoi.accounts[0].get(address)).to.eql(account);
const addressContract = 'ct_ECdrEy2NJKq3qK3xraPtcDP7vfdi56SQXYAH3bVVSTmpqpYyW';
const accountContract = {
- tag: 10, version: 1, nonce: 0, balance: '1000',
+ tag: Tag.Account, version: 1, nonce: 0, balance: '1000',
};
expect(unpackedPoi.accounts[0].get(addressContract as Encoded.AccountAddress))
.to.eql(accountContract);
expect(unpackedPoi.accounts[0].toObject()).to.eql({
ak_BvMjyAXbpHkjzVfG53N6FxF1LwTX2EYwFLfNbk8mcXjp8CXBC: {
- tag: 10, version: 1, nonce: 0, balance: '100000000000000000003',
+ tag: Tag.Account, version: 1, nonce: 0, balance: '100000000000000000003',
},
[addressContract.replace('ct_', 'ak_')]: accountContract,
[address]: account,
});
const contract = {
- tag: 40,
+ tag: Tag.Contract,
version: 1,
owner: 'ak_i9svRuk9SJfAponRnCYVnVWN9HVLdBEd8ZdGREJMaUiTn4S4D',
ctVersion: { vmVersion: VmVersion.Fate, abiVersion: AbiVersion.Fate },
@@ -188,6 +188,119 @@ describe('Tx', () => {
expect(buildTx(unpackedPoi, { prefix: Encoding.Poi })).to.equal(poi);
});
+
+ it('unpacks state channel calls record', () => {
+ const tx = 'cs_+QFBggJuAbkBOvkBNz8B+QEyuJf4lUABuEBRt/rxUTPwSp8BBMQWR70Ag6kTiNXTDmO2LWStsbEXhED9reWbZWfYmFIwTrKG6Khrbb7SvfC4T4ll2BtXsX/luE/4TSkCoQFZYYdOS6IFcvCPFPCBUOkebcCW0ZehLaMRA+K9RcniKwICoQVRt/rxUTPwSp8BBMQWR70Ag6kTiNXTDmO2LWStsbEXhAA9PwDAuJf4lUABuEBRt/rxUTPwSp8BBMQWR70Ag6kTiNXTDmO2LWStsbEXhADlKPCJlyMdCDQrNsajcRCzQk6M8LSJvbdnJ7Lc4aFjuE/4TSkCoQFZYYdOS6IFcvCPFPCBUOkebcCW0ZehLaMRA+K9RcniKwMDoQVRt/rxUTPwSp8BBMQWR70Ag6kTiNXTDmO2LWStsbEXhAEOVADAenqUfg==';
+ const params = {
+ tag: Tag.CallsMtree,
+ version: 1,
+ payload: {
+ 'ba_Ubf68VEz8EqfAQTEFke9AIOpE4jV0w5jti1krbGxF4RA/a3lm2Vn2JhSME6yhuioa22+0r3wuE+JZdgbV7F/5c9Ms1g=': {
+ callerId: 'ak_gN7nP72rm7D1kuSYWRtL9Sf4pFRoTPKM8wa9JHyneazW8zHm4',
+ callerNonce: 2,
+ contractId: 'ct_czPqotjcUujiXu5DaTeJMbv2WJpqwuhsQFn6edrGVRaoHLifk',
+ gasPrice: '0',
+ gasUsed: 61,
+ height: 2,
+ log: [],
+ returnType: 0,
+ returnValue: 'cb_P4fvHVw=',
+ tag: Tag.ContractCall,
+ version: 2,
+ },
+ 'ba_Ubf68VEz8EqfAQTEFke9AIOpE4jV0w5jti1krbGxF4QA5SjwiZcjHQg0KzbGo3EQs0JOjPC0ib23Zyey3OGhY+BjbKc=': {
+ callerId: 'ak_gN7nP72rm7D1kuSYWRtL9Sf4pFRoTPKM8wa9JHyneazW8zHm4',
+ callerNonce: 3,
+ contractId: 'ct_czPqotjcUujiXu5DaTeJMbv2WJpqwuhsQFn6edrGVRaoHLifk',
+ gasPrice: '1',
+ gasUsed: 14,
+ height: 3,
+ log: [],
+ returnType: 0,
+ returnValue: 'cb_VNLOFXc=',
+ tag: Tag.ContractCall,
+ version: 2,
+ },
+ },
+ } as const;
+ expect(unpackTx(tx, Tag.CallsMtree)).to.be.eql(params);
+ expect(buildTx(params, { prefix: Encoding.CallStateTree })).to.be.equal(tx);
+ });
+
+ it('unpacks state channel signed tx', () => {
+ const { signatures, encodedTx } = unpackTx(
+ 'tx_+NILAfiEuEBCv6dwkalvFkuHyYNcRpgZVYlSMmyOO9ukCrBBYYy2zLdgaSs/ug3e01ep2jiy6z9ABOkC83QNpCjdi0eAahUBuEC1RFFr7z4401oJRENrqGRlRsOwTp/GU70W5zeiTP0TZ8rtfzhGH1ZjIsq7u+o6duevI+eyrBtXr3yeqbViEB4KuEj4RjkCoQYzv70uksCUiH6SlOGVAYhx0LkLFmtDUXsRejThITz2MwOgGK/uHihyT8uUtXTAcncw9QFkW0QghCzEWDfwXWbHR14jXFqu',
+ Tag.SignedTx,
+ );
+ expect(signatures).to.have.lengthOf(2);
+ if (encodedTx.tag !== Tag.ChannelOffChainTx) throw new Error('Unexpected nested transaction');
+ expect(encodedTx.channelId).to.be.satisfy((s: string) => s.startsWith('ch_'));
+ expect(encodedTx.round).to.be.equal(3);
+ expect(encodedTx.stateHash).to.be.satisfy((s: string) => s.startsWith('st_'));
+ });
+
+ it('unpacks state trees tx', () => {
+ const tx = 'ss_+QKqPgC5ATb5ATOCAm0BuQEs+QEpPwH5ASSo50ABo/v6skWp8mq1jwV/+iKDkHayfTtp7ytW6d/nZ2QVQ4zhEAABP6rpQAGj+/qyRanyarWPBX/6IoOQdrJ9O2nvK1bp3+dnZBVDjOEQAACCLwCm5UABofv6skWp8mq1jwV/+iKDkHayfTtp7ytW6d/nZ2QVQ4zhEAC4p/ilQAGg+/qyRanyarWPBX/6IoOQdrJ9O2nvK1bp3+dnZBVDjOG4gPh+KAGhAaJtvnDfkCeML/RLVY1N/6eQNHADrvu4hZoCmMAbCi5SgwUAA7hO+ExGA6Dh3797nquCHCSm088avgOiqgjjarRQviEYAXq+YlegWcCgjf6AeCCSADcBBwcBAQCOLwERgHggkhlnZXRBcmeCLwCFNy4wLjEAgAHAggPouKf4pYICbgG4n/idPwH4mbiX+JVAAbhA+/qyRanyarWPBX/6IoOQdrJ9O2nvK1bp3+dnZBVDjOEHycljzso7F0NwAzM/Oj84MV1Lo7ia3VslsuGHHCI+wrhP+E0pAqEBom2+cN+QJ4wv9EtVjU3/p5A0cAOu+7iFmgKYwBsKLlICAqEF+/qyRanyarWPBX/6IoOQdrJ9O2nvK1bp3+dnZBVDjOEAPT8AwIrJggJvAYTDPwHAismCAnABhMM/AcCKyYICcQGEwz8BwLij+KGCAnIBuJv4mT8B+JWs60ABoPv6skWp8mq1jwV/+iKDkHayfTtp7ytW6d/nZ2QVQ4zhh8YKAQCCA+iz8kABoKJtvnDfkCeML/RLVY1N/6eQNHADrvu4hZoCmMAbCi5Sjs0KAQCJBWvHXi1jD/wVs/JAAaBuFXSR/8BDssKtH01lCLrV/Jd1ImY9KNci1mQqB0RIJY7NCgEAiQVrx14tYxAAA0X2l9c=';
+ const params = {
+ accounts: {
+ ak_2uyUQn1dyzrMxjzhSQgZ2rV1dk2D5BCYpquzzBn6hxoSAo7y1d: {
+ balance: '1000',
+ nonce: 0,
+ tag: Tag.Account,
+ version: 1,
+ },
+ ak_2EY2KjfhXkpLq2u13YuvDBahi8Yxq5ErNocCeCUAvwHmJjS2aF: {
+ balance: '99999999999999998997',
+ nonce: 0,
+ tag: Tag.Account,
+ version: 1,
+ },
+ ak_qUwhrGsBqhxh2Ace9KBsrDtJpmFeWhuhLZg61L4cQ4Lknhvud: {
+ balance: '100000000000000000003',
+ nonce: 0,
+ tag: Tag.Account,
+ version: 1,
+ },
+ },
+ calls: {
+ 'ba_+/qyRanyarWPBX/6IoOQdrJ9O2nvK1bp3+dnZBVDjOEHycljzso7F0NwAzM/Oj84MV1Lo7ia3VslsuGHHCI+wsMqg1w=': {
+ callerId: 'ak_2EY2KjfhXkpLq2u13YuvDBahi8Yxq5ErNocCeCUAvwHmJjS2aF',
+ callerNonce: 2,
+ contractId: 'ct_2uyUQn1dyzrMxjzhSQgZ2rV1dk2D5BCYpquzzBn6hxoSAo7y1d',
+ gasPrice: '0',
+ gasUsed: 61,
+ height: 2,
+ log: [],
+ returnType: 0,
+ returnValue: 'cb_P4fvHVw=',
+ tag: Tag.ContractCall,
+ version: 2,
+ },
+ },
+ channels: {},
+ contracts: {
+ ct_2uyUQn1dyzrMxjzhSQgZ2rV1dk2D5BCYpquzzBn6hxoSAo7y1d: {
+ active: true,
+ code: 'cb_+ExGA6Dh3797nquCHCSm088avgOiqgjjarRQviEYAXq+YlegWcCgjf6AeCCSADcBBwcBAQCOLwERgHggkhlnZXRBcmeCLwCFNy4wLjEALb9eTg==',
+ ctVersion: {
+ abiVersion: 3,
+ vmVersion: 5,
+ },
+ deposit: '1000',
+ log: 'cb_Xfbg4g==',
+ owner: 'ak_2EY2KjfhXkpLq2u13YuvDBahi8Yxq5ErNocCeCUAvwHmJjS2aF',
+ referers: [],
+ tag: Tag.Contract,
+ version: 1,
+ },
+ },
+ ns: {},
+ oracles: {},
+ tag: Tag.StateTrees,
+ version: 0,
+ } as const;
+ expect(unpackTx(tx, Tag.StateTrees)).to.be.eql(params);
+ });
});
const address = 'ak_i9svRuk9SJfAponRnCYVnVWN9HVLdBEd8ZdGREJMaUiTn4S4D';