diff --git a/src/abi/interaction.local.net.spec.ts b/src/abi/interaction.local.net.spec.ts index 2f1c286af..2a2487688 100644 --- a/src/abi/interaction.local.net.spec.ts +++ b/src/abi/interaction.local.net.spec.ts @@ -3,13 +3,13 @@ import { assert } from "chai"; import { promises } from "fs"; import { QueryRunnerAdapter } from "../adapters/queryRunnerAdapter"; import { SmartContractQueriesController } from "../smartContractQueriesController"; +import { SmartContractTransactionsFactory } from "../smartContracts"; import { loadAbiRegistry, loadTestWallets, prepareDeployment, TestWallet } from "../testutils"; import { ContractController } from "../testutils/contractController"; import { createLocalnetProvider } from "../testutils/networkProviders"; import { Transaction } from "../transaction"; import { TransactionComputer } from "../transactionComputer"; import { TransactionsFactoryConfig } from "../transactionsFactories"; -import { SmartContractTransactionsFactory } from "../transactionsFactories/smartContractTransactionsFactory"; import { TransactionWatcher } from "../transactionWatcher"; import { Interaction } from "./interaction"; import { ResultsParser } from "./resultsParser"; @@ -102,8 +102,7 @@ describe("test smart contract interactor", function () { const bytecode = await promises.readFile("src/testdata/answer.wasm"); - const deployTransaction = factory.createTransactionForDeploy({ - sender: alice.address, + const deployTransaction = factory.createTransactionForDeploy(alice.address, { bytecode: bytecode, gasLimit: 3000000n, }); @@ -144,8 +143,7 @@ describe("test smart contract interactor", function () { assert.deepEqual(parsed[0], new BigNumber(42)); // Query - let transaction = factory.createTransactionForExecute({ - sender: alice.address, + let transaction = factory.createTransactionForExecute(alice.address, { contract: contractAddress, function: "getUltimateAnswer", gasLimit: 3000000n, @@ -160,8 +158,7 @@ describe("test smart contract interactor", function () { await provider.sendTransaction(transaction); // Execute, and wait for execution - transaction = factory.createTransactionForExecute({ - sender: alice.address, + transaction = factory.createTransactionForExecute(alice.address, { contract: contractAddress, function: "getUltimateAnswer", gasLimit: 3000000n, @@ -393,8 +390,7 @@ describe("test smart contract interactor", function () { const bytecode = await promises.readFile("src/testdata/counter.wasm"); - const deployTransaction = factory.createTransactionForDeploy({ - sender: alice.address, + const deployTransaction = factory.createTransactionForDeploy(alice.address, { bytecode: bytecode, gasLimit: 3000000n, }); @@ -422,8 +418,7 @@ describe("test smart contract interactor", function () { const queryRunner = new QueryRunnerAdapter({ networkProvider: provider }); const queryController = new SmartContractQueriesController({ abi: abiRegistry, queryRunner: queryRunner }); - let incrementTransaction = factory.createTransactionForExecute({ - sender: alice.address, + let incrementTransaction = factory.createTransactionForExecute(alice.address, { contract: contractAddress, function: "increment", gasLimit: 3000000n, @@ -451,8 +446,7 @@ describe("test smart contract interactor", function () { let typedBundle = resultsParser.parseOutcome(transactionOnNetwork, abiRegistry.getEndpoint("increment")); assert.deepEqual(typedBundle.firstValue!.valueOf(), new BigNumber(2)); - let decrementTransaction = factory.createTransactionForExecute({ - sender: alice.address, + let decrementTransaction = factory.createTransactionForExecute(alice.address, { contract: contractAddress, function: "decrement", gasLimit: 3000000n, @@ -590,8 +584,7 @@ describe("test smart contract interactor", function () { const bytecode = await promises.readFile("src/testdata/lottery-esdt.wasm"); // Deploy the contract - const deployTransaction = factory.createTransactionForDeploy({ - sender: alice.address, + const deployTransaction = factory.createTransactionForDeploy(alice.address, { bytecode: bytecode, gasLimit: 100000000n, }); @@ -617,8 +610,7 @@ describe("test smart contract interactor", function () { assert.isTrue(untypedBundle.returnCode.isSuccess()); // start() - let startTransaction = factory.createTransactionForExecute({ - sender: alice.address, + let startTransaction = factory.createTransactionForExecute(alice.address, { contract: contractAddress, function: "start", arguments: ["lucky", "EGLD", 1, null, null, 1, null, null], @@ -638,8 +630,7 @@ describe("test smart contract interactor", function () { assert.lengthOf(typedBundle.values, 0); // status() - let lotteryStatusTransaction = factory.createTransactionForExecute({ - sender: alice.address, + let lotteryStatusTransaction = factory.createTransactionForExecute(alice.address, { contract: contractAddress, function: "status", arguments: ["lucky"], @@ -660,8 +651,7 @@ describe("test smart contract interactor", function () { assert.equal(typedBundle.firstValue!.valueOf().name, "Running"); // getlotteryInfo() (this is a view function, but for the sake of the test, we'll execute it) - let lotteryInfoTransaction = factory.createTransactionForExecute({ - sender: alice.address, + let lotteryInfoTransaction = factory.createTransactionForExecute(alice.address, { contract: contractAddress, function: "getLotteryInfo", arguments: ["lucky"], diff --git a/src/abi/interaction.ts b/src/abi/interaction.ts index e1bedc5f4..8519308d7 100644 --- a/src/abi/interaction.ts +++ b/src/abi/interaction.ts @@ -3,9 +3,10 @@ import { Address } from "../address"; import { Compatibility } from "../compatibility"; import { TRANSACTION_VERSION_DEFAULT } from "../constants"; import { IAddress, IChainID, IGasLimit, IGasPrice, INonce, ITokenTransfer, ITransactionValue } from "../interface"; +import { SmartContractTransactionsFactory } from "../smartContracts"; import { TokenTransfer } from "../tokens"; import { Transaction } from "../transaction"; -import { SmartContractTransactionsFactory, TransactionsFactoryConfig } from "../transactionsFactories"; +import { TransactionsFactoryConfig } from "../transactionsFactories"; import { ContractFunction } from "./function"; import { InteractionChecker } from "./interactionChecker"; import { CallArguments } from "./interface"; @@ -17,7 +18,7 @@ import { EndpointDefinition, TypedValue } from "./typesystem"; */ interface ISmartContractWithinInteraction { call({ func, args, value, gasLimit, receiver }: CallArguments): Transaction; - getAddress(): IAddress; + getAddress(): Address; getEndpoint(name: ContractFunction): EndpointDefinition; } @@ -41,7 +42,7 @@ export class Interaction { private chainID: IChainID = ""; private querent: IAddress = Address.empty(); private explicitReceiver?: IAddress; - private sender: IAddress = Address.empty(); + private sender: Address = Address.empty(); private version: number = TRANSACTION_VERSION_DEFAULT; private tokenTransfers: TokenTransfer[]; @@ -97,8 +98,7 @@ export class Interaction { config: factoryConfig, }); - const transaction = factory.createTransactionForExecute({ - sender: this.sender, + const transaction = factory.createTransactionForExecute(this.sender, { contract: this.contract.getAddress(), function: this.function.valueOf(), gasLimit: BigInt(this.gasLimit.valueOf()), @@ -173,7 +173,7 @@ export class Interaction { return this; } - withSender(sender: IAddress): Interaction { + withSender(sender: Address): Interaction { this.sender = sender; return this; } diff --git a/src/abi/interface.ts b/src/abi/interface.ts index b474ad8ed..e51c5b70b 100644 --- a/src/abi/interface.ts +++ b/src/abi/interface.ts @@ -1,4 +1,5 @@ -import { IAddress, IChainID, IGasLimit, IGasPrice, ITransactionValue } from "../interface"; +import { Address } from "../address"; +import { IChainID, IGasLimit, IGasPrice, ITransactionValue } from "../interface"; import { Transaction } from "../transaction"; import { ReturnCode } from "./returnCode"; import { TypedValue } from "./typesystem"; @@ -10,7 +11,7 @@ export interface ISmartContract { /** * Gets the address of the Smart Contract. */ - getAddress(): IAddress; + getAddress(): Address; /** * Creates a {@link Transaction} for deploying the Smart Contract to the Network. @@ -36,7 +37,7 @@ export interface DeployArguments { gasLimit: IGasLimit; gasPrice?: IGasPrice; chainID: IChainID; - deployer: IAddress; + deployer: Address; } export interface UpgradeArguments { @@ -47,7 +48,7 @@ export interface UpgradeArguments { gasLimit: IGasLimit; gasPrice?: IGasPrice; chainID: IChainID; - caller: IAddress; + caller: Address; } export interface CallArguments { @@ -55,17 +56,17 @@ export interface CallArguments { args?: any[]; value?: ITransactionValue; gasLimit: IGasLimit; - receiver?: IAddress; + receiver?: Address; gasPrice?: IGasPrice; chainID: IChainID; - caller: IAddress; + caller: Address; } export interface QueryArguments { func: IContractFunction; args?: TypedValue[]; value?: ITransactionValue; - caller?: IAddress; + caller?: Address; } export interface TypedOutcomeBundle { diff --git a/src/abi/smartContract.local.net.spec.ts b/src/abi/smartContract.local.net.spec.ts index 57c5646f8..818cc0349 100644 --- a/src/abi/smartContract.local.net.spec.ts +++ b/src/abi/smartContract.local.net.spec.ts @@ -3,12 +3,12 @@ import { promises } from "fs"; import { QueryRunnerAdapter } from "../adapters/queryRunnerAdapter"; import { Logger } from "../logger"; import { SmartContractQueriesController } from "../smartContractQueriesController"; +import { SmartContractTransactionsFactory } from "../smartContracts"; import { prepareDeployment } from "../testutils"; import { createLocalnetProvider } from "../testutils/networkProviders"; import { loadTestWallets, TestWallet } from "../testutils/wallets"; import { TransactionComputer } from "../transactionComputer"; import { TransactionsFactoryConfig } from "../transactionsFactories"; -import { SmartContractTransactionsFactory } from "../transactionsFactories/smartContractTransactionsFactory"; import { TransactionWatcher } from "../transactionWatcher"; import { decodeUnsignedNumber } from "./codec"; import { ContractFunction } from "./function"; @@ -129,8 +129,7 @@ describe("test on local testnet", function () { const bytecode = await promises.readFile("src/testdata/counter.wasm"); - const deployTransaction = factory.createTransactionForDeploy({ - sender: alice.address, + const deployTransaction = factory.createTransactionForDeploy(alice.address, { bytecode: bytecode, gasLimit: 3000000n, }); @@ -144,8 +143,7 @@ describe("test on local testnet", function () { const contractAddress = SmartContract.computeAddress(alice.address, alice.account.nonce); alice.account.incrementNonce(); - const smartContractCallTransaction = factory.createTransactionForExecute({ - sender: alice.address, + const smartContractCallTransaction = factory.createTransactionForExecute(alice.address, { contract: contractAddress, function: "increment", gasLimit: 3000000n, @@ -157,8 +155,7 @@ describe("test on local testnet", function () { alice.account.incrementNonce(); - const simulateOne = factory.createTransactionForExecute({ - sender: alice.address, + const simulateOne = factory.createTransactionForExecute(alice.address, { function: "increment", contract: contractAddress, gasLimit: 100000n, @@ -171,8 +168,7 @@ describe("test on local testnet", function () { alice.account.incrementNonce(); - const simulateTwo = factory.createTransactionForExecute({ - sender: alice.address, + const simulateTwo = factory.createTransactionForExecute(alice.address, { function: "foobar", contract: contractAddress, gasLimit: 500000n, @@ -283,8 +279,7 @@ describe("test on local testnet", function () { const bytecode = await promises.readFile("src/testdata/counter.wasm"); - const deployTransaction = factory.createTransactionForDeploy({ - sender: alice.address, + const deployTransaction = factory.createTransactionForDeploy(alice.address, { bytecode: bytecode, gasLimit: 3000000n, }); @@ -298,8 +293,7 @@ describe("test on local testnet", function () { const contractAddress = SmartContract.computeAddress(alice.address, alice.account.nonce); alice.account.incrementNonce(); - const firstScCallTransaction = factory.createTransactionForExecute({ - sender: alice.address, + const firstScCallTransaction = factory.createTransactionForExecute(alice.address, { contract: contractAddress, function: "increment", gasLimit: 3000000n, @@ -311,8 +305,7 @@ describe("test on local testnet", function () { alice.account.incrementNonce(); - const secondScCallTransaction = factory.createTransactionForExecute({ - sender: alice.address, + const secondScCallTransaction = factory.createTransactionForExecute(alice.address, { contract: contractAddress, function: "increment", gasLimit: 3000000n, @@ -449,8 +442,7 @@ describe("test on local testnet", function () { const bytecode = await promises.readFile("src/testdata/erc20.wasm"); - const deployTransaction = factory.createTransactionForDeploy({ - sender: alice.address, + const deployTransaction = factory.createTransactionForDeploy(alice.address, { bytecode: bytecode, gasLimit: 50000000n, arguments: [new U32Value(10000)], @@ -464,8 +456,7 @@ describe("test on local testnet", function () { const contractAddress = SmartContract.computeAddress(alice.address, alice.account.nonce); alice.account.incrementNonce(); - const transactionMintBob = factory.createTransactionForExecute({ - sender: alice.address, + const transactionMintBob = factory.createTransactionForExecute(alice.address, { contract: contractAddress, function: "transferToken", gasLimit: 9000000n, @@ -478,8 +469,7 @@ describe("test on local testnet", function () { alice.account.incrementNonce(); - const transactionMintCarol = factory.createTransactionForExecute({ - sender: alice.address, + const transactionMintCarol = factory.createTransactionForExecute(alice.address, { contract: contractAddress, function: "transferToken", gasLimit: 9000000n, @@ -629,8 +619,7 @@ describe("test on local testnet", function () { const bytecode = await promises.readFile("src/testdata/lottery-esdt.wasm"); - const deployTransaction = factory.createTransactionForDeploy({ - sender: alice.address, + const deployTransaction = factory.createTransactionForDeploy(alice.address, { bytecode: bytecode, gasLimit: 50000000n, }); @@ -644,8 +633,7 @@ describe("test on local testnet", function () { const contractAddress = SmartContract.computeAddress(alice.address, alice.account.nonce); alice.account.incrementNonce(); - const startTransaction = factory.createTransactionForExecute({ - sender: alice.address, + const startTransaction = factory.createTransactionForExecute(alice.address, { contract: contractAddress, function: "start", gasLimit: 10000000n, diff --git a/src/abi/smartContract.ts b/src/abi/smartContract.ts index b06b7a5a5..ff8122bf4 100644 --- a/src/abi/smartContract.ts +++ b/src/abi/smartContract.ts @@ -2,11 +2,11 @@ import { Address, AddressComputer } from "../address"; import { Compatibility } from "../compatibility"; import { TRANSACTION_MIN_GAS_PRICE } from "../constants"; import { ErrContractHasNoAddress } from "../errors"; -import { IAddress, INonce } from "../interface"; +import { INonce } from "../interface"; import { Transaction } from "../transaction"; -import { SmartContractTransactionsFactory } from "../transactionsFactories/smartContractTransactionsFactory"; import { TransactionsFactoryConfig } from "../transactionsFactories/transactionsFactoryConfig"; import { guardValueIsSet } from "../utils"; +import { SmartContractTransactionsFactory } from "./../smartContracts/smartContractTransactionsFactory"; import { CodeMetadata } from "./codeMetadata"; import { ContractFunction } from "./function"; import { Interaction } from "./interaction"; @@ -33,7 +33,7 @@ interface IAbi { * An abstraction for deploying and interacting with Smart Contracts. */ export class SmartContract implements ISmartContract { - private address: IAddress = Address.empty(); + private address: Address = Address.empty(); private abi?: IAbi; /** @@ -54,7 +54,7 @@ export class SmartContract implements ISmartContract { /** * Create a SmartContract object by providing its address on the Network. */ - constructor(options: { address?: IAddress; abi?: IAbi } = {}) { + constructor(options: { address?: Address; abi?: IAbi } = {}) { this.address = options.address || Address.empty(); this.abi = options.abi; @@ -93,14 +93,14 @@ export class SmartContract implements ISmartContract { /** * Sets the address, as on Network. */ - setAddress(address: IAddress) { + setAddress(address: Address) { this.address = address; } /** * Gets the address, as on Network. */ - getAddress(): IAddress { + getAddress(): Address { return this.address; } @@ -141,11 +141,10 @@ export class SmartContract implements ISmartContract { const bytecode = Buffer.from(code.toString(), "hex"); const metadataAsJson = this.getMetadataPropertiesAsObject(codeMetadata); - const transaction = factory.createTransactionForDeploy({ - sender: deployer, + const transaction = factory.createTransactionForDeploy(deployer, { bytecode: bytecode, gasLimit: BigInt(gasLimit.valueOf()), - arguments: initArguments, + arguments: initArguments ?? [], isUpgradeable: metadataAsJson.upgradeable, isReadable: metadataAsJson.readable, isPayable: metadataAsJson.payable, @@ -211,12 +210,11 @@ export class SmartContract implements ISmartContract { const bytecode = Uint8Array.from(Buffer.from(code.toString(), "hex")); const metadataAsJson = this.getMetadataPropertiesAsObject(codeMetadata); - const transaction = factory.createTransactionForUpgrade({ - sender: caller, + const transaction = factory.createTransactionForUpgrade(caller, { contract: this.getAddress(), bytecode: bytecode, gasLimit: BigInt(gasLimit.valueOf()), - arguments: initArguments, + arguments: initArguments ?? [], isUpgradeable: metadataAsJson.upgradeable, isReadable: metadataAsJson.readable, isPayable: metadataAsJson.payable, @@ -251,8 +249,7 @@ export class SmartContract implements ISmartContract { args = args || []; value = value || 0; - const transaction = factory.createTransactionForExecute({ - sender: caller, + const transaction = factory.createTransactionForExecute(caller, { contract: receiver ? receiver : this.getAddress(), function: func.toString(), gasLimit: BigInt(gasLimit.valueOf()), @@ -291,7 +288,7 @@ export class SmartContract implements ISmartContract { * @param owner The owner of the Smart Contract * @param nonce The owner nonce used for the deployment transaction */ - static computeAddress(owner: IAddress, nonce: INonce): IAddress { + static computeAddress(owner: Address, nonce: INonce): Address { const deployer = Address.fromBech32(owner.bech32()); const addressComputer = new AddressComputer(); return addressComputer.computeContractAddress(deployer, BigInt(nonce.valueOf())); diff --git a/src/abi/smartContractResults.local.net.spec.ts b/src/abi/smartContractResults.local.net.spec.ts index 1ad837676..850bd9a35 100644 --- a/src/abi/smartContractResults.local.net.spec.ts +++ b/src/abi/smartContractResults.local.net.spec.ts @@ -1,14 +1,14 @@ import { assert } from "chai"; +import { promises } from "fs"; +import { SmartContractTransactionsFactory } from "../smartContracts"; import { loadTestWallets, prepareDeployment, TestWallet } from "../testutils"; import { createLocalnetProvider } from "../testutils/networkProviders"; +import { TransactionComputer } from "../transactionComputer"; +import { TransactionsFactoryConfig } from "../transactionsFactories/transactionsFactoryConfig"; import { TransactionWatcher } from "../transactionWatcher"; import { ContractFunction } from "./function"; import { ResultsParser } from "./resultsParser"; import { SmartContract } from "./smartContract"; -import { TransactionsFactoryConfig } from "../transactionsFactories/transactionsFactoryConfig"; -import { SmartContractTransactionsFactory } from "../transactionsFactories/smartContractTransactionsFactory"; -import { promises } from "fs"; -import { TransactionComputer } from "../transactionComputer"; describe("fetch transactions from local testnet", function () { let alice: TestWallet; @@ -91,8 +91,7 @@ describe("fetch transactions from local testnet", function () { const bytecode = await promises.readFile("src/testdata/counter.wasm"); - const deployTransaction = factory.createTransactionForDeploy({ - sender: alice.address, + const deployTransaction = factory.createTransactionForDeploy(alice.address, { bytecode: bytecode, gasLimit: 3000000n, }); @@ -106,8 +105,7 @@ describe("fetch transactions from local testnet", function () { const contractAddress = SmartContract.computeAddress(alice.address, alice.account.nonce); alice.account.incrementNonce(); - const smartContractCallTransaction = factory.createTransactionForExecute({ - sender: alice.address, + const smartContractCallTransaction = factory.createTransactionForExecute(alice.address, { contract: contractAddress, function: "increment", gasLimit: 3000000n, diff --git a/src/smartContracts/index.ts b/src/smartContracts/index.ts new file mode 100644 index 000000000..29233d303 --- /dev/null +++ b/src/smartContracts/index.ts @@ -0,0 +1,3 @@ +export * from "./smartContractController"; +export * from "./smartContractTransactionsFactory"; +export * from "./smartContractTransactionsOutcomeParser"; diff --git a/src/smartContracts/resources.ts b/src/smartContracts/resources.ts new file mode 100644 index 000000000..78285aad8 --- /dev/null +++ b/src/smartContracts/resources.ts @@ -0,0 +1,46 @@ +import { Address } from "../address"; +import { TokenTransfer } from "../tokens"; + +export type ContractDeployInput = { + bytecode: Uint8Array; + gasLimit: bigint; + arguments?: any[]; + nativeTransferAmount?: bigint; + isUpgradeable?: boolean; + isReadable?: boolean; + isPayable?: boolean; + isPayableBySmartContract?: boolean; +}; + +export type ContractExecuteInput = { + contract: Address; + gasLimit: bigint; + function: string; + arguments?: any[]; + nativeTransferAmount?: bigint; + tokenTransfers?: TokenTransfer[]; +}; + +export type ContractUpgradeInput = ContractDeployInput & { contract: Address }; + +export interface SmartContractDeployOutcome { + returnCode: string; + returnMessage: string; + contracts: DeployedSmartContract[]; +} + +export class DeployedSmartContract { + address: string; + ownerAddress: string; + codeHash: Uint8Array; + + constructor(address: string, ownerAddress: string, codeHash: Uint8Array) { + this.address = address; + this.ownerAddress = ownerAddress; + this.codeHash = codeHash; + } + + toString(): string { + return `DeployedSmartContract(address=${this.address}, ownerAddress=${this.ownerAddress}, codeHash=${Buffer.from(this.codeHash).toString("hex")})`; + } +} diff --git a/src/smartContracts/smartContractController.ts b/src/smartContracts/smartContractController.ts new file mode 100644 index 000000000..8c4fb1790 --- /dev/null +++ b/src/smartContracts/smartContractController.ts @@ -0,0 +1,95 @@ +import { AbiRegistry } from "../abi"; +import { IAccount } from "../accounts/interfaces"; +import { QueryRunnerAdapter } from "../adapters"; +import { IAddress } from "../interface"; +import { ITransactionOnNetwork } from "../interfaceOfNetwork"; +import { INetworkProvider } from "../networkProviders/interface"; +import { SmartContractQueriesController } from "../smartContractQueriesController"; +import { Transaction } from "../transaction"; +import { TransactionComputer } from "../transactionComputer"; +import { TransactionsFactoryConfig } from "../transactionsFactories"; +import { SmartContractTransactionsOutcomeParser } from "../transactionsOutcomeParsers"; +import { TransactionWatcher } from "../transactionWatcher"; +import * as resources from "./resources"; +import { SmartContractTransactionsFactory } from "./smartContractTransactionsFactory"; + +export class SmartContractController { + private factory: SmartContractTransactionsFactory; + private parser: SmartContractTransactionsOutcomeParser; + private queryController: SmartContractQueriesController; + private transactionWatcher: TransactionWatcher; + private txComputer: TransactionComputer; + + constructor(options: { chainID: string; networkProvider: INetworkProvider; abi?: AbiRegistry }) { + this.factory = new SmartContractTransactionsFactory({ + config: new TransactionsFactoryConfig({ chainID: options.chainID }), + abi: options.abi, + }); + this.parser = new SmartContractTransactionsOutcomeParser(options); + + this.queryController = new SmartContractQueriesController({ + queryRunner: new QueryRunnerAdapter(options), + abi: options.abi, + }); + this.transactionWatcher = new TransactionWatcher(options.networkProvider); + this.txComputer = new TransactionComputer(); + } + + async createTransactionForDeploy( + sender: IAccount, + nonce: bigint, + options: resources.ContractDeployInput, + ): Promise { + const transaction = this.factory.createTransactionForDeploy(sender.address, options); + + transaction.nonce = nonce; + transaction.signature = await sender.sign(this.txComputer.computeBytesForSigning(transaction)); + + return transaction; + } + + async awaitCompletedDeploy(txHash: string): Promise { + const transaction = await this.transactionWatcher.awaitCompleted(txHash); + return this.parseDeploy(transaction); + } + + async createTransactionForUpgrade( + sender: IAccount, + nonce: bigint, + options: resources.ContractUpgradeInput, + ): Promise { + const transaction = this.factory.createTransactionForUpgrade(sender.address, options); + + transaction.nonce = nonce; + transaction.signature = await sender.sign(this.txComputer.computeBytesForSigning(transaction)); + + return transaction; + } + + async createTransactionForExecute( + sender: IAccount, + nonce: bigint, + options: resources.ContractExecuteInput, + ): Promise { + const transaction = this.factory.createTransactionForExecute(sender.address, options); + + transaction.nonce = nonce; + transaction.signature = await sender.sign(this.txComputer.computeBytesForSigning(transaction)); + + return transaction; + } + + queryContract(contract: IAddress, func: string, args: any[], caller?: IAddress, value?: bigint): Promise { + return this.queryController.query({ + contract: contract.bech32(), + function: func, + arguments: args, + caller: caller ? caller.bech32() : undefined, + value: BigInt(value ?? 0), + }); + } + + parseDeploy(transactionOnNetwork: ITransactionOnNetwork): resources.SmartContractDeployOutcome { + return this.parser.parseDeploy({ transactionOnNetwork }); + } +} diff --git a/src/transactionsFactories/smartContractTransactionsFactory.spec.ts b/src/smartContracts/smartContractTransactionsFactory.spec.ts similarity index 94% rename from src/transactionsFactories/smartContractTransactionsFactory.spec.ts rename to src/smartContracts/smartContractTransactionsFactory.spec.ts index 62633f757..b2c88ff97 100644 --- a/src/transactionsFactories/smartContractTransactionsFactory.spec.ts +++ b/src/smartContracts/smartContractTransactionsFactory.spec.ts @@ -4,8 +4,8 @@ import { Address } from "../address"; import { Err } from "../errors"; import { loadAbiRegistry, loadContractCode } from "../testutils/utils"; import { Token, TokenTransfer } from "../tokens"; +import { TransactionsFactoryConfig } from "../transactionsFactories"; import { SmartContractTransactionsFactory } from "./smartContractTransactionsFactory"; -import { TransactionsFactoryConfig } from "./transactionsFactoryConfig"; describe("test smart contract transactions factory", function () { const config = new TransactionsFactoryConfig({ chainID: "D" }); @@ -35,8 +35,7 @@ describe("test smart contract transactions factory", function () { assert.throws( () => - factory.createTransactionForDeploy({ - sender: sender, + factory.createTransactionForDeploy(sender, { bytecode: bytecode.valueOf(), gasLimit: gasLimit, arguments: args, @@ -51,15 +50,13 @@ describe("test smart contract transactions factory", function () { const gasLimit = 6000000n; const args = [new U32Value(1)]; - const transaction = factory.createTransactionForDeploy({ - sender: sender, + const transaction = factory.createTransactionForDeploy(sender, { bytecode: bytecode.valueOf(), gasLimit: gasLimit, arguments: args, }); - const transactionAbiAware = abiAwareFactory.createTransactionForDeploy({ - sender: sender, + const transactionAbiAware = abiAwareFactory.createTransactionForDeploy(sender, { bytecode: bytecode.valueOf(), gasLimit: gasLimit, arguments: args, @@ -81,16 +78,14 @@ describe("test smart contract transactions factory", function () { const gasLimit = 6000000n; const args = [new U32Value(7)]; - const transaction = factory.createTransactionForExecute({ - sender: sender, + const transaction = factory.createTransactionForExecute(sender, { contract: contract, function: func, gasLimit: gasLimit, arguments: args, }); - const transactionAbiAware = abiAwareFactory.createTransactionForExecute({ - sender: sender, + const transactionAbiAware = abiAwareFactory.createTransactionForExecute(sender, { contract: contract, function: func, gasLimit: gasLimit, @@ -113,8 +108,7 @@ describe("test smart contract transactions factory", function () { const gasLimit = 6000000n; const egldAmount = 1000000000000000000n; - const transaction = factory.createTransactionForExecute({ - sender: sender, + const transaction = factory.createTransactionForExecute(sender, { contract: contract, function: func, gasLimit: gasLimit, @@ -122,8 +116,7 @@ describe("test smart contract transactions factory", function () { nativeTransferAmount: egldAmount, }); - const transactionAbiAware = abiAwareFactory.createTransactionForExecute({ - sender: sender, + const transactionAbiAware = abiAwareFactory.createTransactionForExecute(sender, { contract: contract, function: func, gasLimit: gasLimit, @@ -149,8 +142,7 @@ describe("test smart contract transactions factory", function () { const token = new Token({ identifier: "FOO-6ce17b", nonce: 0n }); const transfer = new TokenTransfer({ token, amount: 10n }); - const transaction = factory.createTransactionForExecute({ - sender: sender, + const transaction = factory.createTransactionForExecute(sender, { contract: contract, function: func, gasLimit: gasLimit, @@ -158,8 +150,7 @@ describe("test smart contract transactions factory", function () { tokenTransfers: [transfer], }); - const transactionAbiAware = abiAwareFactory.createTransactionForExecute({ - sender: sender, + const transactionAbiAware = abiAwareFactory.createTransactionForExecute(sender, { contract: contract, function: func, gasLimit: gasLimit, @@ -188,8 +179,7 @@ describe("test smart contract transactions factory", function () { const barToken = new Token({ identifier: "BAR-5bc08f", nonce: 0n }); const barTransfer = new TokenTransfer({ token: barToken, amount: 3140n }); - const transaction = factory.createTransactionForExecute({ - sender: sender, + const transaction = factory.createTransactionForExecute(sender, { contract: contract, function: func, gasLimit: gasLimit, @@ -197,8 +187,7 @@ describe("test smart contract transactions factory", function () { tokenTransfers: [fooTransfer, barTransfer], }); - const transactionAbiAware = abiAwareFactory.createTransactionForExecute({ - sender: sender, + const transactionAbiAware = abiAwareFactory.createTransactionForExecute(sender, { contract: contract, function: func, gasLimit: gasLimit, @@ -232,8 +221,7 @@ describe("test smart contract transactions factory", function () { const token = new Token({ identifier: "NFT-123456", nonce: 1n }); const transfer = new TokenTransfer({ token, amount: 1n }); - const transaction = factory.createTransactionForExecute({ - sender: sender, + const transaction = factory.createTransactionForExecute(sender, { contract: contract, function: func, gasLimit: gasLimit, @@ -241,8 +229,7 @@ describe("test smart contract transactions factory", function () { tokenTransfers: [transfer], }); - const transactionAbiAware = abiAwareFactory.createTransactionForExecute({ - sender: sender, + const transactionAbiAware = abiAwareFactory.createTransactionForExecute(sender, { contract: contract, function: func, gasLimit: gasLimit, @@ -279,8 +266,7 @@ describe("test smart contract transactions factory", function () { const secondToken = new Token({ identifier: "NFT-123456", nonce: 42n }); const secondTransfer = new TokenTransfer({ token: secondToken, amount: 1n }); - const transaction = factory.createTransactionForExecute({ - sender: sender, + const transaction = factory.createTransactionForExecute(sender, { contract: contract, function: func, gasLimit: gasLimit, @@ -288,8 +274,7 @@ describe("test smart contract transactions factory", function () { tokenTransfers: [firstTransfer, secondTransfer], }); - const transactionAbiAware = abiAwareFactory.createTransactionForExecute({ - sender: sender, + const transactionAbiAware = abiAwareFactory.createTransactionForExecute(sender, { contract: contract, function: func, gasLimit: gasLimit, @@ -326,8 +311,7 @@ describe("test smart contract transactions factory", function () { const secondToken = new Token({ identifier: "NFT-123456", nonce: 42n }); const secondTransfer = new TokenTransfer({ token: secondToken, amount: 1n }); - const transaction = factory.createTransactionForExecute({ - sender: sender, + const transaction = factory.createTransactionForExecute(sender, { contract: contract, function: func, gasLimit: gasLimit, @@ -336,8 +320,7 @@ describe("test smart contract transactions factory", function () { tokenTransfers: [firstTransfer, secondTransfer], }); - const transactionAbiAware = abiAwareFactory.createTransactionForExecute({ - sender: sender, + const transactionAbiAware = abiAwareFactory.createTransactionForExecute(sender, { contract: contract, function: func, gasLimit: gasLimit, @@ -369,16 +352,14 @@ describe("test smart contract transactions factory", function () { const gasLimit = 6000000n; const args = [new U32Value(7)]; - const transaction = factory.createTransactionForUpgrade({ - sender: sender, + const transaction = factory.createTransactionForUpgrade(sender, { contract: contract, bytecode: bytecode.valueOf(), gasLimit: gasLimit, arguments: args, }); - const transactionAbiAware = abiAwareFactory.createTransactionForUpgrade({ - sender: sender, + const transactionAbiAware = abiAwareFactory.createTransactionForUpgrade(sender, { contract: contract, bytecode: bytecode.valueOf(), gasLimit: gasLimit, @@ -442,8 +423,7 @@ describe("test smart contract transactions factory", function () { const gasLimit = 6000000n; // By default, use the upgrade constructor. - const tx1 = factory.createTransactionForUpgrade({ - sender: sender, + const tx1 = factory.createTransactionForUpgrade(sender, { contract: receiver, bytecode: bytecode, gasLimit: gasLimit, @@ -455,8 +435,7 @@ describe("test smart contract transactions factory", function () { // Fallback to the "upgrade" endpoint. (abi).upgradeConstructorDefinition = undefined; - const tx2 = factory.createTransactionForUpgrade({ - sender: sender, + const tx2 = factory.createTransactionForUpgrade(sender, { contract: receiver, bytecode: bytecode, gasLimit: gasLimit, @@ -468,8 +447,7 @@ describe("test smart contract transactions factory", function () { // Fallback to the constructor. (abi).endpoints.length = 0; - const tx3 = factory.createTransactionForUpgrade({ - sender: sender, + const tx3 = factory.createTransactionForUpgrade(sender, { contract: receiver, bytecode: bytecode, gasLimit: gasLimit, @@ -483,8 +461,7 @@ describe("test smart contract transactions factory", function () { assert.throws( () => - factory.createTransactionForUpgrade({ - sender: sender, + factory.createTransactionForUpgrade(sender, { contract: receiver, bytecode: bytecode, gasLimit: gasLimit, diff --git a/src/transactionsFactories/smartContractTransactionsFactory.ts b/src/smartContracts/smartContractTransactionsFactory.ts similarity index 82% rename from src/transactionsFactories/smartContractTransactionsFactory.ts rename to src/smartContracts/smartContractTransactionsFactory.ts index dc55129b1..c5731dcc8 100644 --- a/src/transactionsFactories/smartContractTransactionsFactory.ts +++ b/src/smartContracts/smartContractTransactionsFactory.ts @@ -1,14 +1,16 @@ -import { ArgSerializer, CodeMetadata, ContractFunction, EndpointDefinition, isTyped, NativeSerializer } from "../abi"; +import { ArgSerializer, CodeMetadata, ContractFunction, EndpointDefinition } from "../abi"; +import { NativeSerializer } from "../abi/nativeSerializer"; +import { isTyped } from "../abi/typesystem"; import { Address } from "../address"; import { CONTRACT_DEPLOY_ADDRESS_HEX, VM_TYPE_WASM_VM } from "../constants"; import { Err } from "../errors"; -import { IAddress } from "../interface"; import { Logger } from "../logger"; import { TokenComputer, TokenTransfer } from "../tokens"; import { Transaction } from "../transaction"; +import { TokenTransfersDataBuilder } from "../transactionsFactories/tokenTransfersDataBuilder"; +import { TransactionBuilder } from "../transactionsFactories/transactionBuilder"; import { byteArrayToHex, utf8ToHex } from "../utils.codec"; -import { TokenTransfersDataBuilder } from "./tokenTransfersDataBuilder"; -import { TransactionBuilder } from "./transactionBuilder"; +import * as resources from "./resources"; interface IConfig { chainID: string; @@ -44,17 +46,7 @@ export class SmartContractTransactionsFactory { this.contractDeployAddress = Address.fromHex(CONTRACT_DEPLOY_ADDRESS_HEX, this.config.addressHrp); } - createTransactionForDeploy(options: { - sender: IAddress; - bytecode: Uint8Array; - gasLimit: bigint; - arguments?: any[]; - nativeTransferAmount?: bigint; - isUpgradeable?: boolean; - isReadable?: boolean; - isPayable?: boolean; - isPayableBySmartContract?: boolean; - }): Transaction { + createTransactionForDeploy(sender: Address, options: resources.ContractDeployInput): Transaction { const nativeTransferAmount = options.nativeTransferAmount ?? 0n; const isUpgradeable = options.isUpgradeable ?? true; const isReadable = options.isReadable ?? true; @@ -70,7 +62,7 @@ export class SmartContractTransactionsFactory { return new TransactionBuilder({ config: this.config, - sender: options.sender, + sender: sender, receiver: this.contractDeployAddress, dataParts: dataParts, gasLimit: options.gasLimit, @@ -79,15 +71,7 @@ export class SmartContractTransactionsFactory { }).build(); } - createTransactionForExecute(options: { - sender: IAddress; - contract: IAddress; - function: string; - gasLimit: bigint; - arguments?: any[]; - nativeTransferAmount?: bigint; - tokenTransfers?: TokenTransfer[]; - }): Transaction { + createTransactionForExecute(sender: Address, options: resources.ContractExecuteInput): Transaction { const args = options.arguments || []; let tokenTransfers = options.tokenTransfers ? [...options.tokenTransfers] : []; let nativeTransferAmount = options.nativeTransferAmount ?? 0n; @@ -109,22 +93,23 @@ export class SmartContractTransactionsFactory { dataParts = this.dataArgsBuilder.buildDataPartsForESDTTransfer(transfer); } else { dataParts = this.dataArgsBuilder.buildDataPartsForSingleESDTNFTTransfer(transfer, receiver); - receiver = options.sender; + receiver = sender; } } else if (numberOfTokens > 1) { dataParts = this.dataArgsBuilder.buildDataPartsForMultiESDTNFTTransfer(receiver, tokenTransfers); - receiver = options.sender; + receiver = sender; } dataParts.push(dataParts.length ? utf8ToHex(options.function) : options.function); const endpoint = this.abi?.getEndpoint(options.function); + const preparedArgs = this.argsToDataParts(args, endpoint); dataParts.push(...preparedArgs); return new TransactionBuilder({ config: this.config, - sender: options.sender, + sender: sender, receiver: receiver, dataParts: dataParts, gasLimit: options.gasLimit, @@ -133,18 +118,7 @@ export class SmartContractTransactionsFactory { }).build(); } - createTransactionForUpgrade(options: { - sender: IAddress; - contract: IAddress; - bytecode: Uint8Array; - gasLimit: bigint; - arguments?: any[]; - nativeTransferAmount?: bigint; - isUpgradeable?: boolean; - isReadable?: boolean; - isPayable?: boolean; - isPayableBySmartContract?: boolean; - }): Transaction { + createTransactionForUpgrade(sender: Address, options: resources.ContractUpgradeInput): Transaction { const nativeTransferAmount = options.nativeTransferAmount ?? 0n; const isUpgradeable = options.isUpgradeable ?? true; @@ -162,7 +136,7 @@ export class SmartContractTransactionsFactory { return new TransactionBuilder({ config: this.config, - sender: options.sender, + sender: sender, receiver: options.contract, dataParts: dataParts, gasLimit: options.gasLimit, @@ -193,7 +167,7 @@ export class SmartContractTransactionsFactory { } } - createTransactionForClaimingDeveloperRewards(options: { sender: IAddress; contract: IAddress }): Transaction { + createTransactionForClaimingDeveloperRewards(options: { sender: Address; contract: Address }): Transaction { const dataParts = ["ClaimDeveloperRewards"]; return new TransactionBuilder({ @@ -207,9 +181,9 @@ export class SmartContractTransactionsFactory { } createTransactionForChangingOwnerAddress(options: { - sender: IAddress; - contract: IAddress; - newOwner: IAddress; + sender: Address; + contract: Address; + newOwner: Address; }): Transaction { const dataParts = ["ChangeOwnerAddress", Address.fromBech32(options.newOwner.bech32()).toHex()]; diff --git a/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.dev.net.spec.ts b/src/smartContracts/smartContractTransactionsOutcomeParser.dev.net.spec.ts similarity index 100% rename from src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.dev.net.spec.ts rename to src/smartContracts/smartContractTransactionsOutcomeParser.dev.net.spec.ts diff --git a/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.main.net.spec.ts b/src/smartContracts/smartContractTransactionsOutcomeParser.main.net.spec.ts similarity index 100% rename from src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.main.net.spec.ts rename to src/smartContracts/smartContractTransactionsOutcomeParser.main.net.spec.ts diff --git a/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.spec.ts b/src/smartContracts/smartContractTransactionsOutcomeParser.spec.ts similarity index 98% rename from src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.spec.ts rename to src/smartContracts/smartContractTransactionsOutcomeParser.spec.ts index e005f1b39..3e8149269 100644 --- a/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.spec.ts +++ b/src/smartContracts/smartContractTransactionsOutcomeParser.spec.ts @@ -1,17 +1,22 @@ +import BigNumber from "bignumber.js"; +import { assert } from "chai"; +import { Address } from "../address"; +import { TransactionsConverter } from "../converters/transactionsConverter"; import { ContractResultItem, ContractResults, - TransactionEventTopic, - TransactionOnNetwork, TransactionEventOnNetwork, + TransactionEventTopic, TransactionLogsOnNetwork, + TransactionOnNetwork, } from "../networkProviders"; -import BigNumber from "bignumber.js"; -import { assert } from "chai"; -import { Address } from "../address"; -import { TransactionsConverter } from "../converters/transactionsConverter"; import { loadAbiRegistry } from "../testutils"; -import { SmartContractCallOutcome, TransactionEvent, TransactionLogs, TransactionOutcome } from "./resources"; +import { + SmartContractCallOutcome, + TransactionEvent, + TransactionLogs, + TransactionOutcome, +} from "../transactionsOutcomeParsers/resources"; import { SmartContractTransactionsOutcomeParser } from "./smartContractTransactionsOutcomeParser"; describe("test smart contract transactions outcome parser", () => { diff --git a/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.ts b/src/smartContracts/smartContractTransactionsOutcomeParser.ts similarity index 98% rename from src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.ts rename to src/smartContracts/smartContractTransactionsOutcomeParser.ts index f575622bb..5db245c85 100644 --- a/src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.ts +++ b/src/smartContracts/smartContractTransactionsOutcomeParser.ts @@ -3,7 +3,11 @@ import { Address } from "../address"; import { ARGUMENTS_SEPARATOR } from "../constants"; import { Err } from "../errors"; import { IContractResultItem, ITransactionEvent, ITransactionOnNetwork } from "../interfaceOfNetwork"; -import { SmartContractCallOutcome, TransactionOutcome, findEventsByIdentifier } from "./resources"; +import { + SmartContractCallOutcome, + TransactionOutcome, + findEventsByIdentifier, +} from "../transactionsOutcomeParsers/resources"; enum Events { SCDeploy = "SCDeploy", diff --git a/src/transactionsFactories/index.ts b/src/transactionsFactories/index.ts index 39ea35baf..23d727598 100644 --- a/src/transactionsFactories/index.ts +++ b/src/transactionsFactories/index.ts @@ -1,4 +1,3 @@ -export * from "./smartContractTransactionsFactory"; export * from "./tokenManagementTransactionsFactory"; export * from "./transactionsFactoryConfig"; export * from "./transferTransactionsFactory"; diff --git a/src/transactionsOutcomeParsers/index.ts b/src/transactionsOutcomeParsers/index.ts index 8c5a55439..6511796e7 100644 --- a/src/transactionsOutcomeParsers/index.ts +++ b/src/transactionsOutcomeParsers/index.ts @@ -1,4 +1,4 @@ +export * from "../smartContracts/smartContractTransactionsOutcomeParser"; export * from "./resources"; -export * from "./smartContractTransactionsOutcomeParser"; export * from "./tokenManagementTransactionsOutcomeParser"; export * from "./transactionEventsParser";