diff --git a/src/constants.ts b/src/constants.ts index 66d72198..11df29f3 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 3b33abfd..8b9bc598 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 00000000..1740d480 --- /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 8867c889..eb369345 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); +}