diff --git a/src/@types/common.ts b/src/@types/common.ts index b772d500f..ad7b92d94 100644 --- a/src/@types/common.ts +++ b/src/@types/common.ts @@ -1,6 +1,7 @@ export enum CasperNetworkName { Mainnet = 'casper', - Testnet = 'casper-test' + Testnet = 'casper-test', + Integration = 'integration-test' } export enum AuctionManagerEntryPoint { diff --git a/src/rpc/rpc_client.test.ts b/src/rpc/rpc_client.test.ts new file mode 100644 index 000000000..4aa5361b9 --- /dev/null +++ b/src/rpc/rpc_client.test.ts @@ -0,0 +1,463 @@ +import { TypedJSON } from 'typedjson'; +import { expect } from 'chai'; + +import { InfoGetTransactionResultV1Compatible } from './response'; + +describe('RPC Client', () => { + it('should be able to parse getTransactionByTransactionHash response', () => { + const json = { + jsonrpc: '2.0', + id: '1', + result: { + deploy: { + hash: + '84ad4a6aa15ac60810c854f8463fa83f1fecd1f4ec51088cd22baf7da47bbdf5', + header: { + ttl: '30m', + account: + '02033300ef2194d8cc8a2074130d0c58f2b10faae9cec3adc25d2a3e96c806ed1f54', + body_hash: + '86f834702123baeddce7d3d03952ad549ceee8cc4a951a85d692eca1880bfcbd', + gas_price: 1, + timestamp: '2024-06-05T14:01:32.621Z', + chain_name: 'casper', + dependencies: [] + }, + payment: { + ModuleBytes: { + args: [ + [ + 'amount', + { + bytes: '06001f5b448d0e', + parsed: '15999900000000', + cl_type: 'U512' + } + ] + ], + module_bytes: '' + } + }, + session: { + Transfer: { + args: [ + [ + 'amount', + { + bytes: '06001f5b448d0e', + parsed: '15999900000000', + cl_type: 'U512' + } + ], + [ + 'target', + { + bytes: + 'fbab6b8ac6befe3d2f2f4c0cc6497796a2a661d77dbf19e2cfe789e3c08b86d9', + parsed: + 'fbab6b8ac6befe3d2f2f4c0cc6497796a2a661d77dbf19e2cfe789e3c08b86d9', + cl_type: { + ByteArray: 32 + } + } + ], + [ + 'id', + { + bytes: '00', + parsed: null, + cl_type: { + Option: 'U64' + } + } + ] + ] + } + }, + approvals: [ + { + signer: + '02033300ef2194d8cc8a2074130d0c58f2b10faae9cec3adc25d2a3e96c806ed1f54', + signature: + '02da42dda61957ddb8633ec8bc72839d00e579e40b513ece0afd15fd4ee7cb436572224b50770b23ec2b60c9f9cec132e0ec5bc9297cdc91ef53c6d89e48a584fd' + } + ] + }, + api_version: '1.5.6', + execution_results: [ + { + result: { + Success: { + cost: '100000000', + effect: { + operations: [], + transforms: [ + { + key: + 'account-hash-6174cf2e6f8fed1715c9a3bace9c50bfe572eecb763b0ed3f644532616452008', + transform: 'Identity' + }, + { + key: + 'hash-d2469afeb99130f0be7c9ce230a84149e6d756e306ef8cf5b8a49d5182e41676', + transform: 'Identity' + }, + { + key: + 'account-hash-fbab6b8ac6befe3d2f2f4c0cc6497796a2a661d77dbf19e2cfe789e3c08b86d9', + transform: 'Identity' + }, + { + key: + 'account-hash-fbab6b8ac6befe3d2f2f4c0cc6497796a2a661d77dbf19e2cfe789e3c08b86d9', + transform: 'Identity' + }, + { + key: + 'hash-d2469afeb99130f0be7c9ce230a84149e6d756e306ef8cf5b8a49d5182e41676', + transform: 'Identity' + }, + { + key: + 'hash-d2469afeb99130f0be7c9ce230a84149e6d756e306ef8cf5b8a49d5182e41676', + transform: 'Identity' + }, + { + key: + 'hash-d63c44078a1931b5dc4b80a7a0ec586164fd0470ce9f8b23f6d93b9e86c5944d', + transform: 'Identity' + }, + { + key: + 'hash-d2469afeb99130f0be7c9ce230a84149e6d756e306ef8cf5b8a49d5182e41676', + transform: 'Identity' + }, + { + key: + 'hash-7cc1b1db4e08bbfe7bacf8e1ad828a5d9bcccbb33e55d322808c3a88da53213a', + transform: 'Identity' + }, + { + key: + 'hash-7cc1b1db4e08bbfe7bacf8e1ad828a5d9bcccbb33e55d322808c3a88da53213a', + transform: 'Identity' + }, + { + key: + 'hash-4475016098705466254edd18d267a9dad43e341d4dafadb507d0fe3cf2d4a74b', + transform: 'Identity' + }, + { + key: + 'hash-7cc1b1db4e08bbfe7bacf8e1ad828a5d9bcccbb33e55d322808c3a88da53213a', + transform: 'Identity' + }, + { + key: + 'balance-2feb39e0671116d70f2df80aeeb78fac604194ab2d160566ca75e319a09edd6a', + transform: 'Identity' + }, + { + key: + 'balance-fe327f9815a1d016e1143db85e25a86341883949fd75ac1c1e7408a26c5b62ef', + transform: 'Identity' + }, + { + key: + 'balance-2feb39e0671116d70f2df80aeeb78fac604194ab2d160566ca75e319a09edd6a', + transform: { + WriteCLValue: { + bytes: '06001f5b448d0e', + parsed: '15999900000000', + cl_type: 'U512' + } + } + }, + { + key: + 'balance-fe327f9815a1d016e1143db85e25a86341883949fd75ac1c1e7408a26c5b62ef', + transform: { + AddUInt512: '100000000' + } + }, + { + key: + 'account-hash-6174cf2e6f8fed1715c9a3bace9c50bfe572eecb763b0ed3f644532616452008', + transform: 'Identity' + }, + { + key: + 'hash-d2469afeb99130f0be7c9ce230a84149e6d756e306ef8cf5b8a49d5182e41676', + transform: 'Identity' + }, + { + key: + 'account-hash-fbab6b8ac6befe3d2f2f4c0cc6497796a2a661d77dbf19e2cfe789e3c08b86d9', + transform: 'Identity' + }, + { + key: + 'account-hash-fbab6b8ac6befe3d2f2f4c0cc6497796a2a661d77dbf19e2cfe789e3c08b86d9', + transform: 'Identity' + }, + { + key: + 'hash-d2469afeb99130f0be7c9ce230a84149e6d756e306ef8cf5b8a49d5182e41676', + transform: 'Identity' + }, + { + key: + 'hash-d2469afeb99130f0be7c9ce230a84149e6d756e306ef8cf5b8a49d5182e41676', + transform: 'Identity' + }, + { + key: + 'hash-d63c44078a1931b5dc4b80a7a0ec586164fd0470ce9f8b23f6d93b9e86c5944d', + transform: 'Identity' + }, + { + key: + 'hash-d2469afeb99130f0be7c9ce230a84149e6d756e306ef8cf5b8a49d5182e41676', + transform: 'Identity' + }, + { + key: + 'hash-7cc1b1db4e08bbfe7bacf8e1ad828a5d9bcccbb33e55d322808c3a88da53213a', + transform: 'Identity' + }, + { + key: + 'hash-7cc1b1db4e08bbfe7bacf8e1ad828a5d9bcccbb33e55d322808c3a88da53213a', + transform: 'Identity' + }, + { + key: + 'hash-4475016098705466254edd18d267a9dad43e341d4dafadb507d0fe3cf2d4a74b', + transform: 'Identity' + }, + { + key: + 'hash-7cc1b1db4e08bbfe7bacf8e1ad828a5d9bcccbb33e55d322808c3a88da53213a', + transform: 'Identity' + }, + { + key: + 'balance-2feb39e0671116d70f2df80aeeb78fac604194ab2d160566ca75e319a09edd6a', + transform: 'Identity' + }, + { + key: + 'balance-fe327f9815a1d016e1143db85e25a86341883949fd75ac1c1e7408a26c5b62ef', + transform: 'Identity' + }, + { + key: + 'balance-2feb39e0671116d70f2df80aeeb78fac604194ab2d160566ca75e319a09edd6a', + transform: { + WriteCLValue: { + bytes: '06001f5b448d0e', + parsed: '15999900000000', + cl_type: 'U512' + } + } + }, + { + key: + 'balance-fe327f9815a1d016e1143db85e25a86341883949fd75ac1c1e7408a26c5b62ef', + transform: { + AddUInt512: '100000000' + } + }, + { + key: + 'hash-7cc1b1db4e08bbfe7bacf8e1ad828a5d9bcccbb33e55d322808c3a88da53213a', + transform: 'Identity' + }, + { + key: + 'hash-7cc1b1db4e08bbfe7bacf8e1ad828a5d9bcccbb33e55d322808c3a88da53213a', + transform: 'Identity' + }, + { + key: + 'hash-4475016098705466254edd18d267a9dad43e341d4dafadb507d0fe3cf2d4a74b', + transform: 'Identity' + }, + { + key: + 'hash-7cc1b1db4e08bbfe7bacf8e1ad828a5d9bcccbb33e55d322808c3a88da53213a', + transform: 'Identity' + }, + { + key: + 'balance-2feb39e0671116d70f2df80aeeb78fac604194ab2d160566ca75e319a09edd6a', + transform: 'Identity' + }, + { + key: + 'balance-5d533f1316b9ac1173e47e946f1f523a66abee451d05b13690856228706d3f03', + transform: 'Identity' + }, + { + key: + 'balance-2feb39e0671116d70f2df80aeeb78fac604194ab2d160566ca75e319a09edd6a', + transform: { + WriteCLValue: { + bytes: '00', + parsed: '0', + cl_type: 'U512' + } + } + }, + { + key: + 'balance-5d533f1316b9ac1173e47e946f1f523a66abee451d05b13690856228706d3f03', + transform: { + AddUInt512: '15999900000000' + } + }, + { + key: + 'transfer-23df36827bab18568e8077bf1151ed29497456e6bb0896371e9c1a244bcb30c9', + transform: { + WriteTransfer: { + id: null, + to: + 'account-hash-fbab6b8ac6befe3d2f2f4c0cc6497796a2a661d77dbf19e2cfe789e3c08b86d9', + gas: '0', + from: + 'account-hash-a106cf121145d7cc62835df18dea2991395c87a4c67c83f28b4d63847a71653e', + amount: '15999900000000', + source: + 'uref-2feb39e0671116d70f2df80aeeb78fac604194ab2d160566ca75e319a09edd6a-007', + target: + 'uref-5d533f1316b9ac1173e47e946f1f523a66abee451d05b13690856228706d3f03-004', + deploy_hash: + '84ad4a6aa15ac60810c854f8463fa83f1fecd1f4ec51088cd22baf7da47bbdf5' + } + } + }, + { + key: + 'deploy-84ad4a6aa15ac60810c854f8463fa83f1fecd1f4ec51088cd22baf7da47bbdf5', + transform: { + WriteDeployInfo: { + gas: '100000000', + from: + 'account-hash-a106cf121145d7cc62835df18dea2991395c87a4c67c83f28b4d63847a71653e', + source: + 'uref-2feb39e0671116d70f2df80aeeb78fac604194ab2d160566ca75e319a09edd6a-007', + transfers: [ + 'transfer-23df36827bab18568e8077bf1151ed29497456e6bb0896371e9c1a244bcb30c9' + ], + deploy_hash: + '84ad4a6aa15ac60810c854f8463fa83f1fecd1f4ec51088cd22baf7da47bbdf5' + } + } + }, + { + key: + 'hash-d2469afeb99130f0be7c9ce230a84149e6d756e306ef8cf5b8a49d5182e41676', + transform: 'Identity' + }, + { + key: + 'hash-d2469afeb99130f0be7c9ce230a84149e6d756e306ef8cf5b8a49d5182e41676', + transform: 'Identity' + }, + { + key: + 'hash-d63c44078a1931b5dc4b80a7a0ec586164fd0470ce9f8b23f6d93b9e86c5944d', + transform: 'Identity' + }, + { + key: + 'hash-d2469afeb99130f0be7c9ce230a84149e6d756e306ef8cf5b8a49d5182e41676', + transform: 'Identity' + }, + { + key: + 'balance-fe327f9815a1d016e1143db85e25a86341883949fd75ac1c1e7408a26c5b62ef', + transform: 'Identity' + }, + { + key: + 'hash-d2469afeb99130f0be7c9ce230a84149e6d756e306ef8cf5b8a49d5182e41676', + transform: 'Identity' + }, + { + key: + 'hash-7cc1b1db4e08bbfe7bacf8e1ad828a5d9bcccbb33e55d322808c3a88da53213a', + transform: 'Identity' + }, + { + key: + 'hash-4475016098705466254edd18d267a9dad43e341d4dafadb507d0fe3cf2d4a74b', + transform: 'Identity' + }, + { + key: + 'hash-7cc1b1db4e08bbfe7bacf8e1ad828a5d9bcccbb33e55d322808c3a88da53213a', + transform: 'Identity' + }, + { + key: + 'balance-fe327f9815a1d016e1143db85e25a86341883949fd75ac1c1e7408a26c5b62ef', + transform: 'Identity' + }, + { + key: + 'balance-7e38074b9fe8435ddd12ad892a3a06ecedc0cd71194fa35d061726e21743865b', + transform: 'Identity' + }, + { + key: + 'balance-fe327f9815a1d016e1143db85e25a86341883949fd75ac1c1e7408a26c5b62ef', + transform: { + WriteCLValue: { + bytes: '00', + parsed: '0', + cl_type: 'U512' + } + } + }, + { + key: + 'balance-7e38074b9fe8435ddd12ad892a3a06ecedc0cd71194fa35d061726e21743865b', + transform: { + AddUInt512: '100000000' + } + } + ] + }, + transfers: [ + 'transfer-23df36827bab18568e8077bf1151ed29497456e6bb0896371e9c1a244bcb30c9' + ] + } + }, + block_hash: + '15e48342b9ae88d6c6fed97144a3df1fabc1b9ffa90af18674b6c3f085ef5ebc' + } + ] + } + }; + + const serializer = new TypedJSON(InfoGetTransactionResultV1Compatible); + const result = serializer.parse(json.result)!; + result.rawJSON = json.result; + + const txResult = InfoGetTransactionResultV1Compatible.newInfoGetTransactionResultFromV1Compatible( + result, + result.rawJSON + ); + + expect(txResult).to.be.not.undefined; + expect(txResult).to.be.not.empty; + expect( + txResult.executionInfo?.executionResult.initiator.publicKey?.toHex() + ).to.deep.equal(json.result.deploy.header.account); + expect( + txResult.executionInfo?.executionResult.transfers[0].transactionHash.toString() + ).to.deep.equal(txResult.transaction.hash.toHex()); + }); +}); diff --git a/src/types/Contract.ts b/src/types/Contract.ts index afe1c5cc6..0ed3890b3 100644 --- a/src/types/Contract.ts +++ b/src/types/Contract.ts @@ -1,7 +1,7 @@ import { jsonArrayMember, jsonMember, jsonObject } from 'typedjson'; import { ContractHash, ContractPackageHash } from './key'; -import { EntryPointV1 } from './EntryPoint'; import { NamedKeys } from './NamedKey'; +import { NamedEntryPoint } from './AddressableEntity'; /** * Represents a smart contract on the blockchain, including its unique identifiers, entry points, named keys, and protocol version. @@ -33,8 +33,8 @@ export class Contract { /** * The list of entry points (functions) that can be called on this contract. */ - @jsonArrayMember(EntryPointV1, { name: 'entry_points' }) - entryPoints: EntryPointV1[]; + @jsonArrayMember(NamedEntryPoint, { name: 'entry_points' }) + entryPoints: NamedEntryPoint[]; /** * The named keys associated with the contract, providing access to specific values or data stored by the contract. @@ -59,7 +59,7 @@ export class Contract { constructor( contractPackageHash: ContractPackageHash, contractWasmHash: ContractHash, - entryPoints: EntryPointV1[], + entryPoints: NamedEntryPoint[], namedKeys: NamedKeys, protocolVersion: string ) { diff --git a/src/types/ContractPackage.test.ts b/src/types/ContractPackage.test.ts new file mode 100644 index 000000000..62c4c3239 --- /dev/null +++ b/src/types/ContractPackage.test.ts @@ -0,0 +1,158 @@ +import { TypedJSON } from 'typedjson'; +import { expect } from 'chai'; + +import { ContractPackage } from './ContractPackage'; + +describe('ContractPackage', () => { + const createSerializerAndParse = (json: any) => { + const serializer = new TypedJSON(ContractPackage); + return serializer.parse(json); + }; + + const commonAssertions = ( + contractPackage: ContractPackage | undefined, + json: any + ) => { + expect(contractPackage?.accessKey.toPrefixedString()).to.deep.equal( + json.access_key + ); + expect(contractPackage?.lockStatus).to.deep.equal(json.lock_status); + expect(contractPackage?.versions).to.not.be.empty; + expect(contractPackage?.groups).to.not.be.empty; + + json.versions.forEach((version: any, index: number) => { + expect( + contractPackage?.versions[index].contractHash.toPrefixedString() + ).to.deep.equal(version.contract_hash); + expect(contractPackage?.versions[index].contractVersion).to.deep.equal( + version.contract_version + ); + expect( + contractPackage?.versions[index].protocolVersionMajor + ).to.deep.equal(version.protocol_version_major); + }); + }; + + it('should parse ContractPackage V1', () => { + const jsonV1 = { + access_key: + 'uref-dc06bab1599b6163eab6786ca9a13e2ef28f157bd69a3bc3d8a4018a70450f8b-007', + versions: [ + { + protocol_version_major: 1, + contract_version: 1, + contract_hash: + 'contract-55cc25981545886d019401a40768adf71084ff4c251734b54280c3f1d600c9d1' + }, + { + protocol_version_major: 1, + contract_version: 2, + contract_hash: + 'contract-171f1bac4d4b12e66bdd1dfe2575c463b2e2ad8706cfa574b87ff5566b4c644c' + }, + { + protocol_version_major: 1, + contract_version: 3, + contract_hash: + 'contract-52809f5150e80b49096f25964082de4bcc3bdbb243d38414bbb22091a4ebdf96' + } + ], + disabled_versions: [ + { + protocol_version_major: 1, + contract_version: 1 + }, + { + protocol_version_major: 1, + contract_version: 2 + } + ], + groups: [ + { + group: 'constructor', + keys: [ + 'uref-1ff80105947906fa593f18198825aab2033047253edf839b16f36ab949158d2b-007' + ] + } + ], + lock_status: 'Unlocked' + }; + + const contractPackage = createSerializerAndParse(jsonV1); + commonAssertions(contractPackage, jsonV1); + + expect(contractPackage?.disabledVersions[0][0]).to.deep.equal( + jsonV1.disabled_versions[0].protocol_version_major + ); + expect(contractPackage?.disabledVersions[0][1]).to.deep.equal( + jsonV1.disabled_versions[0].contract_version + ); + + jsonV1.groups.forEach((group, index: number) => { + expect(contractPackage?.groups[index].groupName).to.deep.equal( + group.group + ); + expect( + contractPackage?.groups[index].groupUsers[0].toPrefixedString() + ).to.deep.equal(group.keys?.[0]); + }); + }); + + it('should parse ContractPackage V2', () => { + const jsonV2 = { + access_key: + 'uref-dc06bab1599b6163eab6786ca9a13e2ef28f157bd69a3bc3d8a4018a70450f8b-007', + versions: [ + { + protocol_version_major: 1, + contract_version: 1, + contract_hash: + 'contract-55cc25981545886d019401a40768adf71084ff4c251734b54280c3f1d600c9d1' + }, + { + protocol_version_major: 1, + contract_version: 2, + contract_hash: + 'contract-171f1bac4d4b12e66bdd1dfe2575c463b2e2ad8706cfa574b87ff5566b4c644c' + }, + { + protocol_version_major: 1, + contract_version: 3, + contract_hash: + 'contract-52809f5150e80b49096f25964082de4bcc3bdbb243d38414bbb22091a4ebdf96' + } + ], + disabled_versions: [ + [1, 1], + [1, 2] + ], + groups: [ + { + group_name: 'constructor', + group_users: [ + 'uref-1ff80105947906fa593f18198825aab2033047253edf839b16f36ab949158d2b-007' + ] + } + ], + lock_status: 'Unlocked' + }; + + const contractPackage = createSerializerAndParse(jsonV2); + commonAssertions(contractPackage, jsonV2); + + expect(contractPackage?.disabledVersions[0][0]).to.deep.equal( + jsonV2.disabled_versions[0][0] + ); + expect(contractPackage?.disabledVersions[0][1]).to.deep.equal( + jsonV2.disabled_versions[0][1] + ); + jsonV2.groups.forEach((group, index: number) => { + expect(contractPackage?.groups[index].groupName).to.deep.equal( + group.group_name + ); + expect( + contractPackage?.groups[index].groupUsers[0].toPrefixedString() + ).to.deep.equal(group.group_users?.[0]); + }); + }); +}); diff --git a/src/types/ContractPackage.ts b/src/types/ContractPackage.ts index d8a6698da..7f8f02257 100644 --- a/src/types/ContractPackage.ts +++ b/src/types/ContractPackage.ts @@ -1,32 +1,10 @@ -import { jsonArrayMember, jsonMember, jsonObject } from 'typedjson'; +import { jsonArrayMember, jsonMember, jsonObject, TypedJSON } from 'typedjson'; import { ContractHash, URef } from './key'; +import { deserializeDisabledVersions } from './SerializationUtils'; -/** - * Represents a disabled contract version, marking specific versions as incompatible with the current protocol. - */ -@jsonObject -class DisabledContractVersion { - /** - * The version number of the contract. - */ - @jsonMember({ name: 'contract_version', constructor: Number }) - contractVersion: number; - - /** - * Major version of the protocol that disables this contract version. - */ - @jsonMember({ name: 'protocol_version_major', constructor: Number }) - protocolVersionMajor: number; - - /** - * Constructs a new `DisabledContractVersion` instance. - * @param contractVersion - The version of the contract. - * @param protocolVersionMajor - The major protocol version disabling this contract version. - */ - constructor(contractVersion: number, protocolVersionMajor: number) { - this.contractVersion = contractVersion; - this.protocolVersionMajor = protocolVersionMajor; - } +export interface IDisabledVersion { + protocol_version_major: number; + contract_version: number; } /** @@ -37,27 +15,46 @@ export class ContractGroup { /** * The name of the group. */ - @jsonMember({ name: 'group', constructor: String }) - group: string; + @jsonMember({ name: 'group_name', constructor: String, preserveNull: true }) + groupName: string; /** * The list of URef keys associated with this group, defining permissions for contract interaction. */ @jsonArrayMember(URef, { - name: 'keys', + name: 'group_users', serializer: (value: URef[]) => value.map(it => it.toJSON()), - deserializer: (json: any) => json.map((it: string) => URef.fromJSON(it)) + deserializer: (json: any) => { + if (!json) return; + return json.map((it: string) => URef.fromJSON(it)); + } }) - keys: URef[]; + groupUsers: URef[]; /** - * Constructs a new `ContractGroup` instance. - * @param group - The name of the group. - * @param keys - An array of URef keys associated with the group. + * Converts a plain JSON object into an instance of `ContractGroup`. + * + * @param json The JSON object to parse. + * @returns An instance of `ContractGroup` or `undefined` if parsing fails. */ - constructor(group: string, keys: URef[]) { - this.group = group; - this.keys = keys; + public static fromJSON(json: any): ContractGroup | undefined { + const serializer = new TypedJSON(ContractGroup); + const contractGroup = serializer.parse(json); + + // V1 Compatible + if (contractGroup) { + if (Array.isArray(json?.keys)) { + contractGroup.groupUsers = json.keys.map((it: any) => + URef.fromJSON(it) + ); + } + + if (typeof json?.group === 'string') { + contractGroup.groupName = json.group; + } + } + + return contractGroup; } } @@ -125,13 +122,26 @@ export class ContractPackage { /** * Array of disabled contract versions, marking incompatible versions. */ - @jsonArrayMember(DisabledContractVersion, { name: 'disabled_versions' }) - disabledVersions: DisabledContractVersion[]; + @jsonArrayMember(Number, { + name: 'disabled_versions', + dimensions: 2, + deserializer: json => { + if (!json) return; + return deserializeDisabledVersions(json); + } + }) + disabledVersions: number[][]; /** * Array of contract groups, managing access control with sets of URef keys. */ - @jsonArrayMember(ContractGroup, { name: 'groups' }) + @jsonArrayMember(ContractGroup, { + name: 'groups', + deserializer: json => { + if (!json) return; + return json.map((it: ContractGroup) => ContractGroup.fromJSON(it)); + } + }) groups: ContractGroup[]; /** @@ -156,7 +166,7 @@ export class ContractPackage { */ constructor( accessKey: URef, - disabledVersions: DisabledContractVersion[], + disabledVersions: number[][], groups: ContractGroup[], versions: ContractVersion[], lockStatus: string diff --git a/src/types/Deploy.ts b/src/types/Deploy.ts index 599f44960..9cde94540 100644 --- a/src/types/Deploy.ts +++ b/src/types/Deploy.ts @@ -269,9 +269,7 @@ export class Deploy { * @param keys The private key used to sign the deploy. */ public sign(keys: PrivateKey): void { - const signatureBytes = keys.signAndAddAlgorithmBytes( - this.hash.toBytes() - ); + const signatureBytes = keys.signAndAddAlgorithmBytes(this.hash.toBytes()); const signature = new HexBytes(signatureBytes); this.approvals.push(new Approval(keys.publicKey, signature)); } @@ -412,7 +410,7 @@ export class Deploy { deploy.session.getArgs(), TransactionTarget.newTransactionTargetFromSession(deploy.session), transactionEntryPoint, - new TransactionScheduling({ standard: {} }), + new TransactionScheduling({}), // Standard deploy.approvals, undefined, deploy diff --git a/src/types/ExecutionResult.ts b/src/types/ExecutionResult.ts index f446e7f63..e0358c21c 100644 --- a/src/types/ExecutionResult.ts +++ b/src/types/ExecutionResult.ts @@ -410,8 +410,7 @@ export class ExecutionResult { const transfer = new Transfer(); transfer.amount = writeTransfer.amount; transfer.transactionHash = new TransactionHash( - undefined, - transform.key.transfer + writeTransfer?.deployHash ); transfer.from = new InitiatorAddr(undefined, writeTransfer.from); transfer.gas = writeTransfer.gas; diff --git a/src/types/Package.ts b/src/types/Package.ts index 1b504afdf..9b022d49c 100644 --- a/src/types/Package.ts +++ b/src/types/Package.ts @@ -118,7 +118,10 @@ export class NamedUserGroup { @jsonArrayMember(URef, { name: 'group_users', serializer: (value: URef[]) => value.map(it => it.toJSON()), - deserializer: (json: any) => json.map((it: string) => URef.fromJSON(it)) + deserializer: (json: any) => { + if (!json) return; + return json.map((it: string) => URef.fromJSON(it)); + } }) groupUsers: URef[]; diff --git a/src/types/SerializationUtils.ts b/src/types/SerializationUtils.ts index b4f64b2e4..0deae3eee 100644 --- a/src/types/SerializationUtils.ts +++ b/src/types/SerializationUtils.ts @@ -3,6 +3,7 @@ import humanizeDuration from 'humanize-duration'; import { Args } from './Args'; import { Conversions } from './Conversions'; import { CLValueUInt512 } from './clvalue'; +import { IDisabledVersion } from './ContractPackage'; /** * Serializes a `Uint8Array` into a hexadecimal string. @@ -208,3 +209,28 @@ export const serializeRewards = (map: Map) => { return [key, serializedValue]; }); }; + +/** + * Parses disabled versions into a standardized array of tuples. + * + * @param disabledVersions - The input array, which can be: + * - An array of tuples (`[number, number][]`), or + * - An array of objects with `protocol_version_major` and `contract_version` properties. + * @returns An array of tuples (`[number, number][]`) representing `[protocol_version_major, contract_version]`. + */ +export const deserializeDisabledVersions = ( + disabledVersions: [number, number][] | IDisabledVersion[] +): [number, number][] => { + // V2 Compatible + if (Array.isArray(disabledVersions) && Array.isArray(disabledVersions[0])) { + return disabledVersions as [number, number][]; + } + + // V1 Compatible + return (disabledVersions as IDisabledVersion[]).map( + ({ protocol_version_major, contract_version }) => [ + contract_version, + protocol_version_major + ] + ); +}; diff --git a/src/types/Transaction.ts b/src/types/Transaction.ts index dcbd84022..37356e802 100644 --- a/src/types/Transaction.ts +++ b/src/types/Transaction.ts @@ -662,4 +662,20 @@ export class TransactionHash { this.deploy = deploy; this.transactionV1 = transactionV1; } + + /** + * Converts the `TransactionHash` to a hexadecimal string representation. + * + * @returns {string} The hexadecimal string of the deploy or transactionV1, + * or an empty string if neither is available. + */ + public toString(): string { + if (this.deploy) { + return this.deploy.toHex(); + } else if (this.transactionV1) { + return this.transactionV1.toHex(); + } + + return ''; + } } diff --git a/src/types/Transform.test.ts b/src/types/Transform.test.ts index b963b72d0..69bf7c6a5 100644 --- a/src/types/Transform.test.ts +++ b/src/types/Transform.test.ts @@ -271,342 +271,417 @@ describe('TransformKind JSON Parsing and CLValue Transformation', () => { entry_points: [ { name: 'add_to_the_pool', - args: [], - ret: 'Unit', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'add_to_the_pool', + args: [], + ret: 'Unit', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'allowance', - args: [ - { - name: 'owner', - cl_type: 'Key' - }, - { - name: 'spender', - cl_type: 'Key' - } - ], - ret: 'U256', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'allowance', + args: [ + { + name: 'owner', + cl_type: 'Key' + }, + { + name: 'spender', + cl_type: 'Key' + } + ], + ret: 'U256', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'approve', - args: [ - { - name: 'spender', - cl_type: 'Key' - }, - { - name: 'amount', - cl_type: 'U256' - } - ], - ret: 'Unit', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'approve', + args: [ + { + name: 'spender', + cl_type: 'Key' + }, + { + name: 'amount', + cl_type: 'U256' + } + ], + ret: 'Unit', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'balance_of', - args: [ - { - name: 'account', - cl_type: 'Key' - } - ], - ret: 'U256', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'balance_of', + args: [ + { + name: 'account', + cl_type: 'Key' + } + ], + ret: 'U256', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'burn', - args: [ - { - name: 'owner', - cl_type: 'Key' - }, - { - name: 'amount', - cl_type: 'U256' - } - ], - ret: 'Unit', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'burn', + args: [ + { + name: 'owner', + cl_type: 'Key' + }, + { + name: 'amount', + cl_type: 'U256' + } + ], + ret: 'Unit', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'change_security', - args: [ - { - name: 'admin_list', - cl_type: { - List: 'Key' + entry_point: { + name: 'change_security', + args: [ + { + name: 'admin_list', + cl_type: { + List: 'Key' + } + }, + { + name: 'minter_list', + cl_type: { + List: 'Key' + } + }, + { + name: 'none_list', + cl_type: { + List: 'Key' + } } - }, - { - name: 'minter_list', - cl_type: { - List: 'Key' - } - }, - { - name: 'none_list', - cl_type: { - List: 'Key' - } - } - ], - ret: 'Unit', - access: 'Public', - entry_point_type: 'Called' + ], + ret: 'Unit', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'claim', - args: [ - { - name: 'receipt_id', - cl_type: 'U32' - } - ], - ret: 'Unit', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'claim', + args: [ + { + name: 'receipt_id', + cl_type: 'U32' + } + ], + ret: 'Unit', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'decimals', - args: [], - ret: 'U8', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'decimals', + args: [], + ret: 'U8', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'decrease_allowance', - args: [ - { - name: 'spender', - cl_type: 'Key' - }, - { - name: 'decr_by', - cl_type: 'U256' - } - ], - ret: 'Unit', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'decrease_allowance', + args: [ + { + name: 'spender', + cl_type: 'Key' + }, + { + name: 'decr_by', + cl_type: 'U256' + } + ], + ret: 'Unit', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'grant_role', - args: [ - { - name: 'role', - cl_type: { - ByteArray: 32 + entry_point: { + name: 'grant_role', + args: [ + { + name: 'role', + cl_type: { + ByteArray: 32 + } + }, + { + name: 'address', + cl_type: 'Key' } - }, - { - name: 'address', - cl_type: 'Key' - } - ], - ret: 'Unit', - access: 'Public', - entry_point_type: 'Called' + ], + ret: 'Unit', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'has_role', - args: [ - { - name: 'role', - cl_type: { - ByteArray: 32 + entry_point: { + name: 'has_role', + args: [ + { + name: 'role', + cl_type: { + ByteArray: 32 + } + }, + { + name: 'address', + cl_type: 'Key' } - }, - { - name: 'address', - cl_type: 'Key' - } - ], - ret: 'Bool', - access: 'Public', - entry_point_type: 'Called' + ], + ret: 'Bool', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'increase_allowance', - args: [ - { - name: 'spender', - cl_type: 'Key' - }, - { - name: 'inc_by', - cl_type: 'U256' - } - ], - ret: 'Unit', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'increase_allowance', + args: [ + { + name: 'spender', + cl_type: 'Key' + }, + { + name: 'inc_by', + cl_type: 'U256' + } + ], + ret: 'Unit', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'init', - args: [ - { - name: 'validator_address', - cl_type: 'PublicKey' + entry_point: { + name: 'init', + args: [ + { + name: 'validator_address', + cl_type: 'PublicKey' + }, + { + name: 'claim_time', + cl_type: 'U64' + } + ], + ret: 'Unit', + access: { + Groups: ['constructor_group'] }, - { - name: 'claim_time', - cl_type: 'U64' - } - ], - ret: 'Unit', - access: { - Groups: ['constructor_group'] - }, - entry_point_type: 'Called' + entry_point_type: 'Called' + } }, { name: 'mint', - args: [ - { - name: 'owner', - cl_type: 'Key' - }, - { - name: 'amount', - cl_type: 'U256' - } - ], - ret: 'Unit', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'mint', + args: [ + { + name: 'owner', + cl_type: 'Key' + }, + { + name: 'amount', + cl_type: 'U256' + } + ], + ret: 'Unit', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'name', - args: [], - ret: 'String', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'name', + args: [], + ret: 'String', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'remove_from_the_pool', - args: [ - { - name: 'amount', - cl_type: 'U512' - } - ], - ret: 'Unit', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'remove_from_the_pool', + args: [ + { + name: 'amount', + cl_type: 'U512' + } + ], + ret: 'Unit', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'revoke_role', - args: [ - { - name: 'role', - cl_type: { - ByteArray: 32 + entry_point: { + name: 'revoke_role', + args: [ + { + name: 'role', + cl_type: { + ByteArray: 32 + } + }, + { + name: 'address', + cl_type: 'Key' } - }, - { - name: 'address', - cl_type: 'Key' - } - ], - ret: 'Unit', - access: 'Public', - entry_point_type: 'Called' + ], + ret: 'Unit', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'stake', - args: [], - ret: 'Unit', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'stake', + args: [], + ret: 'Unit', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'staked_cspr', - args: [], - ret: 'U512', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'staked_cspr', + args: [], + ret: 'U512', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'symbol', - args: [], - ret: 'String', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'symbol', + args: [], + ret: 'String', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'total_supply', - args: [], - ret: 'U256', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'total_supply', + args: [], + ret: 'U256', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'transfer', - args: [ - { - name: 'recipient', - cl_type: 'Key' - }, - { - name: 'amount', - cl_type: 'U256' - } - ], - ret: 'Unit', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'transfer', + args: [ + { + name: 'recipient', + cl_type: 'Key' + }, + { + name: 'amount', + cl_type: 'U256' + } + ], + ret: 'Unit', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'transfer_from', - args: [ - { - name: 'owner', - cl_type: 'Key' - }, - { - name: 'recipient', - cl_type: 'Key' - }, - { - name: 'amount', - cl_type: 'U256' - } - ], - ret: 'Unit', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'transfer_from', + args: [ + { + name: 'owner', + cl_type: 'Key' + }, + { + name: 'recipient', + cl_type: 'Key' + }, + { + name: 'amount', + cl_type: 'U256' + } + ], + ret: 'Unit', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'unstake', - args: [ - { - name: 'scspr_amount', - cl_type: 'U256' - } - ], - ret: 'U32', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'unstake', + args: [ + { + name: 'scspr_amount', + cl_type: 'U256' + } + ], + ret: 'U32', + access: 'Public', + entry_point_type: 'Called' + } }, { name: 'withdraw_from_the_pool', - args: [ - { - name: 'amount', - cl_type: 'U512' - } - ], - ret: 'Unit', - access: 'Public', - entry_point_type: 'Called' + entry_point: { + name: 'withdraw_from_the_pool', + args: [ + { + name: 'amount', + cl_type: 'U512' + } + ], + ret: 'Unit', + access: 'Public', + entry_point_type: 'Called' + } } ], protocol_version: '2.0.0' @@ -628,5 +703,6 @@ describe('TransformKind JSON Parsing and CLValue Transformation', () => { expect(contract?.contractWasmHash.toPrefixedWasmString()).to.deep.equal( transformContractV2Json.kind.Write.Contract.contract_wasm_hash ); + expect(contract?.entryPoints[0].entryPoint).to.not.be.empty; }); }); diff --git a/src/types/clvalue/Map.test.ts b/src/types/clvalue/Map.test.ts index 08fe9345e..efb274c0a 100644 --- a/src/types/clvalue/Map.test.ts +++ b/src/types/clvalue/Map.test.ts @@ -37,6 +37,9 @@ describe('CLValue CLMap implementation', () => { testMap.append(myKey, myVal); expect(testMap.get('ABC')).to.be.deep.eq(myVal); + expect(testMap.get('ABC')?.i32?.toNumber()).to.be.deep.eq( + myVal.i32?.toNumber() + ); }); it('Get() should return undefined on non-existing key', () => { @@ -82,5 +85,8 @@ describe('CLValue CLMap implementation', () => { expect(fromJson).to.be.deep.eq(clValueMap); expect(json).to.be.deep.eq(expectedJson); + expect(fromJson.map?.get('ABC')?.i32?.toNumber()).to.be.deep.eq( + myVal.i32?.toNumber() + ); }); }); diff --git a/src/types/clvalue/Map.ts b/src/types/clvalue/Map.ts index ebc0be535..79e576252 100644 --- a/src/types/clvalue/Map.ts +++ b/src/types/clvalue/Map.ts @@ -195,7 +195,7 @@ export class CLValueMap { const { result: u32, bytes: u32Bytes } = CLValueUInt32.fromBytes(bytes); const size = u32.toNumber(); - let remainder = u32Bytes; + const remainder = u32Bytes; if (size === 0) { return { result: mapResult, bytes: remainder }; @@ -204,14 +204,12 @@ export class CLValueMap { for (let i = 0; i < size; i++) { if (remainder.length) { const keyVal = CLValueParser.fromBytesByType(remainder, mapType.key); - remainder = keyVal.bytes; if (!keyVal.bytes || !keyVal.result) { continue; } - const valVal = CLValueParser.fromBytesByType(remainder, mapType.val); - remainder = valVal.bytes; + const valVal = CLValueParser.fromBytesByType(keyVal.bytes, mapType.val); if (!valVal.bytes || !valVal.result) { continue; diff --git a/src/types/clvalue/Parser.test.ts b/src/types/clvalue/Parser.test.ts new file mode 100644 index 000000000..7bebb8327 --- /dev/null +++ b/src/types/clvalue/Parser.test.ts @@ -0,0 +1,42 @@ +import { expect } from 'chai'; + +import { CLValueParser } from './Parser'; +import { CLValue } from './CLValue'; +import { CLTypeMap } from './cltype'; + +describe('CLValue Parser', () => { + it('should parse json to StoredValue', async () => { + const json = { + cl_type: { + Map: { + key: 'String', + value: { + List: { + Tuple2: ['String', 'Any'] + } + } + } + }, + bytes: + '080000000a0000004665654368616e6765640100000003000000666565081000000046656557616c6c65744368616e676564010000000a0000006665655f77616c6c65740b0d0000004f666665724163636570746564040000000a000000636f6c6c656374696f6e0b08000000746f6b656e5f69640a070000006f6666657265720b050000006f776e65720b0d0000004f6666657243616e63656c6564030000000a000000636f6c6c656374696f6e0b08000000746f6b656e5f69640a070000006f6666657265720b0d000000546f6b656e44656c6973746564020000000a000000636f6c6c656374696f6e0b08000000746f6b656e5f69640a0b000000546f6b656e4c6973746564040000000a000000636f6c6c656374696f6e0b08000000746f6b656e5f69640a050000006f776e65720b050000007072696365080c000000546f6b656e4f666665726564050000000a000000636f6c6c656374696f6e0b08000000746f6b656e5f69640a070000006f6666657265720b05000000707269636508140000006164646974696f6e616c5f726563697069656e740d0b09000000546f6b656e536f6c64040000000a000000636f6c6c656374696f6e0b08000000746f6b656e5f69640a0500000062757965720b140000006164646974696f6e616c5f726563697069656e740d0b', + parsed: null + }; + + const parsedCLValue = CLValueParser.fromJSON(json); + + expect(parsedCLValue).to.be.instanceOf(CLValue); + expect(parsedCLValue.getType()).to.be.instanceOf(CLTypeMap); + expect( + parsedCLValue.map + ?.getData()[0] + .inner1.getType() + .toString() + ).to.be.deep.equal('String'); + expect( + parsedCLValue.map + ?.getData()[0] + .inner2.getType() + .toJSON() + ).to.deep.equal({ List: { Tuple2: ['String', 'Any'] } }); + }); +}); diff --git a/src/types/clvalue/Parser.ts b/src/types/clvalue/Parser.ts index 80688dd4a..dfc8c9f2a 100644 --- a/src/types/clvalue/Parser.ts +++ b/src/types/clvalue/Parser.ts @@ -219,13 +219,6 @@ export class CLValueParser { ); result.tuple3 = tuple3?.result; return { result, bytes: tuple3?.bytes }; - // case TypeID.Dynamic: - // const typeData = CLTypeParser.matchBytesToCLType(bytes); - // result.type = new CLTypeDynamic( - // typeData.result?.getTypeID(), - // typeData?.result - // ); - // return { result, bytes: typeData?.bytes }; default: throw ErrUnsupportedCLType; } diff --git a/src/utils/constants.ts b/src/utils/constants.ts index d6c5c6fc8..1cbc7c0cd 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -1,6 +1,13 @@ -import { CasperNetworkName } from "../@types"; +import { CasperNetworkName } from '../@types'; -export const AuctionManagerContractHashMap: Record = { - [CasperNetworkName.Mainnet] : 'ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea', - [CasperNetworkName.Testnet] : '93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2' -} +export const AuctionManagerContractHashMap: Record< + CasperNetworkName, + string +> = { + [CasperNetworkName.Mainnet]: + 'ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea', + [CasperNetworkName.Testnet]: + '93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2', + [CasperNetworkName.Integration]: + 'e22d38bcf3454a93face78a353feaccbf1d637d1ef9ef2e061a655728ff59bbe' +};