From b2e6b92d9bfbacc1c03d6670c576c05f8edd7f27 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Fri, 1 Sep 2023 14:36:25 +0300 Subject: [PATCH 1/6] transactionIntent & transactionIntentBuilder --- src/transactionIntent.ts | 17 ++++++ .../transactionIntentBuilder.ts | 53 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 src/transactionIntent.ts create mode 100644 src/transactionIntentsFactories/transactionIntentBuilder.ts diff --git a/src/transactionIntent.ts b/src/transactionIntent.ts new file mode 100644 index 000000000..680495a28 --- /dev/null +++ b/src/transactionIntent.ts @@ -0,0 +1,17 @@ +import { BigNumber } from "bignumber.js"; + +export class TransactionIntent { + public sender: string; + public receiver: string; + public gasLimit: BigNumber.Value; + public value?: BigNumber.Value; + public data?: Uint8Array; + + public constructor(sender: string, receiver: string, gasLimit: BigNumber.Value, value?: BigNumber.Value, data?: Uint8Array) { + this.sender = sender; + this.receiver = receiver; + this.gasLimit = gasLimit; + this.value = value; + this.data = data; + } +} diff --git a/src/transactionIntentsFactories/transactionIntentBuilder.ts b/src/transactionIntentsFactories/transactionIntentBuilder.ts new file mode 100644 index 000000000..545c2627b --- /dev/null +++ b/src/transactionIntentsFactories/transactionIntentBuilder.ts @@ -0,0 +1,53 @@ +import { BigNumber } from "bignumber.js"; +import { IAddress, ITransactionPayload } from "../interface"; +import { ARGUMENTS_SEPARATOR } from "../constants"; +import { TransactionPayload } from "../transactionPayload"; +import { TransactionIntent } from "../transactionIntent"; + +interface Config { + minGasLimit: BigNumber.Value; + gasLimitPerByte: BigNumber.Value; +} + +export class TransactionIntentBuilder { + private config: Config; + private sender: IAddress; + private receiver: IAddress; + private dataParts: string[]; + private executionGasLimit: BigNumber.Value; + private value?: BigNumber.Value; + + constructor(config: Config, sender: IAddress, receiver: IAddress, dataParts: string[], executionGasLimit: BigNumber.Value, value?: BigNumber.Value) { + this.config = config; + this.sender = sender; + this.receiver = receiver; + this.dataParts = dataParts; + this.executionGasLimit = executionGasLimit; + this.value = value; + } + + private computeGasLimit(payload: ITransactionPayload, executionGasLimit: BigNumber.Value): BigNumber.Value { + const dataMovementGas = new BigNumber(this.config.minGasLimit).plus(new BigNumber(this.config.gasLimitPerByte).plus(new BigNumber(payload.length()))); + const gasLimit = new BigNumber(dataMovementGas).plus(new BigNumber(executionGasLimit)); + return gasLimit; + } + + private buildTransactionPayload(dataParts: string[]): ITransactionPayload { + const data = dataParts.join(ARGUMENTS_SEPARATOR); + return new TransactionPayload(data); + } + + build(): TransactionIntent { + const data = this.buildTransactionPayload(this.dataParts) + const gasLimit = this.computeGasLimit(data, this.executionGasLimit); + + + return new TransactionIntent( + this.sender.bech32(), + this.receiver.bech32(), + gasLimit, + this.value !== 0 ? this.value : 0, + data.valueOf() + ) + } +} From 2099f3d6dd845a636b45aa913e836b62e0bbf767 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Fri, 1 Sep 2023 17:21:07 +0300 Subject: [PATCH 2/6] started the sc intent factory --- src/constants.ts | 3 + src/tokenOperations/codec.ts | 5 +- .../smartContractTransactionIntentsFactory.ts | 77 +++++++++++++++++++ src/utils.codec.ts | 5 ++ 4 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 src/transactionIntentsFactories/smartContractTransactionIntentsFactory.ts diff --git a/src/constants.ts b/src/constants.ts index 66d72198a..11df29f34 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -10,3 +10,6 @@ export const ESDTNFT_TRANSFER_FUNCTION_NAME = "ESDTNFTTransfer"; export const MULTI_ESDTNFT_TRANSFER_FUNCTION_NAME = "MultiESDTNFTTransfer"; export const ESDT_TRANSFER_VALUE = "0"; export const ARGUMENTS_SEPARATOR = "@"; +export const VM_TYPE_WASM_VM = new Uint8Array([0x05, 0x00]); +export const CONTRACT_DEPLOY_ADDRESS = "erd1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6gq4hu" + diff --git a/src/tokenOperations/codec.ts b/src/tokenOperations/codec.ts index 3b33abfd6..8b9bc5988 100644 --- a/src/tokenOperations/codec.ts +++ b/src/tokenOperations/codec.ts @@ -32,10 +32,7 @@ export function bigIntToHex(value: BigNumber.Value): string { return contractsCodecUtils.getHexMagnitudeOfBigInt(value); } -export function utf8ToHex(value: string) { - const hex = Buffer.from(value).toString("hex"); - return codecUtils.zeroPadStringIfOddLength(hex); -} +export { utf8ToHex } from "../utils.codec"; export function bufferToHex(value: Buffer) { const hex = value.toString("hex"); diff --git a/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.ts b/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.ts new file mode 100644 index 000000000..1740d4809 --- /dev/null +++ b/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.ts @@ -0,0 +1,77 @@ +import { BigNumber } from "bignumber.js"; +import { IAddress } from "../interface"; +import { TransactionIntent } from "../transactionIntent"; +import { AbiRegistry, ArgSerializer, CodeMetadata, TypedValue } from "../smartcontracts"; +import { utf8ToHex } from "../utils.codec"; +import { CONTRACT_DEPLOY_ADDRESS, VM_TYPE_WASM_VM } from "../constants"; +import { NativeSerializer } from "../smartcontracts/nativeSerializer"; +import { Err } from "../errors"; +import { Address } from "../address"; +import { TransactionIntentBuilder } from "./transactionIntentBuilder"; + +interface Config { + chainID: string; + minGasLimit: BigNumber.Value; + gasLimitPerByte: BigNumber.Value; +} + +export class SmartContractTransactionIntentsFactory { + private config: Config; + private abiRegistry?: AbiRegistry; + + constructor(config: Config, abi?: AbiRegistry) { + this.config = config; + this.abiRegistry = abi; + } + + createTransactionIntentForDeploy( + sender: IAddress, + bytecode: Uint8Array, + gasLimit: BigNumber.Value, + args: any[], + isUpgradeable: boolean = true, + isReadable: boolean = true, + isPayable: boolean = false, + isPayableBySmartContract: boolean = false + ): TransactionIntent { + const metadata = new CodeMetadata(isUpgradeable, isReadable, isPayable, isPayableBySmartContract); + let parts = [ + utf8ToHex(bytecode.toString()), + utf8ToHex(VM_TYPE_WASM_VM.toString()), + metadata.toString() + ]; + + parts = parts.concat(this.argsToStrings(args)); + + return new TransactionIntentBuilder( + this.config, + sender, + Address.fromBech32(CONTRACT_DEPLOY_ADDRESS), + parts, + gasLimit + ).build() + } + + private argsToStrings(args: any): string[] { + if (this.abiRegistry !== undefined) { + const constructorDefinition = this.abiRegistry.constructorDefinition + const typedArgs = NativeSerializer.nativeToTypedValues(args, constructorDefinition) + return new ArgSerializer().valuesToStrings(args); + } + + if (this.areArgsOfTypedValue(args)) { + return new ArgSerializer().valuesToStrings(args); + } + + throw new Err("Can't convert args to TypedValues"); + } + + private areArgsOfTypedValue(args: any[]): boolean { + for (const arg of args) { + if (!(arg instanceof TypedValue)) { + return false; + } + } + return true; + } +} diff --git a/src/utils.codec.ts b/src/utils.codec.ts index 8867c889f..eb369345e 100644 --- a/src/utils.codec.ts +++ b/src/utils.codec.ts @@ -20,3 +20,8 @@ export function zeroPadStringIfOddLength(input: string): string { return input; } + +export function utf8ToHex(value: string) { + const hex = Buffer.from(value).toString("hex"); + return zeroPadStringIfOddLength(hex); +} From a8091a992debf9c9d95c08b6c7e39aa7ddd06cf5 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Mon, 4 Sep 2023 14:59:08 +0300 Subject: [PATCH 3/6] add deploy intent and unit tests --- src/testdata/adder.abi.json | 62 ++++++++++++++++++ src/testdata/adder.wasm | Bin 0 -> 687 bytes ...tContractTransactionIntentsFactory.spec.ts | 60 +++++++++++++++++ .../smartContractTransactionIntentsFactory.ts | 10 +-- .../transactionIntentBuilder.ts | 6 +- src/utils.codec.ts | 4 ++ 6 files changed, 134 insertions(+), 8 deletions(-) create mode 100644 src/testdata/adder.abi.json create mode 100755 src/testdata/adder.wasm create mode 100644 src/transactionIntentsFactories/smartContractTransactionIntentsFactory.spec.ts diff --git a/src/testdata/adder.abi.json b/src/testdata/adder.abi.json new file mode 100644 index 000000000..88d5bf134 --- /dev/null +++ b/src/testdata/adder.abi.json @@ -0,0 +1,62 @@ +{ + "buildInfo": { + "rustc": { + "version": "1.71.0-nightly", + "commitHash": "7f94b314cead7059a71a265a8b64905ef2511796", + "commitDate": "2023-04-23", + "channel": "Nightly", + "short": "rustc 1.71.0-nightly (7f94b314c 2023-04-23)" + }, + "contractCrate": { + "name": "adder", + "version": "0.0.0" + }, + "framework": { + "name": "multiversx-sc", + "version": "0.41.3" + } + }, + "docs": [ + "One of the simplest smart contracts possible,", + "it holds a single variable in storage, which anyone can increment." + ], + "name": "Adder", + "constructor": { + "inputs": [ + { + "name": "initial_value", + "type": "BigUint" + } + ], + "outputs": [] + }, + "endpoints": [ + { + "name": "getSum", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "docs": [ + "Add desired amount to the storage variable." + ], + "name": "add", + "mutability": "mutable", + "inputs": [ + { + "name": "value", + "type": "BigUint" + } + ], + "outputs": [] + } + ], + "events": [], + "hasCallback": false, + "types": {} +} diff --git a/src/testdata/adder.wasm b/src/testdata/adder.wasm new file mode 100755 index 0000000000000000000000000000000000000000..77ce7e234a7c0110114e1527bd49705ec98ecf88 GIT binary patch literal 687 zcmZuvO>dh(5S`g2n6M3OW2=>;9w?{w)LYNNQXNIAqDpDcur_OK*+8{GBA@V2$hA@q z{XP9t?k?a+m3m-z=e;*?J_Lv=M*zT&P6Chswh3w5{)7ZuNNC%|<}v`b@8ztkbSl%c(}A6dtEGU|MAyrVW0x|qbRizhX24mLq@p$|T(}Jio literal 0 HcmV?d00001 diff --git a/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.spec.ts b/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.spec.ts new file mode 100644 index 000000000..fbcd147ca --- /dev/null +++ b/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.spec.ts @@ -0,0 +1,60 @@ +import { assert, expect } from "chai"; +import { SmartContractTransactionIntentsFactory } from "./smartContractTransactionIntentsFactory"; +import { Address } from "../address"; +import { Code } from "../smartcontracts/code"; +import { promises } from "fs"; +import { AbiRegistry } from "../smartcontracts/typesystem/abiRegistry"; +import { U32Value } from "../smartcontracts"; +import { CONTRACT_DEPLOY_ADDRESS } from "../constants"; + +describe("test smart contract intents factory", function () { + let smartContractIntentsFactory: SmartContractTransactionIntentsFactory; + let abiSmartContractIntentsFactory: SmartContractTransactionIntentsFactory; + let adderByteCode: Code; + let abiRegistry: AbiRegistry; + + before(async function () { + smartContractIntentsFactory = new SmartContractTransactionIntentsFactory({ chainID: "D", minGasLimit: 50000, gasLimitPerByte: 1500 }); + let adderBuffer = await promises.readFile("src/testdata/adder.wasm"); + adderByteCode = Code.fromBuffer(adderBuffer); + + let abiJson = await promises.readFile("src/testdata/adder.abi.json", { encoding: "utf8" }); + let abiObj = JSON.parse(abiJson); + abiRegistry = AbiRegistry.create(abiObj); + + abiSmartContractIntentsFactory = new SmartContractTransactionIntentsFactory({ chainID: "D", minGasLimit: 50000, gasLimitPerByte: 1500 }, abiRegistry); + }); + + it("should throw error", async function () { + const sender = Address.fromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); + const gasLimit = 6000000; + const args = [0]; + try { + smartContractIntentsFactory.createTransactionIntentForDeploy(sender, adderByteCode.valueOf(), gasLimit, args); + } + catch (err) { + expect(err.message).to.equal("Can't convert args to TypedValues"); + } + }); + + it("should build deploy intent", async function () { + const sender = Address.fromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); + const gasLimit = 6000000; + const args = [new U32Value(0)]; + + const deployIntent = smartContractIntentsFactory.createTransactionIntentForDeploy(sender, adderByteCode.valueOf(), gasLimit, args); + const abiDeployIntent = abiSmartContractIntentsFactory.createTransactionIntentForDeploy(sender, adderByteCode.valueOf(), gasLimit, args); + + assert.equal(deployIntent.sender, "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); + assert.equal(deployIntent.receiver, CONTRACT_DEPLOY_ADDRESS); + assert.isDefined(deployIntent.data); + + if (deployIntent.data) { + const expectedGasLimit = 6000000 + 50000 + 1500 * deployIntent.data.length; + assert.equal(deployIntent.gasLimit.valueOf(), expectedGasLimit); + } + assert.equal(deployIntent.value, 0); + + assert.deepEqual(deployIntent, abiDeployIntent); + }); +}); diff --git a/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.ts b/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.ts index 1740d4809..ec95be6de 100644 --- a/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.ts +++ b/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.ts @@ -2,7 +2,7 @@ import { BigNumber } from "bignumber.js"; import { IAddress } from "../interface"; import { TransactionIntent } from "../transactionIntent"; import { AbiRegistry, ArgSerializer, CodeMetadata, TypedValue } from "../smartcontracts"; -import { utf8ToHex } from "../utils.codec"; +import { byteArrayToHex } from "../utils.codec"; import { CONTRACT_DEPLOY_ADDRESS, VM_TYPE_WASM_VM } from "../constants"; import { NativeSerializer } from "../smartcontracts/nativeSerializer"; import { Err } from "../errors"; @@ -32,12 +32,12 @@ export class SmartContractTransactionIntentsFactory { isUpgradeable: boolean = true, isReadable: boolean = true, isPayable: boolean = false, - isPayableBySmartContract: boolean = false + isPayableBySmartContract: boolean = true ): TransactionIntent { const metadata = new CodeMetadata(isUpgradeable, isReadable, isPayable, isPayableBySmartContract); let parts = [ - utf8ToHex(bytecode.toString()), - utf8ToHex(VM_TYPE_WASM_VM.toString()), + byteArrayToHex(bytecode), + byteArrayToHex(VM_TYPE_WASM_VM), metadata.toString() ]; @@ -52,7 +52,7 @@ export class SmartContractTransactionIntentsFactory { ).build() } - private argsToStrings(args: any): string[] { + private argsToStrings(args: any[]): string[] { if (this.abiRegistry !== undefined) { const constructorDefinition = this.abiRegistry.constructorDefinition const typedArgs = NativeSerializer.nativeToTypedValues(args, constructorDefinition) diff --git a/src/transactionIntentsFactories/transactionIntentBuilder.ts b/src/transactionIntentsFactories/transactionIntentBuilder.ts index 545c2627b..5f80c4b06 100644 --- a/src/transactionIntentsFactories/transactionIntentBuilder.ts +++ b/src/transactionIntentsFactories/transactionIntentBuilder.ts @@ -27,12 +27,12 @@ export class TransactionIntentBuilder { } private computeGasLimit(payload: ITransactionPayload, executionGasLimit: BigNumber.Value): BigNumber.Value { - const dataMovementGas = new BigNumber(this.config.minGasLimit).plus(new BigNumber(this.config.gasLimitPerByte).plus(new BigNumber(payload.length()))); + const dataMovementGas = new BigNumber(this.config.minGasLimit).plus(new BigNumber(this.config.gasLimitPerByte).multipliedBy(new BigNumber(payload.length()))); const gasLimit = new BigNumber(dataMovementGas).plus(new BigNumber(executionGasLimit)); return gasLimit; } - private buildTransactionPayload(dataParts: string[]): ITransactionPayload { + private buildTransactionPayload(dataParts: string[]): TransactionPayload { const data = dataParts.join(ARGUMENTS_SEPARATOR); return new TransactionPayload(data); } @@ -46,7 +46,7 @@ export class TransactionIntentBuilder { this.sender.bech32(), this.receiver.bech32(), gasLimit, - this.value !== 0 ? this.value : 0, + this.value !== undefined ? this.value : 0, data.valueOf() ) } diff --git a/src/utils.codec.ts b/src/utils.codec.ts index eb369345e..2d79785b5 100644 --- a/src/utils.codec.ts +++ b/src/utils.codec.ts @@ -25,3 +25,7 @@ export function utf8ToHex(value: string) { const hex = Buffer.from(value).toString("hex"); return zeroPadStringIfOddLength(hex); } + +export function byteArrayToHex(byteArray: Uint8Array): string { + return Buffer.from(byteArray).toString("hex"); +} From 7db0a4a96f6aade942e37adda931c349389ba166 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Mon, 4 Sep 2023 20:17:12 +0300 Subject: [PATCH 4/6] smart contract transaction intents factory --- ...tContractTransactionIntentsFactory.spec.ts | 48 ++++++++++ .../smartContractTransactionIntentsFactory.ts | 94 ++++++++++++++++--- .../transactionIntentBuilder.ts | 7 +- 3 files changed, 133 insertions(+), 16 deletions(-) diff --git a/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.spec.ts b/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.spec.ts index fbcd147ca..1b02baa79 100644 --- a/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.spec.ts +++ b/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.spec.ts @@ -57,4 +57,52 @@ describe("test smart contract intents factory", function () { assert.deepEqual(deployIntent, abiDeployIntent); }); + + it("should build execute intent", async function () { + const sender = Address.fromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); + const contract = Address.fromBech32("erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4"); + const func = "add"; + const gasLimit = 6000000; + const args = [new U32Value(7)]; + + const deployIntent = smartContractIntentsFactory.createTransactionIntentForExecute(sender, contract, func, gasLimit, args); + const abiDeployIntent = abiSmartContractIntentsFactory.createTransactionIntentForExecute(sender, contract, func, gasLimit, args); + + assert.equal(deployIntent.sender, "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); + assert.equal(deployIntent.receiver, "erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4"); + + assert.isDefined(deployIntent.data); + let decoder = new TextDecoder(); + assert.equal(decoder.decode(deployIntent.data), "add@07"); + + assert.equal(deployIntent.gasLimit.valueOf(), 6059000); + assert.equal(deployIntent.value, 0); + + assert.deepEqual(deployIntent, abiDeployIntent); + }); + + it("should build upgrade intent", async function () { + const sender = Address.fromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); + const contract = Address.fromBech32("erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4"); + const gasLimit = 6000000; + const args = [new U32Value(0)]; + + const deployIntent = smartContractIntentsFactory.createTransactionIntentForUpgrade(sender, contract, adderByteCode.valueOf(), gasLimit, args); + const abiDeployIntent = abiSmartContractIntentsFactory.createTransactionIntentForUpgrade(sender, contract, adderByteCode.valueOf(), gasLimit, args); + + assert.equal(deployIntent.sender, "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); + assert.equal(deployIntent.receiver, "erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4"); + assert.isDefined(deployIntent.data); + + if (deployIntent.data) { + let decoder = new TextDecoder(); + assert(decoder.decode(deployIntent.data).startsWith("upgradeContract@", 0)); + + const expectedGasLimit = 6000000 + 50000 + 1500 * deployIntent.data.length; + assert.equal(deployIntent.gasLimit.valueOf(), expectedGasLimit); + } + assert.equal(deployIntent.value, 0); + + assert.deepEqual(deployIntent, abiDeployIntent); + }); }); diff --git a/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.ts b/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.ts index ec95be6de..89fb089c9 100644 --- a/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.ts +++ b/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.ts @@ -1,7 +1,7 @@ import { BigNumber } from "bignumber.js"; import { IAddress } from "../interface"; import { TransactionIntent } from "../transactionIntent"; -import { AbiRegistry, ArgSerializer, CodeMetadata, TypedValue } from "../smartcontracts"; +import { AbiRegistry, ArgSerializer, CodeMetadata, EndpointDefinition, TypedValue } from "../smartcontracts"; import { byteArrayToHex } from "../utils.codec"; import { CONTRACT_DEPLOY_ADDRESS, VM_TYPE_WASM_VM } from "../constants"; import { NativeSerializer } from "../smartcontracts/nativeSerializer"; @@ -29,10 +29,10 @@ export class SmartContractTransactionIntentsFactory { bytecode: Uint8Array, gasLimit: BigNumber.Value, args: any[], - isUpgradeable: boolean = true, - isReadable: boolean = true, - isPayable: boolean = false, - isPayableBySmartContract: boolean = true + isUpgradeable = true, + isReadable = true, + isPayable = false, + isPayableBySmartContract = true ): TransactionIntent { const metadata = new CodeMetadata(isUpgradeable, isReadable, isPayable, isPayableBySmartContract); let parts = [ @@ -41,7 +41,14 @@ export class SmartContractTransactionIntentsFactory { metadata.toString() ]; - parts = parts.concat(this.argsToStrings(args)); + let preparedArgs: string[]; + if (this.abiRegistry) { + preparedArgs = this.argsToStrings(args, this.abiRegistry.constructorDefinition) + } + else { + preparedArgs = this.argsToStrings(args) + } + parts = parts.concat(preparedArgs); return new TransactionIntentBuilder( this.config, @@ -49,14 +56,77 @@ export class SmartContractTransactionIntentsFactory { Address.fromBech32(CONTRACT_DEPLOY_ADDRESS), parts, gasLimit - ).build() + ).build(); } - private argsToStrings(args: any[]): string[] { - if (this.abiRegistry !== undefined) { - const constructorDefinition = this.abiRegistry.constructorDefinition - const typedArgs = NativeSerializer.nativeToTypedValues(args, constructorDefinition) - return new ArgSerializer().valuesToStrings(args); + createTransactionIntentForExecute( + sender: IAddress, + contractAddress: IAddress, + func: string, + gasLimit: BigNumber.Value, + args: any[] = [] + ): TransactionIntent { + let parts: string[] = [func]; + + let preparedArgs: string[]; + if (this.abiRegistry) { + preparedArgs = this.argsToStrings(args, this.abiRegistry.getEndpoint(func)); + } + else { + preparedArgs = this.argsToStrings(args); + } + parts = parts.concat(preparedArgs); + + return new TransactionIntentBuilder( + this.config, + sender, + contractAddress, + parts, + gasLimit + ).build(); + } + + createTransactionIntentForUpgrade( + sender: IAddress, + contract: IAddress, + bytecode: Uint8Array, + gasLimit: BigNumber.Value, + args: any[], + isUpgradeable = true, + isReadable = true, + isPayable = false, + isPayableBySmartContract = true + ): TransactionIntent { + const metadata = new CodeMetadata(isUpgradeable, isReadable, isPayable, isPayableBySmartContract); + + let parts = [ + "upgradeContract", + byteArrayToHex(bytecode), + metadata.toString() + ]; + + let preparedArgs: string[]; + if (this.abiRegistry) { + preparedArgs = this.argsToStrings(args, this.abiRegistry.constructorDefinition) + } + else { + preparedArgs = this.argsToStrings(args) + } + parts = parts.concat(preparedArgs); + + return new TransactionIntentBuilder( + this.config, + sender, + contract, + parts, + gasLimit + ).build(); + } + + private argsToStrings(args: any[], endpoint?: EndpointDefinition): string[] { + if (endpoint) { + const typedArgs = NativeSerializer.nativeToTypedValues(args, endpoint) + return new ArgSerializer().valuesToStrings(typedArgs); } if (this.areArgsOfTypedValue(args)) { diff --git a/src/transactionIntentsFactories/transactionIntentBuilder.ts b/src/transactionIntentsFactories/transactionIntentBuilder.ts index 5f80c4b06..ffa1f42bb 100644 --- a/src/transactionIntentsFactories/transactionIntentBuilder.ts +++ b/src/transactionIntentsFactories/transactionIntentBuilder.ts @@ -32,16 +32,15 @@ export class TransactionIntentBuilder { return gasLimit; } - private buildTransactionPayload(dataParts: string[]): TransactionPayload { - const data = dataParts.join(ARGUMENTS_SEPARATOR); + private buildTransactionPayload(): TransactionPayload { + const data = this.dataParts.join(ARGUMENTS_SEPARATOR); return new TransactionPayload(data); } build(): TransactionIntent { - const data = this.buildTransactionPayload(this.dataParts) + const data = this.buildTransactionPayload() const gasLimit = this.computeGasLimit(data, this.executionGasLimit); - return new TransactionIntent( this.sender.bech32(), this.receiver.bech32(), From 5ba4506d488371109b3bb2250283ac54deeaf984 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Thu, 7 Sep 2023 17:26:35 +0300 Subject: [PATCH 5/6] fixes after review --- src/transactionIntent.ts | 18 ++- ...tContractTransactionIntentsFactory.spec.ts | 123 ++++++++++++---- .../smartContractTransactionIntentsFactory.ts | 138 +++++++++--------- .../transactionIntentBuilder.ts | 39 +++-- src/utils.codec.spec.ts | 16 +- 5 files changed, 212 insertions(+), 122 deletions(-) diff --git a/src/transactionIntent.ts b/src/transactionIntent.ts index 680495a28..43cb9e36c 100644 --- a/src/transactionIntent.ts +++ b/src/transactionIntent.ts @@ -7,11 +7,17 @@ export class TransactionIntent { public value?: BigNumber.Value; public data?: Uint8Array; - public constructor(sender: string, receiver: string, gasLimit: BigNumber.Value, value?: BigNumber.Value, data?: Uint8Array) { - this.sender = sender; - this.receiver = receiver; - this.gasLimit = gasLimit; - this.value = value; - this.data = data; + public constructor(options: { + sender: string, + receiver: string, + gasLimit: BigNumber.Value, + value?: BigNumber.Value, + data?: Uint8Array + }) { + this.sender = options.sender; + this.receiver = options.receiver; + this.gasLimit = options.gasLimit; + this.value = options.value; + this.data = options.data; } } diff --git a/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.spec.ts b/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.spec.ts index 1b02baa79..c2a8513c6 100644 --- a/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.spec.ts +++ b/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.spec.ts @@ -2,52 +2,78 @@ import { assert, expect } from "chai"; import { SmartContractTransactionIntentsFactory } from "./smartContractTransactionIntentsFactory"; import { Address } from "../address"; import { Code } from "../smartcontracts/code"; -import { promises } from "fs"; import { AbiRegistry } from "../smartcontracts/typesystem/abiRegistry"; import { U32Value } from "../smartcontracts"; import { CONTRACT_DEPLOY_ADDRESS } from "../constants"; +import { loadContractCode, loadAbiRegistry } from "../testutils/utils"; +import { Err } from "../errors"; describe("test smart contract intents factory", function () { - let smartContractIntentsFactory: SmartContractTransactionIntentsFactory; - let abiSmartContractIntentsFactory: SmartContractTransactionIntentsFactory; + let factory: SmartContractTransactionIntentsFactory; + let abiAwareFactory: SmartContractTransactionIntentsFactory; let adderByteCode: Code; let abiRegistry: AbiRegistry; before(async function () { - smartContractIntentsFactory = new SmartContractTransactionIntentsFactory({ chainID: "D", minGasLimit: 50000, gasLimitPerByte: 1500 }); - let adderBuffer = await promises.readFile("src/testdata/adder.wasm"); - adderByteCode = Code.fromBuffer(adderBuffer); - - let abiJson = await promises.readFile("src/testdata/adder.abi.json", { encoding: "utf8" }); - let abiObj = JSON.parse(abiJson); - abiRegistry = AbiRegistry.create(abiObj); - - abiSmartContractIntentsFactory = new SmartContractTransactionIntentsFactory({ chainID: "D", minGasLimit: 50000, gasLimitPerByte: 1500 }, abiRegistry); + factory = new SmartContractTransactionIntentsFactory({ + config: + { + chainID: "D", + minGasLimit: 50000, + gasLimitPerByte: 1500 + } + }); + + adderByteCode = await loadContractCode("src/testdata/adder.wasm"); + abiRegistry = await loadAbiRegistry("src/testdata/adder.abi.json"); + + abiAwareFactory = new SmartContractTransactionIntentsFactory({ + config: + { + chainID: "D", + minGasLimit: 50000, + gasLimitPerByte: 1500 + }, + abi: abiRegistry + }, + ); }); - it("should throw error", async function () { + it("should throw error when args are not of type 'TypedValue'", async function () { const sender = Address.fromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); const gasLimit = 6000000; const args = [0]; - try { - smartContractIntentsFactory.createTransactionIntentForDeploy(sender, adderByteCode.valueOf(), gasLimit, args); - } - catch (err) { - expect(err.message).to.equal("Can't convert args to TypedValues"); - } + + assert.throws(() => factory.createTransactionIntentForDeploy({ + sender: sender, + bytecode: adderByteCode.valueOf(), + gasLimit: gasLimit, + args: args + }), Err, "Can't convert args to TypedValues"); }); - it("should build deploy intent", async function () { + it("should build intent for deploy", async function () { const sender = Address.fromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); const gasLimit = 6000000; const args = [new U32Value(0)]; - const deployIntent = smartContractIntentsFactory.createTransactionIntentForDeploy(sender, adderByteCode.valueOf(), gasLimit, args); - const abiDeployIntent = abiSmartContractIntentsFactory.createTransactionIntentForDeploy(sender, adderByteCode.valueOf(), gasLimit, args); + const deployIntent = factory.createTransactionIntentForDeploy({ + sender: sender, + bytecode: adderByteCode.valueOf(), + gasLimit: gasLimit, + args: args + }); + const abiDeployIntent = abiAwareFactory.createTransactionIntentForDeploy({ + sender: sender, + bytecode: adderByteCode.valueOf(), + gasLimit: gasLimit, + args: args + }); assert.equal(deployIntent.sender, "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); assert.equal(deployIntent.receiver, CONTRACT_DEPLOY_ADDRESS); assert.isDefined(deployIntent.data); + expect(deployIntent.data?.length).to.be.greaterThan(0); if (deployIntent.data) { const expectedGasLimit = 6000000 + 50000 + 1500 * deployIntent.data.length; @@ -58,22 +84,33 @@ describe("test smart contract intents factory", function () { assert.deepEqual(deployIntent, abiDeployIntent); }); - it("should build execute intent", async function () { + it("should build intent for execute", async function () { const sender = Address.fromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); const contract = Address.fromBech32("erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4"); const func = "add"; const gasLimit = 6000000; const args = [new U32Value(7)]; - const deployIntent = smartContractIntentsFactory.createTransactionIntentForExecute(sender, contract, func, gasLimit, args); - const abiDeployIntent = abiSmartContractIntentsFactory.createTransactionIntentForExecute(sender, contract, func, gasLimit, args); + const deployIntent = factory.createTransactionIntentForExecute({ + sender: sender, + contractAddress: contract, + func: func, + gasLimit: gasLimit, + args: args + }); + const abiDeployIntent = abiAwareFactory.createTransactionIntentForExecute({ + sender: sender, + contractAddress: contract, + func: func, + gasLimit: gasLimit, + args: args + }); assert.equal(deployIntent.sender, "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); assert.equal(deployIntent.receiver, "erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4"); assert.isDefined(deployIntent.data); - let decoder = new TextDecoder(); - assert.equal(decoder.decode(deployIntent.data), "add@07"); + assert.deepEqual(deployIntent.data, Buffer.from("add@07")); assert.equal(deployIntent.gasLimit.valueOf(), 6059000); assert.equal(deployIntent.value, 0); @@ -81,22 +118,33 @@ describe("test smart contract intents factory", function () { assert.deepEqual(deployIntent, abiDeployIntent); }); - it("should build upgrade intent", async function () { + it("should build intent for upgrade", async function () { const sender = Address.fromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); const contract = Address.fromBech32("erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4"); const gasLimit = 6000000; const args = [new U32Value(0)]; - const deployIntent = smartContractIntentsFactory.createTransactionIntentForUpgrade(sender, contract, adderByteCode.valueOf(), gasLimit, args); - const abiDeployIntent = abiSmartContractIntentsFactory.createTransactionIntentForUpgrade(sender, contract, adderByteCode.valueOf(), gasLimit, args); + const deployIntent = factory.createTransactionIntentForUpgrade({ + sender: sender, + contract: contract, + bytecode: adderByteCode.valueOf(), + gasLimit: gasLimit, + args: args + }); + const abiDeployIntent = abiAwareFactory.createTransactionIntentForUpgrade({ + sender: sender, + contract: contract, + bytecode: adderByteCode.valueOf(), + gasLimit: gasLimit, + args: args + }); assert.equal(deployIntent.sender, "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); assert.equal(deployIntent.receiver, "erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4"); assert.isDefined(deployIntent.data); if (deployIntent.data) { - let decoder = new TextDecoder(); - assert(decoder.decode(deployIntent.data).startsWith("upgradeContract@", 0)); + assert(checkIfByteArrayStartsWith(deployIntent.data, "upgradeContract@")); const expectedGasLimit = 6000000 + 50000 + 1500 * deployIntent.data.length; assert.equal(deployIntent.gasLimit.valueOf(), expectedGasLimit); @@ -105,4 +153,15 @@ describe("test smart contract intents factory", function () { assert.deepEqual(deployIntent, abiDeployIntent); }); + + function checkIfByteArrayStartsWith(array: Uint8Array, sequence: string) { + const sequenceBytes = Buffer.from(sequence); + + for (let i = 0; i < sequenceBytes.length; i++) { + if (sequenceBytes[i] !== array[i]) { + return false; + } + } + return true; + } }); diff --git a/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.ts b/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.ts index 89fb089c9..21b5a83c7 100644 --- a/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.ts +++ b/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.ts @@ -1,7 +1,7 @@ import { BigNumber } from "bignumber.js"; import { IAddress } from "../interface"; import { TransactionIntent } from "../transactionIntent"; -import { AbiRegistry, ArgSerializer, CodeMetadata, EndpointDefinition, TypedValue } from "../smartcontracts"; +import { AbiRegistry, ArgSerializer, CodeMetadata, EndpointDefinition } from "../smartcontracts"; import { byteArrayToHex } from "../utils.codec"; import { CONTRACT_DEPLOY_ADDRESS, VM_TYPE_WASM_VM } from "../constants"; import { NativeSerializer } from "../smartcontracts/nativeSerializer"; @@ -16,114 +16,118 @@ interface Config { } export class SmartContractTransactionIntentsFactory { - private config: Config; - private abiRegistry?: AbiRegistry; - - constructor(config: Config, abi?: AbiRegistry) { + private readonly config: Config; + private readonly abiRegistry?: AbiRegistry; + + constructor({ + config, + abi + }: { + config: Config; + abi?: AbiRegistry; + }) { this.config = config; this.abiRegistry = abi; } - createTransactionIntentForDeploy( + createTransactionIntentForDeploy(options: { sender: IAddress, bytecode: Uint8Array, gasLimit: BigNumber.Value, - args: any[], - isUpgradeable = true, - isReadable = true, - isPayable = false, - isPayableBySmartContract = true - ): TransactionIntent { + args?: any[], + isUpgradeable?: boolean, + isReadable?: boolean, + isPayable?: boolean, + isPayableBySmartContract?: boolean + }): TransactionIntent { + const isUpgradeable = options.isUpgradeable || true; + const isReadable = options.isReadable || true; + const isPayable = options.isPayable || false; + const isPayableBySmartContract = options.isPayableBySmartContract || true; + + const args = options.args || []; + const metadata = new CodeMetadata(isUpgradeable, isReadable, isPayable, isPayableBySmartContract); let parts = [ - byteArrayToHex(bytecode), + byteArrayToHex(options.bytecode), byteArrayToHex(VM_TYPE_WASM_VM), metadata.toString() ]; - let preparedArgs: string[]; - if (this.abiRegistry) { - preparedArgs = this.argsToStrings(args, this.abiRegistry.constructorDefinition) - } - else { - preparedArgs = this.argsToStrings(args) - } + const preparedArgs = this.argsToDataParts(args, this.abiRegistry?.constructorDefinition) parts = parts.concat(preparedArgs); - return new TransactionIntentBuilder( - this.config, - sender, - Address.fromBech32(CONTRACT_DEPLOY_ADDRESS), - parts, - gasLimit - ).build(); + return new TransactionIntentBuilder({ + config: this.config, + sender: options.sender, + receiver: Address.fromBech32(CONTRACT_DEPLOY_ADDRESS), + dataParts: parts, + executionGasLimit: options.gasLimit + }).build(); } - createTransactionIntentForExecute( + createTransactionIntentForExecute(options: { sender: IAddress, contractAddress: IAddress, func: string, gasLimit: BigNumber.Value, - args: any[] = [] + args?: any[] + } ): TransactionIntent { - let parts: string[] = [func]; + const args = options.args || []; + let parts: string[] = [options.func]; - let preparedArgs: string[]; - if (this.abiRegistry) { - preparedArgs = this.argsToStrings(args, this.abiRegistry.getEndpoint(func)); - } - else { - preparedArgs = this.argsToStrings(args); - } + const preparedArgs = this.argsToDataParts(args, this.abiRegistry?.constructorDefinition) parts = parts.concat(preparedArgs); - return new TransactionIntentBuilder( - this.config, - sender, - contractAddress, - parts, - gasLimit - ).build(); + return new TransactionIntentBuilder({ + config: this.config, + sender: options.sender, + receiver: options.contractAddress, + dataParts: parts, + executionGasLimit: options.gasLimit + }).build(); } - createTransactionIntentForUpgrade( + createTransactionIntentForUpgrade(options: { sender: IAddress, contract: IAddress, bytecode: Uint8Array, gasLimit: BigNumber.Value, - args: any[], - isUpgradeable = true, - isReadable = true, - isPayable = false, - isPayableBySmartContract = true + args?: any[], + isUpgradeable?: boolean, + isReadable?: boolean, + isPayable?: boolean, + isPayableBySmartContract?: boolean + } ): TransactionIntent { + const isUpgradeable = options.isUpgradeable || true; + const isReadable = options.isReadable || true; + const isPayable = options.isPayable || false; + const isPayableBySmartContract = options.isPayableBySmartContract || true; + + const args = options.args || []; const metadata = new CodeMetadata(isUpgradeable, isReadable, isPayable, isPayableBySmartContract); let parts = [ "upgradeContract", - byteArrayToHex(bytecode), + byteArrayToHex(options.bytecode), metadata.toString() ]; - let preparedArgs: string[]; - if (this.abiRegistry) { - preparedArgs = this.argsToStrings(args, this.abiRegistry.constructorDefinition) - } - else { - preparedArgs = this.argsToStrings(args) - } + const preparedArgs = this.argsToDataParts(args, this.abiRegistry?.constructorDefinition) parts = parts.concat(preparedArgs); - return new TransactionIntentBuilder( - this.config, - sender, - contract, - parts, - gasLimit - ).build(); + return new TransactionIntentBuilder({ + config: this.config, + sender: options.sender, + receiver: options.contract, + dataParts: parts, + executionGasLimit: options.gasLimit + }).build(); } - private argsToStrings(args: any[], endpoint?: EndpointDefinition): string[] { + private argsToDataParts(args: any[], endpoint?: EndpointDefinition): string[] { if (endpoint) { const typedArgs = NativeSerializer.nativeToTypedValues(args, endpoint) return new ArgSerializer().valuesToStrings(typedArgs); @@ -138,7 +142,7 @@ export class SmartContractTransactionIntentsFactory { private areArgsOfTypedValue(args: any[]): boolean { for (const arg of args) { - if (!(arg instanceof TypedValue)) { + if (!(arg.belongsToTypesystem)) { return false; } } diff --git a/src/transactionIntentsFactories/transactionIntentBuilder.ts b/src/transactionIntentsFactories/transactionIntentBuilder.ts index ffa1f42bb..c294f6d2f 100644 --- a/src/transactionIntentsFactories/transactionIntentBuilder.ts +++ b/src/transactionIntentsFactories/transactionIntentBuilder.ts @@ -17,18 +17,25 @@ export class TransactionIntentBuilder { private executionGasLimit: BigNumber.Value; private value?: BigNumber.Value; - constructor(config: Config, sender: IAddress, receiver: IAddress, dataParts: string[], executionGasLimit: BigNumber.Value, value?: BigNumber.Value) { - this.config = config; - this.sender = sender; - this.receiver = receiver; - this.dataParts = dataParts; - this.executionGasLimit = executionGasLimit; - this.value = value; + constructor(options: { + config: Config, + sender: IAddress, + receiver: IAddress, + dataParts: string[], + executionGasLimit: BigNumber.Value, + value?: BigNumber.Value + }) { + this.config = options.config; + this.sender = options.sender; + this.receiver = options.receiver; + this.dataParts = options.dataParts; + this.executionGasLimit = options.executionGasLimit; + this.value = options.value; } private computeGasLimit(payload: ITransactionPayload, executionGasLimit: BigNumber.Value): BigNumber.Value { - const dataMovementGas = new BigNumber(this.config.minGasLimit).plus(new BigNumber(this.config.gasLimitPerByte).multipliedBy(new BigNumber(payload.length()))); - const gasLimit = new BigNumber(dataMovementGas).plus(new BigNumber(executionGasLimit)); + const dataMovementGas = new BigNumber(this.config.minGasLimit).plus(new BigNumber(this.config.gasLimitPerByte).multipliedBy(payload.length())); + const gasLimit = dataMovementGas.plus(executionGasLimit); return gasLimit; } @@ -41,12 +48,12 @@ export class TransactionIntentBuilder { const data = this.buildTransactionPayload() const gasLimit = this.computeGasLimit(data, this.executionGasLimit); - return new TransactionIntent( - this.sender.bech32(), - this.receiver.bech32(), - gasLimit, - this.value !== undefined ? this.value : 0, - data.valueOf() - ) + return new TransactionIntent({ + sender: this.sender.bech32(), + receiver: this.receiver.bech32(), + gasLimit: gasLimit, + value: this.value || 0, + data: data.valueOf() + }) } } diff --git a/src/utils.codec.spec.ts b/src/utils.codec.spec.ts index 1ab1660ba..ba38f632c 100644 --- a/src/utils.codec.spec.ts +++ b/src/utils.codec.spec.ts @@ -1,5 +1,5 @@ import { assert } from "chai"; -import { isPaddedHex, numberToPaddedHex, zeroPadStringIfOddLength } from "./utils.codec"; +import { isPaddedHex, numberToPaddedHex, zeroPadStringIfOddLength, byteArrayToHex, utf8ToHex } from "./utils.codec"; describe("test codec utils", () => { it("should convert numberToPaddedHex", () => { @@ -21,4 +21,18 @@ describe("test codec utils", () => { assert.equal(zeroPadStringIfOddLength("1"), "01"); assert.equal(zeroPadStringIfOddLength("01"), "01"); }); + + it("should convert byteArrayToHex", () => { + const firstArray = new Uint8Array([0x05, 0x00]); + const secondArray = new Uint8Array([0x7]); + + assert.equal(byteArrayToHex(firstArray), "0500"); + assert.equal(byteArrayToHex(secondArray), "07"); + }); + + it("should convert utf8ToHex", () => { + assert.equal(utf8ToHex("stringandnumber7"), "737472696e67616e646e756d62657237"); + assert.equal(utf8ToHex("somestring"), "736f6d65737472696e67"); + assert.equal(utf8ToHex("aaa"), "616161"); + }); }); From 08dd376001cdbbd533d310ba4b0920f8dd5426f7 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Fri, 8 Sep 2023 10:55:46 +0300 Subject: [PATCH 6/6] small fixes for tests --- ...artContractTransactionIntentsFactory.spec.ts | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.spec.ts b/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.spec.ts index c2a8513c6..75d65332f 100644 --- a/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.spec.ts +++ b/src/transactionIntentsFactories/smartContractTransactionIntentsFactory.spec.ts @@ -73,12 +73,10 @@ describe("test smart contract intents factory", function () { assert.equal(deployIntent.sender, "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); assert.equal(deployIntent.receiver, CONTRACT_DEPLOY_ADDRESS); assert.isDefined(deployIntent.data); - expect(deployIntent.data?.length).to.be.greaterThan(0); + expect(deployIntent.data!.length).to.be.greaterThan(0); - if (deployIntent.data) { - const expectedGasLimit = 6000000 + 50000 + 1500 * deployIntent.data.length; - assert.equal(deployIntent.gasLimit.valueOf(), expectedGasLimit); - } + const expectedGasLimit = 6000000 + 50000 + 1500 * deployIntent.data!.length; + assert.equal(deployIntent.gasLimit.valueOf(), expectedGasLimit); assert.equal(deployIntent.value, 0); assert.deepEqual(deployIntent, abiDeployIntent); @@ -142,13 +140,10 @@ describe("test smart contract intents factory", function () { assert.equal(deployIntent.sender, "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); assert.equal(deployIntent.receiver, "erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4"); assert.isDefined(deployIntent.data); + assert(checkIfByteArrayStartsWith(deployIntent.data!, "upgradeContract@")); - if (deployIntent.data) { - assert(checkIfByteArrayStartsWith(deployIntent.data, "upgradeContract@")); - - const expectedGasLimit = 6000000 + 50000 + 1500 * deployIntent.data.length; - assert.equal(deployIntent.gasLimit.valueOf(), expectedGasLimit); - } + const expectedGasLimit = 6000000 + 50000 + 1500 * deployIntent.data!.length; + assert.equal(deployIntent.gasLimit.valueOf(), expectedGasLimit); assert.equal(deployIntent.value, 0); assert.deepEqual(deployIntent, abiDeployIntent);