From 63d008ebabe769ec8c66f8d44cee32a3be6527a8 Mon Sep 17 00:00:00 2001 From: luizstacio <luizstacio@gmail.com> Date: Thu, 16 Feb 2023 21:45:10 +0100 Subject: [PATCH 01/20] feat: move predicate to work as a wallet --- .../src/templates/contract/factory.hbs | 6 +- .../fixtures/templates/contract/factory.hbs | 6 +- packages/account/LICENSE | 201 +++++++++ packages/account/README.md | 70 +++ packages/account/package.json | 42 ++ .../src/account.test.ts} | 29 +- .../src/account.ts} | 83 +--- packages/account/src/constants.ts | 2 + packages/account/src/index.ts | 1 + packages/account/tsconfig.json | 10 + packages/account/tsup.config.ts | 13 + packages/address/src/utils.ts | 4 +- packages/contract/package.json | 3 +- .../src/contracts/contract-factory.ts | 32 +- .../contract/src/contracts/contract.test.ts | 13 +- packages/contract/src/contracts/contract.ts | 18 +- .../functions/base-invocation-scope.ts | 16 +- packages/contract/src/util.ts | 9 +- packages/fuel-gauge/src/contract.test.ts | 8 +- packages/fuel-gauge/src/doc-examples.test.ts | 8 +- packages/fuel-gauge/src/predicate.test.ts | 412 ++++++++---------- packages/fuels/package.json | 1 + packages/fuels/src/index.ts | 2 + packages/interfaces/src/index.ts | 5 +- packages/predicate/package.json | 11 +- packages/predicate/src/predicate.test.ts | 124 ++++++ packages/predicate/src/predicate.ts | 64 ++- .../predicate/src/utils/getContractRoot.ts | 17 + packages/predicate/src/utils/index.ts | 1 + packages/providers/src/provider.ts | 105 +---- packages/script/package.json | 3 +- packages/script/src/script.test.ts | 8 +- packages/wallet/package.json | 4 +- packages/wallet/src/base-unlocked-wallet.ts | 4 +- packages/wallet/src/index.ts | 1 - packages/wallet/src/transfer.test.ts | 4 +- packages/wallet/src/wallets.ts | 4 +- pnpm-lock.yaml | 41 +- 38 files changed, 864 insertions(+), 521 deletions(-) create mode 100644 packages/account/LICENSE create mode 100644 packages/account/README.md create mode 100644 packages/account/package.json rename packages/{wallet/src/wallet-locked.test.ts => account/src/account.test.ts} (79%) rename packages/{wallet/src/base-locked-wallet.ts => account/src/account.ts} (76%) create mode 100644 packages/account/src/constants.ts create mode 100644 packages/account/src/index.ts create mode 100644 packages/account/tsconfig.json create mode 100644 packages/account/tsup.config.ts create mode 100644 packages/predicate/src/predicate.test.ts create mode 100644 packages/predicate/src/utils/getContractRoot.ts create mode 100644 packages/predicate/src/utils/index.ts diff --git a/packages/abi-typegen/src/templates/contract/factory.hbs b/packages/abi-typegen/src/templates/contract/factory.hbs index 875c66fa2e6..467c7f57694 100644 --- a/packages/abi-typegen/src/templates/contract/factory.hbs +++ b/packages/abi-typegen/src/templates/contract/factory.hbs @@ -1,7 +1,7 @@ {{header}} import { Interface, Contract } from "fuels"; -import type { Provider, BaseWalletLocked, AbstractAddress } from "fuels"; +import type { Provider, Account, AbstractAddress } from "fuels"; import type { {{capitalizedName}}, {{capitalizedName}}Interface } from "../{{capitalizedName}}"; const _abi = {{abiJsonString}} @@ -13,8 +13,8 @@ export class {{capitalizedName}}__factory { } static connect( id: string | AbstractAddress, - walletOrProvider: BaseWalletLocked | Provider + accountOrProvider: Account | Provider ): {{capitalizedName}} { - return new Contract(id, _abi, walletOrProvider) as unknown as {{capitalizedName}} + return new Contract(id, _abi, accountOrProvider) as unknown as {{capitalizedName}} } } diff --git a/packages/abi-typegen/test/fixtures/templates/contract/factory.hbs b/packages/abi-typegen/test/fixtures/templates/contract/factory.hbs index 6dfbc92dc2f..93f9ab616d3 100644 --- a/packages/abi-typegen/test/fixtures/templates/contract/factory.hbs +++ b/packages/abi-typegen/test/fixtures/templates/contract/factory.hbs @@ -10,7 +10,7 @@ */ import { Interface, Contract } from "fuels"; -import type { Provider, BaseWalletLocked, AbstractAddress } from "fuels"; +import type { Provider, Account, AbstractAddress } from "fuels"; import type { MyContractAbi, MyContractAbiInterface } from "../MyContractAbi"; const _abi = { @@ -61,8 +61,8 @@ export class MyContractAbi__factory { } static connect( id: string | AbstractAddress, - walletOrProvider: BaseWalletLocked | Provider + accountOrProvider: Account | Provider ): MyContractAbi { - return new Contract(id, _abi, walletOrProvider) as unknown as MyContractAbi + return new Contract(id, _abi, accountOrProvider) as unknown as MyContractAbi } } diff --git a/packages/account/LICENSE b/packages/account/LICENSE new file mode 100644 index 00000000000..261eeb9e9f8 --- /dev/null +++ b/packages/account/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/account/README.md b/packages/account/README.md new file mode 100644 index 00000000000..de9a28bc1fd --- /dev/null +++ b/packages/account/README.md @@ -0,0 +1,70 @@ +# `@fuel-ts/wallet` + +**@fuel-ts/wallet** is a sub-module for interacting with **Fuel**. + +This module contains the class to manage a private key and signing for a standard Externally Owned Account (EOA) + +# Table of contents + +- [Documentation](#documentation) +- [Usage](#usage) + - [Installation](#installation) + - [Full SDK Installation](#full-sdk-installation) +- [Contributing](#contributing) +- [Changelog](#changelog) +- [License](#license) + +## Documentation + +See [Fuel-ts Documentation](https://fuellabs.github.io/fuels-ts/packages/fuel-ts-wallet/) + +## Usage + +### Installation + +```sh +yarn add @fuel-ts/wallet +# or +npm add @fuel-ts/wallet +``` + +### Full SDK Installation + +Alternatively, we recommend you install the [complete SDK](https://github.com/FuelLabs/fuels-ts) using the umbrella package: + +```sh +yarn add fuels +# or +npm add fuels +``` + +# Test Utilities + +These test utilities are exported to assist in testing apps using Fuels. + +```ts +import { bn } from "@fuel-ts/math"; +import { NativeAssetId } from "@fuel-ts/constants"; +import { seedTestWallet, generateTestWallet } from "@wallet/test-utils"; + +const provider = new Provider("http://127.0.0.1:4000/graphql"); + +// seeding +const wallet = Wallet.fromPrivateKey("0x...", provider); +seedTestWallet(wallet, [{ assetId: NativeAssetId, amount: bn(100_000) }]); + +// generating +const wallet = await generateTestWallet(provider, [[1_000, NativeAssetId]]); +``` + +## Contributing + +In order to contribute to `@fuel-ts/wallet`, please see the main [fuels-ts](https://github.com/FuelLabs/fuels-ts) monorepo. + +## Changelog + +The `@fuel-ts/wallet` changelog can be found at [CHANGELOG](./CHANGELOG.md). + +## License + +The primary license for `@fuel-ts/wallet` is `Apache 2.0`, see [LICENSE](./LICENSE). diff --git a/packages/account/package.json b/packages/account/package.json new file mode 100644 index 00000000000..7200ee8099c --- /dev/null +++ b/packages/account/package.json @@ -0,0 +1,42 @@ +{ + "name": "@fuel-ts/account", + "version": "0.31.0", + "description": "Base Account Class for Fuel", + "author": "Fuel Labs <contact@fuel.sh> (https://fuel.network/)", + "typedoc": { + "entryPoint": "./src/index.ts" + }, + "main": "src/index.ts", + "exports": { + ".": { + "require": "./dist/index.js", + "default": "./dist/index.mjs" + }, + "./test-utils": { + "require": "./dist/test-utils.js", + "default": "./dist/test-utils.mjs" + } + }, + "publishConfig": { + "main": "dist/index.js", + "module": "dist/index.mjs", + "types": "dist/index.d.ts", + "typings": "dist/index.d.ts" + }, + "files": [ + "dist" + ], + "license": "Apache-2.0", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@fuel-ts/address": "workspace:*", + "@fuel-ts/constants": "workspace:*", + "@fuel-ts/interfaces": "workspace:*", + "@fuel-ts/math": "workspace:*", + "@fuel-ts/providers": "workspace:*", + "@fuel-ts/transactions": "workspace:*" + }, + "scripts": { + "build": "tsup --dts" + } +} diff --git a/packages/wallet/src/wallet-locked.test.ts b/packages/account/src/account.test.ts similarity index 79% rename from packages/wallet/src/wallet-locked.test.ts rename to packages/account/src/account.test.ts index 79485a71681..bdb210c975d 100644 --- a/packages/wallet/src/wallet-locked.test.ts +++ b/packages/account/src/account.test.ts @@ -1,28 +1,25 @@ import { bn } from '@fuel-ts/math'; -import { Wallet } from './wallet'; -import type { WalletUnlocked } from './wallets'; +import { Account } from './account'; -describe('WalletLocked', () => { - let wallet: WalletUnlocked; +describe('Account', () => { const assets = [ '0x0101010101010101010101010101010101010101010101010101010101010101', '0x0202020202020202020202020202020202020202020202020202020202020202', '0x0000000000000000000000000000000000000000000000000000000000000000', ]; - beforeAll(() => { - wallet = Wallet.generate(); - }); - it('Create wallet using a address', async () => { - const walletLocked = Wallet.fromAddress(wallet.address); - - expect(walletLocked.address).toEqual(wallet.address); + const walletLocked = new Account( + '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db' + ); + expect(walletLocked.address.toB256()).toEqual( + '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db' + ); }); it('getCoins()', async () => { - const walletLocked = Wallet.fromAddress( + const walletLocked = new Account( '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db' ); const coins = await walletLocked.getCoins(); @@ -36,7 +33,7 @@ describe('WalletLocked', () => { it('getResourcesToSpend()', async () => { // #region typedoc:Message-getResourcesToSpend - const walletLocked = Wallet.fromAddress( + const walletLocked = new Account( '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db' ); const resourcesToSpend = await walletLocked.getResourcesToSpend([ @@ -50,7 +47,7 @@ describe('WalletLocked', () => { }); it('getMessages()', async () => { - const walletLocked = Wallet.fromAddress( + const walletLocked = new Account( '0x69a2b736b60159b43bb8a4f98c0589f6da5fa3a3d101e8e269c499eb942753ba' ); const messages = await walletLocked.getMessages(); @@ -58,7 +55,7 @@ describe('WalletLocked', () => { }); it('getBalance()', async () => { - const walletLocked = Wallet.fromAddress( + const walletLocked = new Account( '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db' ); const balanceA = await walletLocked.getBalance(assets[0]); @@ -68,7 +65,7 @@ describe('WalletLocked', () => { }); it('getBalances()', async () => { - const walletLocked = Wallet.fromAddress( + const walletLocked = new Account( '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db' ); const balances = await walletLocked.getBalances(); diff --git a/packages/wallet/src/base-locked-wallet.ts b/packages/account/src/account.ts similarity index 76% rename from packages/wallet/src/base-locked-wallet.ts rename to packages/account/src/account.ts index 3f60a98b1d8..6994aa4766e 100644 --- a/packages/wallet/src/base-locked-wallet.ts +++ b/packages/account/src/account.ts @@ -1,10 +1,9 @@ import type { BytesLike } from '@ethersproject/bytes'; import { arrayify, hexlify } from '@ethersproject/bytes'; -import type { InputValue } from '@fuel-ts/abi-coder'; import { Address, addressify } from '@fuel-ts/address'; import { NativeAssetId } from '@fuel-ts/constants'; -import { AbstractWallet } from '@fuel-ts/interfaces'; -import type { AbstractAddress, AbstractPredicate } from '@fuel-ts/interfaces'; +import { AbstractAccount } from '@fuel-ts/interfaces'; +import type { AbstractAddress } from '@fuel-ts/interfaces'; import type { BigNumberish, BN } from '@fuel-ts/math'; import { bn } from '@fuel-ts/math'; import type { @@ -15,8 +14,6 @@ import type { Coin, CoinQuantityLike, CoinQuantity, - BuildPredicateOptions, - TransactionResult, Message, Resource, ExcludeResourcesOption, @@ -34,8 +31,8 @@ import { FUEL_NETWORK_URL } from './constants'; /** * BaseWallet */ -export class BaseWalletLocked extends AbstractWallet { - private readonly _address: AbstractAddress; +export class Account extends AbstractAccount { + readonly address: AbstractAddress; provider: Provider; @@ -43,16 +40,12 @@ export class BaseWalletLocked extends AbstractWallet { super(); this.provider = this.connect(provider); if (typeof publicKey === 'string') { - this._address = Address.fromString(publicKey); + this.address = Address.fromString(publicKey); } else { - this._address = addressify(publicKey); + this.address = addressify(publicKey); } } - get address(): AbstractAddress { - return this._address; - } - /** * Change provider connection */ @@ -281,68 +274,4 @@ export class BaseWalletLocked extends AbstractWallet { await this.provider.addMissingVariables(transactionRequest); return this.provider.simulate(transactionRequest); } - - async buildPredicateTransaction( - predicateAddress: AbstractAddress, - amountToPredicate: BigNumberish, - assetId: BytesLike = NativeAssetId, - predicateOptions?: BuildPredicateOptions - ): Promise<ScriptTransactionRequest> { - const options = { - fundTransaction: true, - ...predicateOptions, - }; - const request = new ScriptTransactionRequest({ - gasLimit: MAX_GAS_PER_TX, - ...options, - }); - - // output is locked behind predicate - request.addCoinOutput(predicateAddress, amountToPredicate, assetId); - - const requiredCoinQuantities: CoinQuantityLike[] = []; - if (options.fundTransaction) { - requiredCoinQuantities.push(request.calculateFee()); - } - - if (requiredCoinQuantities.length) { - const resources = await this.getResourcesToSpend(requiredCoinQuantities); - request.addResources(resources); - } - - return request; - } - - async submitPredicate( - predicateAddress: AbstractAddress, - amountToPredicate: BigNumberish, - assetId: BytesLike = NativeAssetId, - options?: BuildPredicateOptions - ): Promise<TransactionResult<'success'>> { - const request = await this.buildPredicateTransaction( - predicateAddress, - amountToPredicate, - assetId, - options - ); - const response = await this.sendTransaction(request); - return response.waitForResult(); - } - - async submitSpendPredicate( - predicate: AbstractPredicate, - amountToSpend: BigNumberish, - predicateData?: InputValue[], - assetId: BytesLike = NativeAssetId, - options?: BuildPredicateOptions - ): Promise<TransactionResult<'success'>> { - return this.provider.submitSpendPredicate( - predicate, - amountToSpend, - this.address, - predicateData, - assetId, - options - ); - } } diff --git a/packages/account/src/constants.ts b/packages/account/src/constants.ts new file mode 100644 index 00000000000..ce37157f9a6 --- /dev/null +++ b/packages/account/src/constants.ts @@ -0,0 +1,2 @@ +// TODO: import using .env file +export const FUEL_NETWORK_URL = 'http://127.0.0.1:4000/graphql'; diff --git a/packages/account/src/index.ts b/packages/account/src/index.ts new file mode 100644 index 00000000000..362a768e537 --- /dev/null +++ b/packages/account/src/index.ts @@ -0,0 +1 @@ +export * from './account'; diff --git a/packages/account/tsconfig.json b/packages/account/tsconfig.json new file mode 100644 index 00000000000..c6f86db2c6b --- /dev/null +++ b/packages/account/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "downlevelIteration": true, + "outDir": "./dist", + "rootDir": "./", + "baseUrl": "./" + }, + "include": ["src", "test"] +} diff --git a/packages/account/tsup.config.ts b/packages/account/tsup.config.ts new file mode 100644 index 00000000000..c140f934706 --- /dev/null +++ b/packages/account/tsup.config.ts @@ -0,0 +1,13 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import { defineConfig } from 'tsup'; + +export default defineConfig((options) => ({ + entry: { + index: 'src/index.ts', + }, + format: ['cjs', 'esm', 'iife'], + splitting: false, + sourcemap: true, + clean: false, + minify: !options.watch, +})); diff --git a/packages/address/src/utils.ts b/packages/address/src/utils.ts index 8cad4b4be1e..ce54f0de503 100644 --- a/packages/address/src/utils.ts +++ b/packages/address/src/utils.ts @@ -1,7 +1,7 @@ import type { BytesLike } from '@ethersproject/bytes'; import { arrayify, hexlify } from '@ethersproject/bytes'; import { Logger } from '@ethersproject/logger'; -import { AbstractContract, AbstractWallet } from '@fuel-ts/interfaces'; +import { AbstractContract, AbstractAccount } from '@fuel-ts/interfaces'; import type { Bech32Address, B256Address, @@ -91,7 +91,7 @@ export function normalizeBech32(address: Bech32Address): Bech32Address { } export const addressify = (addressLike: AddressLike | ContractIdLike): AbstractAddress => { - if (addressLike instanceof AbstractWallet) { + if (addressLike instanceof AbstractAccount) { return addressLike.address; } diff --git a/packages/contract/package.json b/packages/contract/package.json index 535392f110b..866ca5215c7 100644 --- a/packages/contract/package.json +++ b/packages/contract/package.json @@ -41,7 +41,8 @@ "@fuel-ts/sparsemerkle": "workspace:*", "@fuel-ts/wallet": "workspace:*", "@fuel-ts/transactions": "workspace:*", - "@fuel-ts/versions": "workspace:*" + "@fuel-ts/versions": "workspace:*", + "@fuel-ts/account": "workspace:*" }, "devDependencies": { "forc-bin": "workspace:*" diff --git a/packages/contract/src/contracts/contract-factory.ts b/packages/contract/src/contracts/contract-factory.ts index df4a051551b..014f7cc66c7 100644 --- a/packages/contract/src/contracts/contract-factory.ts +++ b/packages/contract/src/contracts/contract-factory.ts @@ -3,13 +3,13 @@ import { arrayify } from '@ethersproject/bytes'; import { Logger } from '@ethersproject/logger'; import { Interface } from '@fuel-ts/abi-coder'; import type { JsonAbi } from '@fuel-ts/abi-coder'; +import type { Account } from '@fuel-ts/account'; import { randomBytes } from '@fuel-ts/keystore'; import type { CreateTransactionRequestLike, Provider } from '@fuel-ts/providers'; import { CreateTransactionRequest } from '@fuel-ts/providers'; import type { StorageSlot } from '@fuel-ts/transactions'; import { MAX_GAS_PER_TX } from '@fuel-ts/transactions'; import { versions } from '@fuel-ts/versions'; -import type { BaseWalletLocked } from '@fuel-ts/wallet'; import { getContractId, getContractStorageRoot, includeHexPrefix } from '../util'; @@ -27,12 +27,12 @@ export default class ContractFactory { bytecode: BytesLike; interface: Interface; provider!: Provider | null; - wallet!: BaseWalletLocked | null; + account!: Account | null; constructor( bytecode: BytesLike, abi: JsonAbi | Interface, - walletOrProvider: BaseWalletLocked | Provider | null = null + accountOrProvider: Account | Provider | null = null ) { // Force the bytecode to be a byte array this.bytecode = arrayify(bytecode); @@ -45,7 +45,7 @@ export default class ContractFactory { /** Instead of using `instanceof` to compare classes, we instead check - if `walletOrProvider` have a `provider` property inside. If yes, + if `accountOrProvider` have a `provider` property inside. If yes, than we assume it's a Wallet. This approach is safer than using `instanceof` because it @@ -56,12 +56,12 @@ export default class ContractFactory { @see Contract */ - if (walletOrProvider && 'provider' in walletOrProvider) { - this.provider = walletOrProvider.provider; - this.wallet = walletOrProvider; + if (accountOrProvider && 'provider' in accountOrProvider) { + this.provider = accountOrProvider.provider; + this.account = accountOrProvider; } else { - this.provider = walletOrProvider; - this.wallet = null; + this.provider = accountOrProvider; + this.account = null; } } @@ -101,19 +101,19 @@ export default class ContractFactory { } async deployContract(deployContractOptions?: DeployContractOptions) { - if (!this.wallet) { + if (!this.account) { return logger.throwArgumentError( - 'Cannot deploy Contract without wallet', - 'wallet', - this.wallet + 'Cannot deploy Contract without account', + 'account', + this.account ); } const { contractId, transactionRequest } = this.createTransactionRequest(deployContractOptions); - await this.wallet.fund(transactionRequest); - const response = await this.wallet.sendTransaction(transactionRequest); + await this.account.fund(transactionRequest); + const response = await this.account.sendTransaction(transactionRequest); await response.wait(); - return new Contract(contractId, this.interface, this.wallet); + return new Contract(contractId, this.interface, this.account); } } diff --git a/packages/contract/src/contracts/contract.test.ts b/packages/contract/src/contracts/contract.test.ts index a8912f75974..44b53553571 100644 --- a/packages/contract/src/contracts/contract.test.ts +++ b/packages/contract/src/contracts/contract.test.ts @@ -1,5 +1,6 @@ +import { Account } from '@fuel-ts/account'; import { Provider } from '@fuel-ts/providers'; -import { BaseWalletLocked, Wallet } from '@fuel-ts/wallet'; +import { Wallet } from '@fuel-ts/wallet'; import Contract from './contract'; @@ -33,25 +34,25 @@ describe('Contract', () => { const provider = new Provider('http://localhost:4000/graphql'); const contract = new Contract(CONTRACT_ID, ABI, provider); expect(contract.provider).toBe(provider); - expect(contract.wallet).toBe(null); + expect(contract.account).toBe(null); }); test('Create contract instance with wallet', async () => { const wallet = Wallet.generate(); const contract = new Contract(CONTRACT_ID, ABI, wallet); expect(contract.provider).toBe(wallet.provider); - expect(contract.wallet).toBe(wallet); + expect(contract.account).toBe(wallet); }); test('Create contract instance with custom wallet', async () => { const generatedWallet = Wallet.generate(); // Create a custom wallet that extends BaseWalletLocked // but without reference to the BaseWalletLocked class - const BaseWalletLockedCustom = Object.assign(BaseWalletLocked); - expect(BaseWalletLockedCustom).not.toBeInstanceOf(BaseWalletLocked); + const BaseWalletLockedCustom = Object.assign(Account); + expect(BaseWalletLockedCustom).not.toBeInstanceOf(Account); const wallet = new BaseWalletLockedCustom(generatedWallet.address); const contract = new Contract(CONTRACT_ID, ABI, wallet); expect(contract.provider).toBe(wallet.provider); - expect(contract.wallet).toBe(wallet); + expect(contract.account).toBe(wallet); }); }); diff --git a/packages/contract/src/contracts/contract.ts b/packages/contract/src/contracts/contract.ts index f158a1cf844..40759de7a66 100644 --- a/packages/contract/src/contracts/contract.ts +++ b/packages/contract/src/contracts/contract.ts @@ -1,10 +1,10 @@ import type { BytesLike } from '@ethersproject/bytes'; import type { FunctionFragment, JsonAbi, JsonFlatAbi } from '@fuel-ts/abi-coder'; import { Interface } from '@fuel-ts/abi-coder'; +import type { Account } from '@fuel-ts/account'; import { Address } from '@fuel-ts/address'; import type { AbstractAddress, AbstractContract } from '@fuel-ts/interfaces'; import type { Provider } from '@fuel-ts/providers'; -import type { BaseWalletLocked } from '@fuel-ts/wallet'; import type { InvokeFunctions } from '../types'; @@ -15,20 +15,20 @@ export default class Contract implements AbstractContract { id!: AbstractAddress; provider!: Provider | null; interface!: Interface; - wallet!: BaseWalletLocked | null; + account!: Account | null; functions: InvokeFunctions = {}; constructor( id: string | AbstractAddress, abi: JsonAbi | JsonFlatAbi | Interface, - walletOrProvider: BaseWalletLocked | Provider + accountOrProvider: Account | Provider ) { this.interface = abi instanceof Interface ? abi : new Interface(abi); this.id = Address.fromAddressOrString(id); /** Instead of using `instanceof` to compare classes, we instead check - if `walletOrProvider` have a `provider` property inside. If yes, + if `accountOrProvider` have a `provider` property inside. If yes, than we assume it's a Wallet. This approach is safer than using `instanceof` because it @@ -39,12 +39,12 @@ export default class Contract implements AbstractContract { @see ContractFactory */ - if (walletOrProvider && 'provider' in walletOrProvider) { - this.provider = walletOrProvider.provider; - this.wallet = walletOrProvider; + if (accountOrProvider && 'provider' in accountOrProvider) { + this.provider = accountOrProvider.provider; + this.account = accountOrProvider; } else { - this.provider = walletOrProvider; - this.wallet = null; + this.provider = accountOrProvider; + this.account = null; } Object.keys(this.interface.functions).forEach((name) => { diff --git a/packages/contract/src/contracts/functions/base-invocation-scope.ts b/packages/contract/src/contracts/functions/base-invocation-scope.ts index aa1623cdf6f..7f7458d0098 100644 --- a/packages/contract/src/contracts/functions/base-invocation-scope.ts +++ b/packages/contract/src/contracts/functions/base-invocation-scope.ts @@ -122,7 +122,7 @@ export class BaseInvocationScope<TReturn = any> { // Add funds required on forwards and to pay gas const opts = BaseInvocationScope.getCallOptions(options); - if (opts.fundTransaction && this.contract.wallet) { + if (opts.fundTransaction && this.contract.account) { await this.fundWithRequiredCoins(); } } @@ -141,7 +141,7 @@ export class BaseInvocationScope<TReturn = any> { * gasUsed, gasPrice and transaction estimate fee in native coins. */ async getTransactionCost(options?: TransactionCostOptions) { - const provider = (this.contract.wallet?.provider || this.contract.provider) as Provider; + const provider = (this.contract.account?.provider || this.contract.provider) as Provider; assert(provider, 'Wallet or Provider is required!'); await this.prepareTransaction(options); @@ -162,7 +162,7 @@ export class BaseInvocationScope<TReturn = any> { this.transactionRequest.inputs = this.transactionRequest.inputs.filter( (i) => i.type !== InputType.Coin ); - const resources = await this.contract.wallet?.getResourcesToSpend(this.requiredCoins); + const resources = await this.contract.account?.getResourcesToSpend(this.requiredCoins); this.transactionRequest.addResources(resources || []); return this; } @@ -208,10 +208,10 @@ export class BaseInvocationScope<TReturn = any> { * running invalid tx and consuming gas try to `simulate` first when possible. */ async call<T = TReturn>(options?: CallOptions): Promise<FunctionInvocationResult<T>> { - assert(this.contract.wallet, 'Wallet is required!'); + assert(this.contract.account, 'Wallet is required!'); const transactionRequest = await this.getTransactionRequest(options); - const response = await this.contract.wallet.sendTransaction(transactionRequest); + const response = await this.contract.account.sendTransaction(transactionRequest); return FunctionInvocationResult.build<T>( this.functionInvocationScopes, @@ -229,10 +229,10 @@ export class BaseInvocationScope<TReturn = any> { * to estimate the amount of gas that will be required to run the transaction. */ async simulate<T = TReturn>(options?: CallOptions): Promise<InvocationCallResult<T>> { - assert(this.contract.wallet, 'Wallet is required!'); + assert(this.contract.account, 'Wallet is required!'); const transactionRequest = await this.getTransactionRequest(options); - const result = await this.contract.wallet.simulateTransaction(transactionRequest); + const result = await this.contract.account.simulateTransaction(transactionRequest); return InvocationCallResult.build<T>(this.functionInvocationScopes, result, this.isMultiCall); } @@ -246,7 +246,7 @@ export class BaseInvocationScope<TReturn = any> { * transaction */ async dryRun<T = TReturn>(options?: CallOptions): Promise<InvocationCallResult<T>> { - const provider = (this.contract.wallet?.provider || this.contract.provider) as Provider; + const provider = (this.contract.account?.provider || this.contract.provider) as Provider; assert(provider, 'Wallet or Provider is required!'); const transactionRequest = await this.getTransactionRequest(options); diff --git a/packages/contract/src/util.ts b/packages/contract/src/util.ts index 5ce9fb800f9..98b5c19512c 100644 --- a/packages/contract/src/util.ts +++ b/packages/contract/src/util.ts @@ -5,14 +5,17 @@ import { calcRoot } from '@fuel-ts/merkle'; import SparseMerkleTree from '@fuel-ts/sparsemerkle'; import type { StorageSlot } from '@fuel-ts/transactions'; -export const getContractRoot = (bytecode: Uint8Array): string => { +export const getContractRoot = (bytecode: BytesLike): string => { const chunkSize = 8; const chunks: Uint8Array[] = []; - for (let offset = 0; offset < bytecode.length; offset += chunkSize) { + const bytes = arrayify(bytecode); + + for (let offset = 0; offset < bytes.length; offset += chunkSize) { const chunk = new Uint8Array(chunkSize); - chunk.set(bytecode.slice(offset, offset + chunkSize)); + chunk.set(bytes.slice(offset, offset + chunkSize)); chunks.push(chunk); } + return calcRoot(chunks.map((c) => hexlify(c))); }; diff --git a/packages/fuel-gauge/src/contract.test.ts b/packages/fuel-gauge/src/contract.test.ts index 6b49d131468..3dc7492908e 100644 --- a/packages/fuel-gauge/src/contract.test.ts +++ b/packages/fuel-gauge/src/contract.test.ts @@ -601,7 +601,7 @@ describe('Contract', () => { const transactionRequestParsed = transactionRequestify(txRequestParsed); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const response = await contract.wallet!.sendTransaction(transactionRequestParsed); + const response = await contract.account!.sendTransaction(transactionRequestParsed); const { value: [resultA, resultB], // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -628,7 +628,7 @@ describe('Contract', () => { const transactionRequestParsed = transactionRequestify(txRequestParsed); - const response = await contract.wallet?.sendTransaction(transactionRequestParsed); + const response = await contract.account?.sendTransaction(transactionRequestParsed); const result = await response?.waitForResult(); expect(result?.status.type).toBe('success'); }); @@ -660,7 +660,7 @@ describe('Contract', () => { // Set custom provider to contract instance const customProvider = new ProviderCustom('http://127.0.0.1:4000/graphql'); - contract.wallet = Wallet.fromAddress(externalWallet.address, customProvider); + contract.account = Wallet.fromAddress(externalWallet.address, customProvider); contract.provider = customProvider; const num = 1337; @@ -676,7 +676,7 @@ describe('Contract', () => { const transactionRequestParsed = transactionRequestify(txRequestParsed); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const response = await contract.wallet!.sendTransaction(transactionRequestParsed); + const response = await contract.account!.sendTransaction(transactionRequestParsed); const { value: [resultA, resultB], transactionResult, diff --git a/packages/fuel-gauge/src/doc-examples.test.ts b/packages/fuel-gauge/src/doc-examples.test.ts index 2c3b0744a30..ba82aba0fa3 100644 --- a/packages/fuel-gauge/src/doc-examples.test.ts +++ b/packages/fuel-gauge/src/doc-examples.test.ts @@ -421,8 +421,8 @@ it.skip('can create a predicate and use', async () => { // #endregion // #region typedoc:Predicate-triple-submit - await wallet1.submitPredicate(predicate.address, 200); - const updatedPredicateBalance = await provider.getBalance(predicate.address, assetId); + await predicate.transfer(predicate.address, 200); + const updatedPredicateBalance = await predicate.getBalance(assetId); // assert that predicate address now has the updated expected amount to predicate expect(bn(updatedPredicateBalance)).toEqual( @@ -440,9 +440,7 @@ it.skip('can create a predicate and use', async () => { // #endregion // #region typedoc:Predicate-triple-spend - await provider.submitSpendPredicate(predicate, updatedPredicateBalance, receiver.address, [ - signatures, - ]); + await predicate.setData(signatures).transfer(receiver.address, updatedPredicateBalance); // check balances const finalPredicateBalance = await provider.getBalance(predicate.address, assetId); diff --git a/packages/fuel-gauge/src/predicate.test.ts b/packages/fuel-gauge/src/predicate.test.ts index 6e4d984b11a..e6f0fc6942e 100644 --- a/packages/fuel-gauge/src/predicate.test.ts +++ b/packages/fuel-gauge/src/predicate.test.ts @@ -1,7 +1,15 @@ import { generateTestWallet } from '@fuel-ts/wallet/test-utils'; import { readFileSync } from 'fs'; -import { Address, NativeAssetId, bn, toHex, toNumber, Provider, Predicate } from 'fuels'; -import type { AbstractAddress, BigNumberish, BN, BaseWalletLocked, BytesLike } from 'fuels'; +import { Address, NativeAssetId, bn, toHex, toNumber, Provider, Predicate, Wallet } from 'fuels'; +import type { + AbstractAddress, + BigNumberish, + BN, + BytesLike, + WalletUnlocked, + InputValue, + WalletLocked, +} from 'fuels'; import { join } from 'path'; import testPredicateAddress from '../test-projects/predicate-address'; @@ -19,43 +27,44 @@ const testPredicateStructBin = readFileSync( const setup = async () => { const provider = new Provider('http://127.0.0.1:4000/graphql'); const wallet = await generateTestWallet(provider, [[5_000_000, NativeAssetId]]); - return wallet; + const receiver = Wallet.fromAddress(Address.fromRandom()); + return [wallet, receiver] as const; }; -const setupPredicate = async ( - wallet: BaseWalletLocked, - amountToPredicate: BigNumberish, - predicate: Predicate +const setupPredicate = async <T extends InputValue[]>( + wallet: WalletUnlocked, + predicate: Predicate<T>, + amountToPredicate: BigNumberish ): Promise<BN> => { - await wallet.submitPredicate(predicate.address, amountToPredicate); - + const tx = await wallet.transfer(predicate.address, amountToPredicate, NativeAssetId); + await tx.waitForResult(); // collect balance from predicate to prevent flaky tests where predicate address gets "filled up" - return wallet.provider.getBalance(predicate.address, NativeAssetId); + return predicate.getBalance(); }; -const assertResults = async ( - wallet: BaseWalletLocked, - receiverAddress: AbstractAddress, +const assertResults = async <T extends InputValue[]>( + predicate: Predicate<T>, + receiver: WalletLocked, initialPredicateBalance: BN, initialReceiverBalance: BN, amountToPredicate: BigNumberish, - predicate: Predicate, - isSkippingInitialReceiverBalance = false + amountToReceiver: BigNumberish + // isSkippingInitialReceiverBalance = false ): Promise<void> => { // Check there are UTXO locked with the predicate hash expect(toNumber(initialPredicateBalance)).toBeGreaterThanOrEqual(toNumber(amountToPredicate)); - !isSkippingInitialReceiverBalance && expect(initialReceiverBalance.toHex()).toEqual(toHex(0)); + // !isSkippingInitialReceiverBalance && expect(initialReceiverBalance.toHex()).toEqual(toHex(0)); + expect(initialReceiverBalance.toHex()).toEqual(toHex(0)); // Check the balance of the receiver - const finalReceiverBalance = await wallet.provider.getBalance(receiverAddress, NativeAssetId); - - expect(bn(initialReceiverBalance).add(initialPredicateBalance).toHex()).toEqual( + const finalReceiverBalance = await receiver.getBalance(); + expect(bn(initialReceiverBalance).add(amountToReceiver).toHex()).toEqual( finalReceiverBalance.toHex() ); // Check we spent the entire predicate hash input - const finalPredicateBalance = await wallet.provider.getBalance(predicate.address, NativeAssetId); - expect(finalPredicateBalance.toHex()).toEqual(toHex(0)); + const finalPredicateBalance = await predicate.getBalance(); + expect(finalPredicateBalance.lte(initialPredicateBalance)).toBeTruthy(); }; type Validation = { @@ -183,314 +192,245 @@ const StructAbiInputs = { describe('Predicate', () => { it('can call a no-arg Predicate that returns true', async () => { - const receiverAddress = Address.fromRandom(); - const wallet = await setup(); - const amountToPredicate = 10; - const predicate = new Predicate(testPredicateTrue); - - const initialPredicateBalance = await setupPredicate(wallet, amountToPredicate, predicate); - const initialReceiverBalance = await wallet.provider.getBalance(receiverAddress, NativeAssetId); - - await wallet.provider.submitSpendPredicate(predicate, initialPredicateBalance, receiverAddress); - - await assertResults( - wallet, - receiverAddress, - initialPredicateBalance, - initialReceiverBalance, - amountToPredicate, - predicate - ); - }); - - it('can call a no-arg Predicate that returns true, via wallet', async () => { - const wallet = await setup(); - const amountToPredicate = 10; + const [wallet, receiver] = await setup(); + const amountToPredicate = 100; + const amountToReceiver = 50; const predicate = new Predicate(testPredicateTrue); - const initialPredicateBalance = await setupPredicate(wallet, amountToPredicate, predicate); - const initialReceiverBalance = await wallet.provider.getBalance(wallet.address, NativeAssetId); + const initialReceiverBalance = await receiver.getBalance(); + const initialPredicateBalance = await setupPredicate(wallet, predicate, amountToPredicate); - await wallet.submitSpendPredicate(predicate, initialPredicateBalance); + const tx = await predicate.transfer(receiver.address, amountToReceiver); + await tx.waitForResult(); await assertResults( - wallet, - wallet.address, + predicate, + receiver, initialPredicateBalance, initialReceiverBalance, amountToPredicate, - predicate, - true + amountToReceiver ); }); - it('can call a no-arg Predicate that returns false, via wallet', async () => { - const wallet = await setup(); - const amountToPredicate = 10; + it('can call a no-arg Predicate that returns false', async () => { + const [wallet, receiver] = await setup(); + const amountToPredicate = 100; + const amountToReceiver = 50; const predicate = new Predicate(testPredicateFalse); - const initialPredicateBalance = await setupPredicate(wallet, amountToPredicate, predicate); + await setupPredicate(wallet, predicate, amountToPredicate); await expect(async () => { - await wallet.submitSpendPredicate(predicate, initialPredicateBalance); + await predicate.transfer(receiver.address, amountToReceiver); }).rejects.toThrow('Invalid transaction'); }); it('can call a Coin predicate which returns true with valid predicate data [address]', async () => { - const receiverAddress = Address.fromRandom(); - const wallet = await setup(); - const amountToPredicate = 10; - const predicate = new Predicate(testPredicateAddress, AddressAbiInputs); - - const initialPredicateBalance = await setupPredicate(wallet, amountToPredicate, predicate); - const initialReceiverBalance = await wallet.provider.getBalance(receiverAddress, NativeAssetId); - - await wallet.provider.submitSpendPredicate( - predicate, - initialPredicateBalance, - receiverAddress, - ['0xef86afa9696cf0dc6385e2c407a6e159a1103cefb7e2ae0636fb33d3cb2a9e4a'] - ); - - await assertResults( - wallet, - receiverAddress, - initialPredicateBalance, - initialReceiverBalance, - amountToPredicate, - predicate - ); - }); - - it('can call a Coin predicate which returns true with valid predicate data [address], via wallet', async () => { - const wallet = await setup(); - const amountToPredicate = 10; - const predicate = new Predicate(testPredicateAddress, AddressAbiInputs); + const [wallet, receiver] = await setup(); + const amountToPredicate = 100; + const amountToReceiver = 50; + const predicate = new Predicate<[string]>(testPredicateAddress, AddressAbiInputs); - const initialPredicateBalance = await setupPredicate(wallet, amountToPredicate, predicate); - const initialReceiverBalance = await wallet.provider.getBalance(wallet.address, NativeAssetId); + const initialPredicateBalance = await setupPredicate(wallet, predicate, amountToPredicate); + const initialReceiverBalance = await receiver.getBalance(); - await wallet.submitSpendPredicate(predicate, initialPredicateBalance, [ - '0xef86afa9696cf0dc6385e2c407a6e159a1103cefb7e2ae0636fb33d3cb2a9e4a', - ]); + const tx = await predicate + .setData('0xef86afa9696cf0dc6385e2c407a6e159a1103cefb7e2ae0636fb33d3cb2a9e4a') + .transfer(receiver.address, amountToReceiver); + await tx.waitForResult(); await assertResults( - wallet, - wallet.address, + predicate, + receiver, initialPredicateBalance, initialReceiverBalance, amountToPredicate, - predicate, - true + amountToReceiver ); }); it('can call a Coin predicate which returns false with invalid predicate data [address]', async () => { - const receiverAddress = Address.fromRandom(); - const wallet = await setup(); + const [wallet, receiver] = await setup(); const amountToPredicate = 10; - const predicate = new Predicate(testPredicateAddress, AddressAbiInputs); + const predicate = new Predicate<[string]>(testPredicateAddress, AddressAbiInputs); - const initialPredicateBalance = await setupPredicate(wallet, amountToPredicate, predicate); - const initialReceiverBalance = await wallet.provider.getBalance(receiverAddress, NativeAssetId); + const initialPredicateBalance = await setupPredicate(wallet, predicate, amountToPredicate); + const initialReceiverBalance = await receiver.getBalance(); // Check there are UTXO locked with the predicate hash - expect(toNumber(initialPredicateBalance)).toBeGreaterThanOrEqual(toNumber(amountToPredicate)); + expect(initialPredicateBalance.gte(amountToPredicate)); expect(initialReceiverBalance.toHex()).toEqual(toHex(0)); + predicate.setData('0xbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbada'); + await expect(async () => { - await wallet.provider.submitSpendPredicate<BytesLike>( - predicate, - initialPredicateBalance, - receiverAddress, - ['0xbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbada'] - ); + await predicate.transfer(receiver.address, 50); }).rejects.toThrow('Invalid transaction'); }); it('can call a Coin predicate which returns true with valid predicate data [u32]', async () => { - const receiverAddress = Address.fromRandom(); - const wallet = await setup(); - const amountToPredicate = 10; - const predicate = new Predicate(testPredicateU32, U32AbiInputs); + const [wallet, receiver] = await setup(); + const amountToPredicate = 100; + const amountToReceiver = 50; + const predicate = new Predicate<[number]>(testPredicateU32, U32AbiInputs); - const initialPredicateBalance = await setupPredicate(wallet, amountToPredicate, predicate); - const initialReceiverBalance = await wallet.provider.getBalance(receiverAddress, NativeAssetId); + const initialPredicateBalance = await setupPredicate(wallet, predicate, amountToPredicate); + const initialReceiverBalance = await receiver.getBalance(); - await wallet.provider.submitSpendPredicate<BigNumberish>( - predicate, - initialPredicateBalance, - receiverAddress, - [1078] - ); + const tx = await predicate.setData(1078).transfer(receiver.address, amountToReceiver); + await tx.waitForResult(); await assertResults( - wallet, - receiverAddress, + predicate, + receiver, initialPredicateBalance, initialReceiverBalance, amountToPredicate, - predicate + amountToReceiver ); }); it('can call a Coin predicate which returns false with invalid predicate data [u32]', async () => { - const receiverAddress = Address.fromRandom(); - const wallet = await setup(); + const [wallet, receiver] = await setup(); const amountToPredicate = 10; - const predicate = new Predicate(testPredicateU32, U32AbiInputs); + const predicate = new Predicate<[number]>(testPredicateU32, U32AbiInputs); - const initialPredicateBalance = await setupPredicate(wallet, amountToPredicate, predicate); - const initialReceiverBalance = await wallet.provider.getBalance(receiverAddress, NativeAssetId); + const initialPredicateBalance = await setupPredicate(wallet, predicate, amountToPredicate); + const initialReceiverBalance = await receiver.getBalance(); // Check there are UTXO locked with the predicate hash expect(toNumber(initialPredicateBalance)).toBeGreaterThanOrEqual(amountToPredicate); expect(initialReceiverBalance.toHex()).toEqual(toHex(0)); await expect(async () => { - await wallet.provider.submitSpendPredicate<BigNumberish>( - predicate, - initialPredicateBalance, - receiverAddress, - [100] - ); + await predicate.setData(100).transfer(receiver.address, amountToPredicate); }).rejects.toThrow('Invalid transaction'); }); it('can call a Coin predicate which returns true with valid predicate data [struct]', async () => { - const receiverAddress = Address.fromRandom(); - const wallet = await setup(); - const amountToPredicate = 10; - const predicate = new Predicate(testPredicateStruct, StructAbiInputs); - - const initialPredicateBalance = await setupPredicate(wallet, amountToPredicate, predicate); - const initialReceiverBalance = await wallet.provider.getBalance(receiverAddress, NativeAssetId); - - const validation: Validation = { - has_account: true, - total_complete: 100, - }; - await wallet.provider.submitSpendPredicate<Validation>( - predicate, - initialPredicateBalance, - receiverAddress, - [validation] - ); + const [wallet, receiver] = await setup(); + const amountToPredicate = 100; + const amountToReceiver = 50; + const predicate = new Predicate<[Validation]>(testPredicateStruct, StructAbiInputs); + + const initialPredicateBalance = await setupPredicate(wallet, predicate, amountToPredicate); + const initialReceiverBalance = await receiver.getBalance(); + + const tx = await predicate + .setData({ + has_account: true, + total_complete: 100, + }) + .transfer(receiver.address, amountToReceiver); + await tx.waitForResult(); await assertResults( - wallet, - receiverAddress, + predicate, + receiver, initialPredicateBalance, initialReceiverBalance, amountToPredicate, - predicate + amountToReceiver ); }); it('can call a [bin] Coin predicate which returns false with invalid predicate data [struct]', async () => { - const receiverAddress = Address.fromRandom(); - const wallet = await setup(); + const [wallet, receiver] = await setup(); const amountToPredicate = 10; - const predicate = new Predicate(testPredicateStructBin, StructAbiInputs); - const initialPredicateBalance = await setupPredicate(wallet, amountToPredicate, predicate); + const predicate = new Predicate<[Validation]>(testPredicateStructBin, StructAbiInputs); - const validation: Validation = { - has_account: false, - total_complete: 0, - }; + const initialPredicateBalance = await setupPredicate(wallet, predicate, amountToPredicate); + const initialReceiverBalance = await receiver.getBalance(); + + // Check there are UTXO locked with the predicate hash + expect(toNumber(initialPredicateBalance)).toBeGreaterThanOrEqual(amountToPredicate); + expect(initialReceiverBalance.toHex()).toEqual(toHex(0)); await expect(async () => { - await wallet.provider.submitSpendPredicate<Validation>( - predicate, - initialPredicateBalance, - receiverAddress, - [validation] - ); + await predicate + .setData({ + has_account: false, + total_complete: 0, + }) + .transfer(receiver.address, amountToPredicate); }).rejects.toThrow('Invalid transaction'); }); - // TODO: Enable this test once predicates start to consume gas - // FUELS-TS - https://github.com/FuelLabs/fuels-ts/issues/385 - // SPEC - https://github.com/FuelLabs/fuel-specs/issues/119 - it.skip('should fail if inform gasLimit too low', async () => { - const receiverAddress = Address.fromRandom(); - const wallet = await setup(); - const amountToPredicate = 10; - const predicate = new Predicate(testPredicateStruct, StructAbiInputs); - - const initialPredicateBalance = await setupPredicate(wallet, amountToPredicate, predicate); - - const validation: Validation = { - has_account: true, - total_complete: 100, - }; - - let failed; - try { - await wallet.provider.submitSpendPredicate<Validation>( - predicate, - initialPredicateBalance, - receiverAddress, - [validation], - undefined, - { gasLimit: 1 } - ); - } catch (e) { - failed = true; - } - - expect(failed).toEqual(true); - }); - it('can call a Coin predicate which returns true with valid predicate data [main args struct]', async () => { - const receiverAddress = Address.fromRandom(); - const wallet = await setup(); - const amountToPredicate = 10; - const predicate = new Predicate(testPredicateStruct, predicateMainArgsStructAbi); - - const initialPredicateBalance = await setupPredicate(wallet, amountToPredicate, predicate); - const initialReceiverBalance = await wallet.provider.getBalance(receiverAddress, NativeAssetId); - - const validation: Validation = { - has_account: true, - total_complete: 100, - }; - await wallet.provider.submitSpendPredicate<Validation>( - predicate, - initialPredicateBalance, - receiverAddress, - [validation] - ); + const [wallet, receiver] = await setup(); + const amountToPredicate = 100; + const amountToReceiver = 50; + const predicate = new Predicate<[Validation]>(testPredicateStruct, predicateMainArgsStructAbi); + + const initialPredicateBalance = await setupPredicate(wallet, predicate, amountToPredicate); + const initialReceiverBalance = await receiver.getBalance(); + + const tx = await predicate + .setData({ + has_account: true, + total_complete: 100, + }) + .transfer(receiver.address, amountToReceiver); + await tx.waitForResult(); await assertResults( - wallet, - receiverAddress, + predicate, + receiver, initialPredicateBalance, initialReceiverBalance, amountToPredicate, - predicate + amountToReceiver ); }); it('can call a [bin] Coin predicate which returns false with invalid predicate data [main args struct]', async () => { - const receiverAddress = Address.fromRandom(); - const wallet = await setup(); - const amountToPredicate = 10; - const predicate = new Predicate(testPredicateMainArgsStruct, predicateMainArgsStructAbi); - const initialPredicateBalance = await setupPredicate(wallet, amountToPredicate, predicate); + const [wallet, receiver] = await setup(); + const amountToPredicate = 100; + const predicate = new Predicate<[Validation]>( + testPredicateMainArgsStruct, + predicateMainArgsStructAbi + ); - const validation: Validation = { - has_account: false, - total_complete: 0, - }; + const initialPredicateBalance = await setupPredicate(wallet, predicate, amountToPredicate); + + // Check there are UTXO locked with the predicate hash + expect(toNumber(initialPredicateBalance)).toBeGreaterThanOrEqual(amountToPredicate); await expect(async () => { - await wallet.provider.submitSpendPredicate<Validation>( - predicate, - initialPredicateBalance, - receiverAddress, - [validation] - ); + await predicate + .setData({ + has_account: false, + total_complete: 0, + }) + .transfer(receiver.address, 50); }).rejects.toThrow('Invalid transaction'); }); + + it('should fail if inform gasLimit too low', async () => { + const [wallet, receiver] = await setup(); + const amountToPredicate = 100; + const predicate = new Predicate<[Validation]>(testPredicateStruct, predicateMainArgsStructAbi); + + const predicateBalance = await setupPredicate(wallet, predicate, amountToPredicate); + + const validation: Validation = { + has_account: true, + total_complete: 100, + }; + + // Should throw if not have resouces to pay tx + gasFee + expect(async () => { + await predicate.setData(validation).transfer(receiver.address, predicateBalance); + }).rejects.toThrow(/not enough resources to fit the target/i); + + // Should throw if gasLimit is too low + // TODO: When gas is to low the return error is Invalid transaction, once is fixed on the + // fuel-client we should change with the proper error message + expect(async () => { + await predicate.setData(validation).transfer(receiver.address, 50, NativeAssetId, { + gasLimit: 1, + }); + }).rejects.toThrow(/Invalid transaction/i); + }); }); diff --git a/packages/fuels/package.json b/packages/fuels/package.json index c13a307e139..0445128ef54 100644 --- a/packages/fuels/package.json +++ b/packages/fuels/package.json @@ -51,6 +51,7 @@ "@fuel-ts/wallet": "workspace:*", "@fuel-ts/wallet-manager": "workspace:*", "@fuel-ts/wordlists": "workspace:*", + "@fuel-ts/account": "workspace:*", "commander": "^9.4.1" }, "scripts": { diff --git a/packages/fuels/src/index.ts b/packages/fuels/src/index.ts index a7972614e29..15b54d0d911 100644 --- a/packages/fuels/src/index.ts +++ b/packages/fuels/src/index.ts @@ -3,6 +3,8 @@ export * from '@fuel-ts/abi-coder'; export * from '@fuel-ts/address'; export * from '@fuel-ts/constants'; export * from '@fuel-ts/contract'; +export * from '@fuel-ts/account'; +export * from '@fuel-ts/predicate'; export * from '@fuel-ts/hasher'; export * from '@fuel-ts/interfaces'; export * from '@fuel-ts/keystore'; diff --git a/packages/interfaces/src/index.ts b/packages/interfaces/src/index.ts index de4617df282..3c771be3435 100644 --- a/packages/interfaces/src/index.ts +++ b/packages/interfaces/src/index.ts @@ -25,17 +25,18 @@ export abstract class AbstractContract { abstract id: AbstractAddress; } -export abstract class AbstractWallet { +export abstract class AbstractAccount { abstract address: AbstractAddress; } -export type AddressLike = AbstractAddress | AbstractWallet; +export type AddressLike = AbstractAddress | AbstractAccount; export type ContractIdLike = AbstractAddress | AbstractContract; export abstract class AbstractPredicate { abstract bytes: Uint8Array; abstract address: AbstractAddress; + abstract predicateData: Uint8Array; // eslint-disable-next-line @typescript-eslint/no-explicit-any abstract types?: ReadonlyArray<any>; } diff --git a/packages/predicate/package.json b/packages/predicate/package.json index 4cb0ee94f46..0c51ec5dc6c 100644 --- a/packages/predicate/package.json +++ b/packages/predicate/package.json @@ -29,8 +29,13 @@ "@fuel-ts/abi-coder": "workspace:*", "@fuel-ts/address": "workspace:*", "@fuel-ts/interfaces": "workspace:*", - "@fuel-ts/contract": "workspace:*", - "@fuel-ts/versions": "workspace:*" + "@fuel-ts/versions": "workspace:*", + "@fuel-ts/account": "workspace:*", + "@fuel-ts/providers": "workspace:*", + "@fuel-ts/transactions": "workspace:*", + "@fuel-ts/merkle": "workspace:*" }, - "devDependencies": {} + "devDependencies": { + "@fuel-ts/math": "workspace:*" + } } diff --git a/packages/predicate/src/predicate.test.ts b/packages/predicate/src/predicate.test.ts new file mode 100644 index 00000000000..486ef8a04f8 --- /dev/null +++ b/packages/predicate/src/predicate.test.ts @@ -0,0 +1,124 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { hexlify } from '@ethersproject/bytes'; +import { Account } from '@fuel-ts/account'; +import { Address } from '@fuel-ts/address'; +import { bn } from '@fuel-ts/math'; +import type { Resource } from '@fuel-ts/providers'; +import { ScriptTransactionRequest, CoinStatus } from '@fuel-ts/providers'; +import type { InputCoin } from '@fuel-ts/transactions'; + +import { Predicate } from './predicate'; + +// This data is arbitrary, make to unit test the Predicate class +const PREDICATE_BYTECODE = + '0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'; +const PREDICATE_ADDRESS = '0x27c54187841c60ac0ebafcf1f2778d30f9973865f9a4bcd959e137aa852c4375'; +const PREDICATE_ABI = { + types: [ + { + typeId: 0, + type: 'bool', + components: null, + typeParameters: null, + }, + { + typeId: 1, + type: 'b256', + }, + ], + functions: [ + { + inputs: [ + { + name: 'data', + type: 1, + typeArguments: null, + }, + ], + name: 'main', + output: { + name: '', + type: 0, + typeArguments: null, + }, + }, + ], + loggedTypes: [], +}; + +describe('Predicate', () => { + it('Should create the correct address for a given bytecode', () => { + const predicate = new Predicate(PREDICATE_BYTECODE); + expect(predicate.address.toB256()).toEqual(PREDICATE_ADDRESS); + }); + + it('Should assign only correct data to predicate', () => { + const predicate = new Predicate(PREDICATE_BYTECODE, PREDICATE_ABI); + const b256 = '0x0101010101010101010101010101010101010101010101010101010101010101'; + + predicate.setData<[string]>(b256); + + // Assign correct data to predicate + expect(hexlify(predicate.predicateData)).toEqual(b256); + // Try to assign incorrect data should fail predicate + expect(async () => { + predicate.setData<[string]>('0x01'); + }).rejects.toThrow(/Invalid b256/i); + }); + + it('Should include predicate on input when sendTransaction', () => { + const b256 = '0x0101010101010101010101010101010101010101010101010101010101010101'; + const sendTransactionMock = jest + .spyOn(Account.prototype, 'sendTransaction') + .mockImplementation(); + const predicate = new Predicate(PREDICATE_BYTECODE, PREDICATE_ABI); + + predicate.setData<[string]>(b256); + + const request = new ScriptTransactionRequest(); + + request.addResource({ + id: '0x01', + assetId: '0x0000000000000000000000000000000000000000000000000000000000000000', + amount: bn(1), + owner: Address.fromB256(PREDICATE_ADDRESS), + status: CoinStatus.Unspent, + maturity: 0, + blockCreated: bn(0), + }); + + predicate.sendTransaction(request); + + const inputCoinMock = sendTransactionMock.mock.calls[0][0].inputs?.[0] as any as InputCoin; + expect(hexlify(inputCoinMock.predicate)).toBe(PREDICATE_BYTECODE); + expect(hexlify(inputCoinMock.predicateData)).toBe(b256); + }); + + it('Should include predicate on input when simulateTransaction', () => { + const b256 = '0x0101010101010101010101010101010101010101010101010101010101010101'; + const simulateTransactionMock = jest + .spyOn(Account.prototype, 'simulateTransaction') + .mockImplementation(); + const predicate = new Predicate(PREDICATE_BYTECODE, PREDICATE_ABI); + + predicate.setData<[string]>(b256); + + const request = new ScriptTransactionRequest(); + + request.addResource({ + id: '0x01', + assetId: '0x0000000000000000000000000000000000000000000000000000000000000000', + amount: bn(1), + owner: Address.fromB256(PREDICATE_ADDRESS), + status: CoinStatus.Unspent, + maturity: 0, + blockCreated: bn(0), + }); + + predicate.simulateTransaction(request); + + const inputCoinMock = simulateTransactionMock.mock.calls[0][0].inputs?.[0] as any as InputCoin; + expect(hexlify(inputCoinMock.predicate)).toBe(PREDICATE_BYTECODE); + expect(hexlify(inputCoinMock.predicateData)).toBe(b256); + }); +}); diff --git a/packages/predicate/src/predicate.ts b/packages/predicate/src/predicate.ts index 9d9b4fcfc8f..7d8bfcfe392 100644 --- a/packages/predicate/src/predicate.ts +++ b/packages/predicate/src/predicate.ts @@ -1,26 +1,36 @@ import type { BytesLike } from '@ethersproject/bytes'; -import { arrayify } from '@ethersproject/bytes'; +import { hexlify, arrayify } from '@ethersproject/bytes'; import { Logger } from '@ethersproject/logger'; -import { Interface } from '@fuel-ts/abi-coder'; -import type { JsonAbiFragmentType, JsonAbi } from '@fuel-ts/abi-coder'; +import { AbiCoder, Interface } from '@fuel-ts/abi-coder'; +import type { JsonAbiFragmentType, JsonAbi, InputValue } from '@fuel-ts/abi-coder'; +import { Account } from '@fuel-ts/account'; import { Address } from '@fuel-ts/address'; -import { ContractUtils } from '@fuel-ts/contract'; -import { AbstractPredicate } from '@fuel-ts/interfaces'; -import type { AbstractAddress } from '@fuel-ts/interfaces'; +import type { + CallResult, + Provider, + TransactionRequestLike, + TransactionResponse, +} from '@fuel-ts/providers'; +import { transactionRequestify } from '@fuel-ts/providers'; +import { InputType } from '@fuel-ts/transactions'; import { versions } from '@fuel-ts/versions'; +import { getContractRoot } from './utils'; + const logger = new Logger(versions.FUELS); -export class Predicate extends AbstractPredicate { +export class Predicate<ARGS extends InputValue[]> extends Account { bytes: Uint8Array; - address: AbstractAddress; types?: ReadonlyArray<JsonAbiFragmentType>; + predicateData: Uint8Array = Uint8Array.from([]); interface?: Interface; - constructor(bytes: BytesLike, types?: JsonAbi) { - super(); + constructor(bytes: BytesLike, types?: JsonAbi, provider?: string | Provider) { + const address = Address.fromB256(getContractRoot(bytes)); + super(address, provider); + + // Assign bytes data this.bytes = arrayify(bytes); - this.address = Address.fromB256(ContractUtils.getContractRoot(this.bytes)); if (types) { this.interface = new Interface(types as JsonAbi); @@ -36,4 +46,36 @@ export class Predicate extends AbstractPredicate { } } } + + populateTransactionPredicateData(transactionRequestLike: TransactionRequestLike) { + const request = transactionRequestify(transactionRequestLike); + + request.inputs?.forEach((input) => { + if (input.type === InputType.Coin && hexlify(input.owner) === this.address.toB256()) { + // eslint-disable-next-line no-param-reassign + input.predicate = this.bytes; + // eslint-disable-next-line no-param-reassign + input.predicateData = this.predicateData; + } + }); + + return request; + } + + sendTransaction(transactionRequestLike: TransactionRequestLike): Promise<TransactionResponse> { + const transactionRequest = this.populateTransactionPredicateData(transactionRequestLike); + return super.sendTransaction(transactionRequest); + } + + simulateTransaction(transactionRequestLike: TransactionRequestLike): Promise<CallResult> { + const transactionRequest = this.populateTransactionPredicateData(transactionRequestLike); + return super.simulateTransaction(transactionRequest); + } + + setData<T extends ARGS>(...args: T) { + const abiCoder = new AbiCoder(); + const encoded = abiCoder.encode(this.types || [], args); + this.predicateData = encoded; + return this; + } } diff --git a/packages/predicate/src/utils/getContractRoot.ts b/packages/predicate/src/utils/getContractRoot.ts new file mode 100644 index 00000000000..956428600d4 --- /dev/null +++ b/packages/predicate/src/utils/getContractRoot.ts @@ -0,0 +1,17 @@ +import type { BytesLike } from '@ethersproject/bytes'; +import { hexlify, arrayify } from '@ethersproject/bytes'; +import { calcRoot } from '@fuel-ts/merkle'; + +export const getContractRoot = (bytecode: BytesLike): string => { + const chunkSize = 8; + const chunks: Uint8Array[] = []; + const bytes = arrayify(bytecode); + + for (let offset = 0; offset < bytes.length; offset += chunkSize) { + const chunk = new Uint8Array(chunkSize); + chunk.set(bytes.slice(offset, offset + chunkSize)); + chunks.push(chunk); + } + + return calcRoot(chunks.map((c) => hexlify(c))); +}; diff --git a/packages/predicate/src/utils/index.ts b/packages/predicate/src/utils/index.ts new file mode 100644 index 00000000000..a1cb82f4415 --- /dev/null +++ b/packages/predicate/src/utils/index.ts @@ -0,0 +1 @@ +export * from './getContractRoot'; diff --git a/packages/providers/src/provider.ts b/packages/providers/src/provider.ts index ec6e3633e29..5d40583f8a4 100644 --- a/packages/providers/src/provider.ts +++ b/packages/providers/src/provider.ts @@ -2,12 +2,9 @@ import type { BytesLike } from '@ethersproject/bytes'; import { arrayify, hexlify } from '@ethersproject/bytes'; import type { Network } from '@ethersproject/networks'; -import type { InputValue } from '@fuel-ts/abi-coder'; -import { AbiCoder } from '@fuel-ts/abi-coder'; import { Address } from '@fuel-ts/address'; -import { NativeAssetId } from '@fuel-ts/constants'; -import type { AbstractAddress, AbstractPredicate } from '@fuel-ts/interfaces'; -import type { BigNumberish, BN } from '@fuel-ts/math'; +import type { AbstractAddress } from '@fuel-ts/interfaces'; +import type { BN } from '@fuel-ts/math'; import { max, bn } from '@fuel-ts/math'; import type { Transaction } from '@fuel-ts/transactions'; import { @@ -33,12 +30,9 @@ import { coinQuantityfy } from './coin-quantity'; import type { Message, MessageProof } from './message'; import type { ExcludeResourcesOption, Resource } from './resource'; import { isRawCoin } from './resource'; -import { ScriptTransactionRequest, transactionRequestify } from './transaction-request'; +import { transactionRequestify } from './transaction-request'; import type { TransactionRequestLike, TransactionRequest } from './transaction-request'; -import type { - TransactionResult, - TransactionResultReceipt, -} from './transaction-response/transaction-response'; +import type { TransactionResultReceipt } from './transaction-response/transaction-response'; import { TransactionResponse } from './transaction-response/transaction-response'; import { calculateTransactionFee, getReceiptsWithMissingData } from './utils'; @@ -724,95 +718,4 @@ export default class Provider { }, }; } - - async buildSpendPredicate<T>( - predicate: AbstractPredicate, - amountToSpend: BigNumberish, - receiverAddress: AbstractAddress, - predicateData?: InputValue<T>[], - assetId: BytesLike = NativeAssetId, - predicateOptions?: BuildPredicateOptions, - walletAddress?: AbstractAddress - ): Promise<ScriptTransactionRequest> { - const predicateResources: Resource[] = await this.getResourcesToSpend(predicate.address, [ - [amountToSpend, assetId], - ]); - const options = { - fundTransaction: true, - ...predicateOptions, - }; - const request = new ScriptTransactionRequest({ - gasLimit: MAX_GAS_PER_TX, - ...options, - }); - - let encoded: undefined | Uint8Array; - if (predicateData && predicate.types) { - const abiCoder = new AbiCoder(); - encoded = abiCoder.encode(predicate.types, predicateData as InputValue[]); - } - - const totalInPredicate: BN = predicateResources.reduce((prev: BN, coin: Resource) => { - request.addResource({ - ...coin, - predicate: predicate.bytes, - predicateData: encoded, - } as unknown as Resource); - request.outputs = []; - - return prev.add(coin.amount); - }, bn(0)); - - // output sent to receiver - request.addCoinOutput(receiverAddress, totalInPredicate, assetId); - - const requiredCoinQuantities: CoinQuantityLike[] = []; - if (options.fundTransaction) { - requiredCoinQuantities.push(request.calculateFee()); - } - - if (requiredCoinQuantities.length && walletAddress) { - const resources = await this.getResourcesToSpend(walletAddress, requiredCoinQuantities); - request.addResources(resources); - } - - return request; - } - - async submitSpendPredicate<T>( - predicate: AbstractPredicate, - amountToSpend: BigNumberish, - receiverAddress: AbstractAddress, - predicateData?: InputValue<T>[], - assetId: BytesLike = NativeAssetId, - options?: BuildPredicateOptions, - walletAddress?: AbstractAddress - ): Promise<TransactionResult<'success'>> { - const request = await this.buildSpendPredicate<T>( - predicate, - amountToSpend, - receiverAddress, - predicateData, - assetId, - options, - walletAddress - ); - - try { - const response = await this.sendTransaction(request); - return await response.waitForResult(); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (error: any) { - const errors: { message: string }[] = error?.response?.errors || []; - if ( - errors.some(({ message }) => - message.includes('unexpected block execution error TransactionValidity(InvalidPredicate') - ) - ) { - throw new Error('Invalid Predicate'); - } - - throw error; - } - } } diff --git a/packages/script/package.json b/packages/script/package.json index d03c99eafc3..732879d2042 100644 --- a/packages/script/package.json +++ b/packages/script/package.json @@ -35,7 +35,8 @@ "@fuel-ts/math": "workspace:*", "@fuel-ts/providers": "workspace:*", "@fuel-ts/wallet": "workspace:*", - "@fuel-ts/transactions": "workspace:*" + "@fuel-ts/transactions": "workspace:*", + "@fuel-ts/account": "workspace:*" }, "devDependencies": { "forc-bin": "workspace:*" diff --git a/packages/script/src/script.test.ts b/packages/script/src/script.test.ts index 11e9ab9423a..b6b481144ad 100644 --- a/packages/script/src/script.test.ts +++ b/packages/script/src/script.test.ts @@ -1,13 +1,13 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { arrayify } from '@ethersproject/bytes'; import { AbiCoder } from '@fuel-ts/abi-coder'; +import type { Account } from '@fuel-ts/account'; import { NativeAssetId } from '@fuel-ts/constants'; import type { BigNumberish } from '@fuel-ts/math'; import { bn } from '@fuel-ts/math'; import type { CoinQuantityLike, TransactionResponse, TransactionResult } from '@fuel-ts/providers'; import { Provider, ScriptTransactionRequest } from '@fuel-ts/providers'; import { ReceiptType } from '@fuel-ts/transactions'; -import type { BaseWalletLocked } from '@fuel-ts/wallet'; import { generateTestWallet } from '@fuel-ts/wallet/test-utils'; import { readFileSync } from 'fs'; import { join } from 'path'; @@ -29,7 +29,7 @@ const setup = async () => { // #region typedoc:script-call const callScript = async <TData, TResult>( - wallet: BaseWalletLocked, + account: Account, script: Script<TData, TResult>, data: TData ): Promise<{ @@ -49,11 +49,11 @@ const callScript = async <TData, TResult>( // Get and add required coins to the transaction if (requiredCoinQuantities.length) { - const resources = await wallet.getResourcesToSpend(requiredCoinQuantities); + const resources = await account.getResourcesToSpend(requiredCoinQuantities); request.addResources(resources); } - const response = await wallet.sendTransaction(request); + const response = await account.sendTransaction(request); const transactionResult = await response.waitForResult(); const result = script.decodeCallResult(transactionResult); diff --git a/packages/wallet/package.json b/packages/wallet/package.json index 9177564faea..9cc93adbcbf 100644 --- a/packages/wallet/package.json +++ b/packages/wallet/package.json @@ -39,7 +39,9 @@ "@fuel-ts/mnemonic": "workspace:*", "@fuel-ts/providers": "workspace:*", "@fuel-ts/signer": "workspace:*", - "@fuel-ts/transactions": "workspace:*" + "@fuel-ts/transactions": "workspace:*", + "@fuel-ts/predicate": "workspace:*", + "@fuel-ts/account": "workspace:*" }, "devDependencies": { "@fuel-ts/address": "workspace:*", diff --git a/packages/wallet/src/base-unlocked-wallet.ts b/packages/wallet/src/base-unlocked-wallet.ts index 55f970797a3..a3a42f7688e 100644 --- a/packages/wallet/src/base-unlocked-wallet.ts +++ b/packages/wallet/src/base-unlocked-wallet.ts @@ -1,4 +1,5 @@ import type { BytesLike } from '@ethersproject/bytes'; +import { Account } from '@fuel-ts/account'; import { hashMessage, hashTransaction } from '@fuel-ts/hasher'; import type { TransactionResponse, @@ -9,13 +10,12 @@ import type { import { transactionRequestify } from '@fuel-ts/providers'; import { Signer } from '@fuel-ts/signer'; -import { BaseWalletLocked } from './base-locked-wallet'; import { FUEL_NETWORK_URL } from './constants'; /** * BaseWalletUnlocked */ -export class BaseWalletUnlocked extends BaseWalletLocked { +export class BaseWalletUnlocked extends Account { /* default HDWallet path */ static defaultPath = "m/44'/1179993420'/0'/0/0"; diff --git a/packages/wallet/src/index.ts b/packages/wallet/src/index.ts index 435b0276c06..79311c9b16c 100644 --- a/packages/wallet/src/index.ts +++ b/packages/wallet/src/index.ts @@ -1,4 +1,3 @@ -export * from './base-locked-wallet'; export * from './base-unlocked-wallet'; export * from './wallet'; export * from './wallets'; diff --git a/packages/wallet/src/transfer.test.ts b/packages/wallet/src/transfer.test.ts index 634daecbc58..285a11d7967 100644 --- a/packages/wallet/src/transfer.test.ts +++ b/packages/wallet/src/transfer.test.ts @@ -96,11 +96,11 @@ describe('Wallet', () => { ]); request.addResources(resources); - request.addCoinOutputs(receiverA, [ + request.addCoinOutputs(receiverA.address, [ [amount, assetIdA], [amount, assetIdB], ]); - request.addCoinOutputs(receiverB, [ + request.addCoinOutputs(receiverB.address, [ [amount, assetIdA], [amount, assetIdB], ]); diff --git a/packages/wallet/src/wallets.ts b/packages/wallet/src/wallets.ts index 01bf1519009..a8558dd7d68 100644 --- a/packages/wallet/src/wallets.ts +++ b/packages/wallet/src/wallets.ts @@ -4,19 +4,19 @@ // /* eslint-disable max-classes-per-file */ import type { BytesLike } from '@ethersproject/bytes'; +import { Account } from '@fuel-ts/account'; import { HDWallet } from '@fuel-ts/hdwallet'; import { Mnemonic } from '@fuel-ts/mnemonic'; import type { Provider } from '@fuel-ts/providers'; import { Signer } from '@fuel-ts/signer'; -import { BaseWalletLocked } from './base-locked-wallet'; import { BaseWalletUnlocked } from './base-unlocked-wallet'; import type { GenerateOptions } from './types/GenerateOptions'; /** * WalletLocked */ -export class WalletLocked extends BaseWalletLocked { +export class WalletLocked extends Account { unlock(privateKey: BytesLike) { // eslint-disable-next-line @typescript-eslint/no-use-before-define return new WalletUnlocked(privateKey, this.provider); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 71223224d97..d55f58ae7bb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -151,6 +151,24 @@ importers: '@types/rimraf': 3.0.2 forc-bin: link:../forc-bin + packages/account: + specifiers: + '@ethersproject/bytes': ^5.7.0 + '@fuel-ts/address': workspace:* + '@fuel-ts/constants': workspace:* + '@fuel-ts/interfaces': workspace:* + '@fuel-ts/math': workspace:* + '@fuel-ts/providers': workspace:* + '@fuel-ts/transactions': workspace:* + dependencies: + '@ethersproject/bytes': 5.7.0 + '@fuel-ts/address': link:../address + '@fuel-ts/constants': link:../constants + '@fuel-ts/interfaces': link:../interfaces + '@fuel-ts/math': link:../math + '@fuel-ts/providers': link:../providers + '@fuel-ts/transactions': link:../transactions + packages/address: specifiers: '@ethersproject/bytes': ^5.7.0 @@ -183,6 +201,7 @@ importers: '@ethersproject/logger': ^5.7.0 '@ethersproject/sha2': ^5.7.0 '@fuel-ts/abi-coder': workspace:* + '@fuel-ts/account': workspace:* '@fuel-ts/address': workspace:* '@fuel-ts/interfaces': workspace:* '@fuel-ts/keystore': workspace:* @@ -200,6 +219,7 @@ importers: '@ethersproject/logger': 5.7.0 '@ethersproject/sha2': 5.7.0 '@fuel-ts/abi-coder': link:../abi-coder + '@fuel-ts/account': link:../account '@fuel-ts/address': link:../address '@fuel-ts/interfaces': link:../interfaces '@fuel-ts/keystore': link:../keystore @@ -255,6 +275,7 @@ importers: '@ethersproject/bytes': ^5.7.0 '@fuel-ts/abi-coder': workspace:* '@fuel-ts/abi-typegen': workspace:* + '@fuel-ts/account': workspace:* '@fuel-ts/address': workspace:* '@fuel-ts/constants': workspace:* '@fuel-ts/contract': workspace:* @@ -283,6 +304,7 @@ importers: '@ethersproject/bytes': 5.7.0 '@fuel-ts/abi-coder': link:../abi-coder '@fuel-ts/abi-typegen': link:../abi-typegen + '@fuel-ts/account': link:../account '@fuel-ts/address': link:../address '@fuel-ts/constants': link:../constants '@fuel-ts/contract': link:../contract @@ -413,18 +435,27 @@ importers: '@ethersproject/bytes': ^5.7.0 '@ethersproject/logger': ^5.7.0 '@fuel-ts/abi-coder': workspace:* + '@fuel-ts/account': workspace:* '@fuel-ts/address': workspace:* - '@fuel-ts/contract': workspace:* '@fuel-ts/interfaces': workspace:* + '@fuel-ts/math': workspace:* + '@fuel-ts/merkle': workspace:* + '@fuel-ts/providers': workspace:* + '@fuel-ts/transactions': workspace:* '@fuel-ts/versions': workspace:* dependencies: '@ethersproject/bytes': 5.7.0 '@ethersproject/logger': 5.7.0 '@fuel-ts/abi-coder': link:../abi-coder + '@fuel-ts/account': link:../account '@fuel-ts/address': link:../address - '@fuel-ts/contract': link:../contract '@fuel-ts/interfaces': link:../interfaces + '@fuel-ts/merkle': link:../merkle + '@fuel-ts/providers': link:../providers + '@fuel-ts/transactions': link:../transactions '@fuel-ts/versions': link:../versions + devDependencies: + '@fuel-ts/math': link:../math packages/providers: specifiers: @@ -477,6 +508,7 @@ importers: specifiers: '@ethersproject/bytes': ^5.7.0 '@fuel-ts/abi-coder': workspace:* + '@fuel-ts/account': workspace:* '@fuel-ts/constants': workspace:* '@fuel-ts/math': workspace:* '@fuel-ts/providers': workspace:* @@ -486,6 +518,7 @@ importers: dependencies: '@ethersproject/bytes': 5.7.0 '@fuel-ts/abi-coder': link:../abi-coder + '@fuel-ts/account': link:../account '@fuel-ts/constants': link:../constants '@fuel-ts/math': link:../math '@fuel-ts/providers': link:../providers @@ -561,6 +594,7 @@ importers: specifiers: '@ethersproject/bytes': ^5.7.0 '@fuel-ts/abi-coder': workspace:* + '@fuel-ts/account': workspace:* '@fuel-ts/address': workspace:* '@fuel-ts/constants': workspace:* '@fuel-ts/hasher': workspace:* @@ -569,6 +603,7 @@ importers: '@fuel-ts/keystore': workspace:* '@fuel-ts/math': workspace:* '@fuel-ts/mnemonic': workspace:* + '@fuel-ts/predicate': workspace:* '@fuel-ts/providers': workspace:* '@fuel-ts/signer': workspace:* '@fuel-ts/testcases': workspace:* @@ -576,6 +611,7 @@ importers: dependencies: '@ethersproject/bytes': 5.7.0 '@fuel-ts/abi-coder': link:../abi-coder + '@fuel-ts/account': link:../account '@fuel-ts/address': link:../address '@fuel-ts/constants': link:../constants '@fuel-ts/hasher': link:../hasher @@ -583,6 +619,7 @@ importers: '@fuel-ts/interfaces': link:../interfaces '@fuel-ts/math': link:../math '@fuel-ts/mnemonic': link:../mnemonic + '@fuel-ts/predicate': link:../predicate '@fuel-ts/providers': link:../providers '@fuel-ts/signer': link:../signer '@fuel-ts/transactions': link:../transactions From 5f2ef64fd9b89ffd49034ea192340892784220ae Mon Sep 17 00:00:00 2001 From: luizstacio <luizstacio@gmail.com> Date: Fri, 17 Feb 2023 00:57:34 +0100 Subject: [PATCH 02/20] chore: add changesets --- .changeset/clever-chefs-shop.md | 5 +++++ .changeset/curly-eggs-think.md | 5 +++++ .changeset/honest-ways-learn.md | 5 +++++ .changeset/nine-bottles-jog.md | 10 ++++++++++ .changeset/pretty-falcons-sleep.md | 5 +++++ 5 files changed, 30 insertions(+) create mode 100644 .changeset/clever-chefs-shop.md create mode 100644 .changeset/curly-eggs-think.md create mode 100644 .changeset/honest-ways-learn.md create mode 100644 .changeset/nine-bottles-jog.md create mode 100644 .changeset/pretty-falcons-sleep.md diff --git a/.changeset/clever-chefs-shop.md b/.changeset/clever-chefs-shop.md new file mode 100644 index 00000000000..b09c716af6a --- /dev/null +++ b/.changeset/clever-chefs-shop.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/wallet": minor +--- + +Remove BaseWalletLocked and use Account package diff --git a/.changeset/curly-eggs-think.md b/.changeset/curly-eggs-think.md new file mode 100644 index 00000000000..4297d86662e --- /dev/null +++ b/.changeset/curly-eggs-think.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/account": minor +--- + +Create Account pacakge. Moves BaseWalletLocked to a sperate package. diff --git a/.changeset/honest-ways-learn.md b/.changeset/honest-ways-learn.md new file mode 100644 index 00000000000..49dba8a5c77 --- /dev/null +++ b/.changeset/honest-ways-learn.md @@ -0,0 +1,5 @@ +--- +"fuels": minor +--- + +Add packages Account and Predicate to exports diff --git a/.changeset/nine-bottles-jog.md b/.changeset/nine-bottles-jog.md new file mode 100644 index 00000000000..dac3cb2d562 --- /dev/null +++ b/.changeset/nine-bottles-jog.md @@ -0,0 +1,10 @@ +--- +"@fuel-ts/address": minor +"@fuel-ts/contract": minor +"@fuel-ts/interfaces": minor +"@fuel-ts/predicate": minor +"@fuel-ts/providers": minor +"@fuel-ts/script": minor +--- + +Update use of BaseWalletLocked to Account diff --git a/.changeset/pretty-falcons-sleep.md b/.changeset/pretty-falcons-sleep.md new file mode 100644 index 00000000000..4f0db3e454f --- /dev/null +++ b/.changeset/pretty-falcons-sleep.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/abi-typegen": minor +--- + +Update import from BaseWalletLocked to Account From 41a5c0a4bc366cc488cf2a7201afcb8ab0198a15 Mon Sep 17 00:00:00 2001 From: luizstacio <luizstacio@gmail.com> Date: Fri, 17 Feb 2023 00:58:57 +0100 Subject: [PATCH 03/20] test: add Account package on index.test.ts --- packages/fuels/src/index.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/fuels/src/index.test.ts b/packages/fuels/src/index.test.ts index 20746d4371a..839fc539c21 100644 --- a/packages/fuels/src/index.test.ts +++ b/packages/fuels/src/index.test.ts @@ -6,6 +6,7 @@ describe('index.js', () => { expect(fuels.Address).toBeTruthy(); expect(fuels.Contract).toBeTruthy(); expect(fuels.Predicate).toBeTruthy(); + expect(fuels.Account).toBeTruthy(); expect(fuels.Provider).toBeTruthy(); expect(fuels.Wallet).toBeTruthy(); expect(fuels.TransactionType).toBeTruthy(); From 697778d909e439c23d0a0a13131ff0358f36592a Mon Sep 17 00:00:00 2001 From: luizstacio <luizstacio@gmail.com> Date: Fri, 17 Feb 2023 02:55:42 +0100 Subject: [PATCH 04/20] refactor: improve code base on reviews --- packages/account/src/account.test.ts | 26 +++++++++++++------------- packages/account/src/account.ts | 12 ++++-------- packages/address/package.json | 1 - packages/address/src/address.test.ts | 9 +++++++++ packages/address/src/address.ts | 20 +++++++++++++------- typedoc.json | 3 ++- 6 files changed, 41 insertions(+), 30 deletions(-) diff --git a/packages/account/src/account.test.ts b/packages/account/src/account.test.ts index bdb210c975d..d0455708ed5 100644 --- a/packages/account/src/account.test.ts +++ b/packages/account/src/account.test.ts @@ -10,19 +10,19 @@ describe('Account', () => { ]; it('Create wallet using a address', async () => { - const walletLocked = new Account( + const account = new Account( '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db' ); - expect(walletLocked.address.toB256()).toEqual( + expect(account.address.toB256()).toEqual( '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db' ); }); it('getCoins()', async () => { - const walletLocked = new Account( + const account = new Account( '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db' ); - const coins = await walletLocked.getCoins(); + const coins = await account.getCoins(); const assetA = coins.find((c) => c.assetId === assets[0]); expect(assetA?.amount.gt(1)).toBeTruthy(); const assetB = coins.find((c) => c.assetId === assets[1]); @@ -33,10 +33,10 @@ describe('Account', () => { it('getResourcesToSpend()', async () => { // #region typedoc:Message-getResourcesToSpend - const walletLocked = new Account( + const account = new Account( '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db' ); - const resourcesToSpend = await walletLocked.getResourcesToSpend([ + const resourcesToSpend = await account.getResourcesToSpend([ { amount: bn(2), assetId: '0x0101010101010101010101010101010101010101010101010101010101010101', @@ -47,28 +47,28 @@ describe('Account', () => { }); it('getMessages()', async () => { - const walletLocked = new Account( + const account = new Account( '0x69a2b736b60159b43bb8a4f98c0589f6da5fa3a3d101e8e269c499eb942753ba' ); - const messages = await walletLocked.getMessages(); + const messages = await account.getMessages(); expect(messages.length).toEqual(1); }); it('getBalance()', async () => { - const walletLocked = new Account( + const account = new Account( '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db' ); - const balanceA = await walletLocked.getBalance(assets[0]); - const balanceB = await walletLocked.getBalance(assets[1]); + const balanceA = await account.getBalance(assets[0]); + const balanceB = await account.getBalance(assets[1]); expect(balanceA.gte(1)).toBeTruthy(); expect(balanceB.gte(1)).toBeTruthy(); }); it('getBalances()', async () => { - const walletLocked = new Account( + const account = new Account( '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db' ); - const balances = await walletLocked.getBalances(); + const balances = await account.getBalances(); expect(balances.length).toBeGreaterThanOrEqual(1); }); }); diff --git a/packages/account/src/account.ts b/packages/account/src/account.ts index 6994aa4766e..b32029cf0f1 100644 --- a/packages/account/src/account.ts +++ b/packages/account/src/account.ts @@ -1,6 +1,6 @@ import type { BytesLike } from '@ethersproject/bytes'; import { arrayify, hexlify } from '@ethersproject/bytes'; -import { Address, addressify } from '@fuel-ts/address'; +import { Address } from '@fuel-ts/address'; import { NativeAssetId } from '@fuel-ts/constants'; import { AbstractAccount } from '@fuel-ts/interfaces'; import type { AbstractAddress } from '@fuel-ts/interfaces'; @@ -29,21 +29,17 @@ import { MAX_GAS_PER_TX } from '@fuel-ts/transactions'; import { FUEL_NETWORK_URL } from './constants'; /** - * BaseWallet + * Account */ export class Account extends AbstractAccount { readonly address: AbstractAddress; provider: Provider; - constructor(publicKey: string | AbstractAddress, provider: string | Provider = FUEL_NETWORK_URL) { + constructor(address: string | AbstractAddress, provider: string | Provider = FUEL_NETWORK_URL) { super(); this.provider = this.connect(provider); - if (typeof publicKey === 'string') { - this.address = Address.fromString(publicKey); - } else { - this.address = addressify(publicKey); - } + this.address = Address.fromDynamicInput(address); } /** diff --git a/packages/address/package.json b/packages/address/package.json index f86d2fe75f7..dda2ce1281f 100644 --- a/packages/address/package.json +++ b/packages/address/package.json @@ -24,7 +24,6 @@ ], "license": "Apache-2.0", "dependencies": { - "@fuel-ts/constants": "workspace:*", "@fuel-ts/interfaces": "workspace:*", "@fuel-ts/keystore": "workspace:*", "@fuel-ts/versions": "workspace:*", diff --git a/packages/address/src/address.test.ts b/packages/address/src/address.test.ts index 64955f7695b..879fbfc8079 100644 --- a/packages/address/src/address.test.ts +++ b/packages/address/src/address.test.ts @@ -225,4 +225,13 @@ describe('Address class', () => { 'Unknown address format: only Bech32, B256, or Public Key (512) supported' ); }); + + test('create an Address class fromDynamicInput [Address]', async () => { + const address = Address.fromRandom(); + const newAddress = Address.fromDynamicInput(address); + + expect(newAddress.toB256()).toEqual(address.toB256()); + expect(address).toBe(address); + expect(newAddress).not.toBe(address); + }); }); diff --git a/packages/address/src/address.ts b/packages/address/src/address.ts index 610ae6683c2..d21356038d1 100644 --- a/packages/address/src/address.ts +++ b/packages/address/src/address.ts @@ -142,17 +142,23 @@ export default class Address extends AbstractAddress { * thrown if the input string is not nilsy and cannot be resolved to a valid address format * @returns a new `Address` instance */ - static fromDynamicInput(addressId: string): Address { - if (isPublicKey(addressId)) { - return Address.fromPublicKey(addressId); + static fromDynamicInput(address: string | AbstractAddress): Address { + // If address is a object than we assume it's a AbstractAddress + // we don't check by instanceof because it's possible to + // that the host app has a different reference to the same class type + if (typeof address !== 'string') { + return Address.fromB256(address.toB256()); + } + if (isPublicKey(address)) { + return Address.fromPublicKey(address); } - if (isBech32(addressId)) { - return new Address(addressId as Bech32Address); + if (isBech32(address)) { + return new Address(address as Bech32Address); } - if (isB256(addressId)) { - return Address.fromB256(addressId); + if (isB256(address)) { + return Address.fromB256(address); } throw new Error('Unknown address format: only Bech32, B256, or Public Key (512) supported'); diff --git a/typedoc.json b/typedoc.json index e99815d5a35..e8e6310a7b1 100644 --- a/typedoc.json +++ b/typedoc.json @@ -24,7 +24,8 @@ "packages/transactions", "packages/wallet", "packages/wallet-manager", - "packages/wordlists" + "packages/wordlists", + "packages/account" ], "entryPointStrategy": "packages", "githubPages": false, From f3a027a0dd7ebc5c0cd17b04756c3f0b7c35be73 Mon Sep 17 00:00:00 2001 From: luizstacio <luizstacio@gmail.com> Date: Fri, 17 Feb 2023 02:56:25 +0100 Subject: [PATCH 05/20] chore: add pnpm lock --- pnpm-lock.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d55f58ae7bb..f560d8fd864 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -174,7 +174,6 @@ importers: '@ethersproject/bytes': ^5.7.0 '@ethersproject/logger': ^5.7.0 '@ethersproject/sha2': ^5.7.0 - '@fuel-ts/constants': workspace:* '@fuel-ts/interfaces': workspace:* '@fuel-ts/keystore': workspace:* '@fuel-ts/testcases': workspace:* @@ -184,7 +183,6 @@ importers: '@ethersproject/bytes': 5.7.0 '@ethersproject/logger': 5.7.0 '@ethersproject/sha2': 5.7.0 - '@fuel-ts/constants': link:../constants '@fuel-ts/interfaces': link:../interfaces '@fuel-ts/keystore': link:../keystore '@fuel-ts/versions': link:../versions From 34c97ddd0061253d68a8f68285a78e4ec6914d6f Mon Sep 17 00:00:00 2001 From: luizstacio <luizstacio@gmail.com> Date: Fri, 17 Feb 2023 04:12:19 +0100 Subject: [PATCH 06/20] test: fix predicate doc example --- packages/fuel-gauge/src/doc-examples.test.ts | 54 +++++++++++-------- .../predicate-triple-sig/src/main.sw | 11 ++-- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/packages/fuel-gauge/src/doc-examples.test.ts b/packages/fuel-gauge/src/doc-examples.test.ts index ba82aba0fa3..4c38c5d2e1a 100644 --- a/packages/fuel-gauge/src/doc-examples.test.ts +++ b/packages/fuel-gauge/src/doc-examples.test.ts @@ -345,7 +345,7 @@ it('can create a predicate', async () => { // #endregion }); -it.skip('can create a predicate and use', async () => { +it('can create a predicate and use', async () => { // #region typedoc:Predicate-triple-wallets // #context import { Provider, Wallet } from 'fuels'; // #context import { seedTestWallet } from '@fuel-ts/wallet/test-utils'; @@ -359,16 +359,15 @@ it.skip('can create a predicate and use', async () => { const wallet1: WalletUnlocked = Wallet.fromPrivateKey(PRIVATE_KEY_1, provider); const wallet2: WalletUnlocked = Wallet.fromPrivateKey(PRIVATE_KEY_2, provider); const wallet3: WalletUnlocked = Wallet.fromPrivateKey(PRIVATE_KEY_3, provider); - const receiver = Wallet.generate({ provider }); // #endregion // #region typedoc:Predicate-triple-seed // #context import { Provider, Wallet } from 'fuels'; // #context import { seedTestWallet } from '@fuel-ts/wallet/test-utils'; - await seedTestWallet(wallet1, [{ assetId: NativeAssetId, amount: bn(100_000) }]); - await seedTestWallet(wallet2, [{ assetId: NativeAssetId, amount: bn(20_000) }]); - await seedTestWallet(wallet3, [{ assetId: NativeAssetId, amount: bn(30_000) }]); + await seedTestWallet(wallet1, [{ assetId: NativeAssetId, amount: bn(1_000_000) }]); + await seedTestWallet(wallet2, [{ assetId: NativeAssetId, amount: bn(2_000_000) }]); + await seedTestWallet(wallet3, [{ assetId: NativeAssetId, amount: bn(300_000) }]); // #endregion // #region typedoc:Predicate-triple @@ -378,12 +377,20 @@ it.skip('can create a predicate and use', async () => { { typeId: 0, type: 'bool', - components: null, - typeParameters: null, }, { typeId: 1, - type: '[b512; 3]', + type: 'b512', + }, + { + typeId: 2, + type: '[_; 3]', + components: [ + { + name: '__array_element', + type: 1, + }, + ], }, ], functions: [ @@ -391,38 +398,38 @@ it.skip('can create a predicate and use', async () => { inputs: [ { name: 'data', - type: 1, - typeArguments: null, + type: 2, }, ], name: 'main', output: { name: '', type: 0, - typeArguments: null, }, }, ], loggedTypes: [], }; const predicate = new Predicate(predicateTriple, AbiInputs); - const amountToPredicate = 1000; - const assetId = NativeAssetId; - const initialPredicateBalance = await provider.getBalance(predicate.address, assetId); + const amountToPredicate = 1_000_000; + const amountToReceiver = 100; + const initialPredicateBalance = await predicate.getBalance(); // #endregion // #region typedoc:Predicate-triple-transfer - const response = await wallet1.transfer(predicate.address, amountToPredicate, assetId); + const response = await wallet1.transfer(predicate.address, amountToPredicate); await response.wait(); - const predicateBalance = await provider.getBalance(predicate.address, assetId); + const predicateBalance = await predicate.getBalance(); // assert that predicate address now has the expected amount to predicate expect(bn(predicateBalance)).toEqual(initialPredicateBalance.add(amountToPredicate)); // #endregion // #region typedoc:Predicate-triple-submit - await predicate.transfer(predicate.address, 200); - const updatedPredicateBalance = await predicate.getBalance(assetId); + const depositOnPredicate = await await wallet1.transfer(predicate.address, 200); + // Wait for Transaction to succeed + await depositOnPredicate.waitForResult(); + const updatedPredicateBalance = await predicate.getBalance(); // assert that predicate address now has the updated expected amount to predicate expect(bn(updatedPredicateBalance)).toEqual( @@ -440,16 +447,17 @@ it.skip('can create a predicate and use', async () => { // #endregion // #region typedoc:Predicate-triple-spend - await predicate.setData(signatures).transfer(receiver.address, updatedPredicateBalance); + const tx = await predicate.setData(signatures).transfer(receiver.address, amountToReceiver); + await tx.waitForResult(); // check balances - const finalPredicateBalance = await provider.getBalance(predicate.address, assetId); - const receiverBalance = await provider.getBalance(receiver.address, assetId); + const finalPredicateBalance = await predicate.getBalance(); + const receiverBalance = await receiver.getBalance(); // assert that predicate address now has a zero balance - expect(bn(finalPredicateBalance)).toEqual(bn(0)); + expect(bn(initialPredicateBalance).lte(finalPredicateBalance)).toBeTruthy(); // assert that predicate funds now belong to the receiver - expect(bn(receiverBalance)).toEqual(bn(updatedPredicateBalance)); + expect(bn(receiverBalance).gte(bn(amountToReceiver))).toBeTruthy(); // #endregion }); diff --git a/packages/fuel-gauge/test-projects/predicate-triple-sig/src/main.sw b/packages/fuel-gauge/test-projects/predicate-triple-sig/src/main.sw index b4f98c6cefe..f3dd807b68a 100644 --- a/packages/fuel-gauge/test-projects/predicate-triple-sig/src/main.sw +++ b/packages/fuel-gauge/test-projects/predicate-triple-sig/src/main.sw @@ -1,10 +1,11 @@ // #region typedoc:Predicate-triple predicate; -use std::{b512::B512, constants::ZERO_B256, ecr::ec_recover_address, inputs::input_predicate_data}; +use std::{b512::B512, ecr::ec_recover_address, inputs::input_predicate_data}; fn extract_pulic_key_and_match(signature: B512, expected_public_key: b256) -> u64 { - if let Result::Ok(pub_key_sig) = ec_recover_address(signature, ZERO_B256) + let message_hash = 0x6aed34e6bddff5e1d872b5d7d5698a7b73abd6f3b33402732edc73ab9ffb9c70; + if let Result::Ok(pub_key_sig) = ec_recover_address(signature, message_hash) { if pub_key_sig.value == expected_public_key { return 1; @@ -17,9 +18,9 @@ fn main() -> bool { let signatures: [B512; 3] = input_predicate_data(0); let public_keys = [ - 0xd58573593432a30a800f97ad32f877425c223a9e427ab557aab5d5bb89156db0, - 0x14df7c7e4e662db31fe2763b1734a3d680e7b743516319a49baaa22b2032a857, - 0x3ff494fb136978c3125844625dad6baf6e87cdb1328c8a51f35bda5afe72425c, + 0xe10f526b192593793b7a1559a391445faba82a1d669e3eb2dcd17f9c121b24b1, + 0x54944e5b8189827e470e5a8bacfc6c3667397dc4e1eef7ef3519d16d6d6c6610, + 0x577e424ee53a16e6a85291feabc8443862495f74ac39a706d2dd0b9fc16955eb, ]; let mut matched_keys = 0; From c79a50e0d05ed7fd00f4e1f723d8c45d852a623f Mon Sep 17 00:00:00 2001 From: luizstacio <luizstacio@gmail.com> Date: Fri, 17 Feb 2023 04:31:31 +0100 Subject: [PATCH 07/20] chore: re-enable utxo --- packages/fuel-gauge/src/contract.test.ts | 11 +++++++---- services/fuel-core/Dockerfile | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/fuel-gauge/src/contract.test.ts b/packages/fuel-gauge/src/contract.test.ts index 3dc7492908e..7cd48f4b06a 100644 --- a/packages/fuel-gauge/src/contract.test.ts +++ b/packages/fuel-gauge/src/contract.test.ts @@ -616,7 +616,7 @@ describe('Contract', () => { const wallet = Wallet.generate(); await seedTestWallet(wallet, [ { - amount: bn(1_000_000_000), + amount: bn(1_000_000), assetId: NativeAssetId, }, ]); @@ -628,8 +628,11 @@ describe('Contract', () => { const transactionRequestParsed = transactionRequestify(txRequestParsed); - const response = await contract.account?.sendTransaction(transactionRequestParsed); - const result = await response?.waitForResult(); + // Fund tx + await wallet.fund(transactionRequestParsed); + // Send tx + const response = await wallet.sendTransaction(transactionRequestParsed); + const result = await response.waitForResult(); expect(result?.status.type).toBe('success'); }); @@ -638,7 +641,7 @@ describe('Contract', () => { const externalWallet = Wallet.generate(); await seedTestWallet(externalWallet, [ { - amount: bn(1_000_000_000), + amount: bn(1_000_000), assetId: NativeAssetId, }, ]); diff --git a/services/fuel-core/Dockerfile b/services/fuel-core/Dockerfile index b75fc5fc548..2050d84e4ff 100644 --- a/services/fuel-core/Dockerfile +++ b/services/fuel-core/Dockerfile @@ -26,6 +26,7 @@ CMD exec ./fuel-core run \ --vm-backtrace \ --poa-instant=true \ --consensus-key ${CONSENSUS_KEY} \ + --utxo-validation \ --chain ./chainConfig.json EXPOSE ${PORT} From 54d95bfd2f03f412c530331dcd59b84edac08500 Mon Sep 17 00:00:00 2001 From: luizstacio <luizstacio@gmail.com> Date: Fri, 17 Feb 2023 18:15:01 +0100 Subject: [PATCH 08/20] test: fix amount on tests --- package.json | 1 + packages/fuel-gauge/src/doc-examples.test.ts | 4 ++-- packages/predicate/src/predicate.test.ts | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 77176f478f0..5fa44928bc1 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "prettier:format": "prettier --write packages", "services:run": "make services-run", "services:clean": "make services-clean", + "services:restart": "run-s services:clean services:run", "changeset:publish": "changeset publish --no-git-tag", "changeset:version-with-docs": "ts-node ./scripts/changeset-version-with-docs", "changeset:next": "ts-node ./scripts/changeset-next", diff --git a/packages/fuel-gauge/src/doc-examples.test.ts b/packages/fuel-gauge/src/doc-examples.test.ts index 4c38c5d2e1a..579c046fb24 100644 --- a/packages/fuel-gauge/src/doc-examples.test.ts +++ b/packages/fuel-gauge/src/doc-examples.test.ts @@ -411,14 +411,14 @@ it('can create a predicate and use', async () => { loggedTypes: [], }; const predicate = new Predicate(predicateTriple, AbiInputs); - const amountToPredicate = 1_000_000; + const amountToPredicate = 100_000; const amountToReceiver = 100; const initialPredicateBalance = await predicate.getBalance(); // #endregion // #region typedoc:Predicate-triple-transfer const response = await wallet1.transfer(predicate.address, amountToPredicate); - await response.wait(); + await response.waitForResult(); const predicateBalance = await predicate.getBalance(); // assert that predicate address now has the expected amount to predicate diff --git a/packages/predicate/src/predicate.test.ts b/packages/predicate/src/predicate.test.ts index 486ef8a04f8..c642e74c184 100644 --- a/packages/predicate/src/predicate.test.ts +++ b/packages/predicate/src/predicate.test.ts @@ -3,7 +3,6 @@ import { hexlify } from '@ethersproject/bytes'; import { Account } from '@fuel-ts/account'; import { Address } from '@fuel-ts/address'; import { bn } from '@fuel-ts/math'; -import type { Resource } from '@fuel-ts/providers'; import { ScriptTransactionRequest, CoinStatus } from '@fuel-ts/providers'; import type { InputCoin } from '@fuel-ts/transactions'; From 3988e5bc136202089690d8c188b239bb1bffe342 Mon Sep 17 00:00:00 2001 From: luizstacio <luizstacio@gmail.com> Date: Fri, 17 Feb 2023 18:28:31 +0100 Subject: [PATCH 09/20] chore: add check for method --- packages/address/src/address.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/address/src/address.ts b/packages/address/src/address.ts index d21356038d1..18ee0dcd90a 100644 --- a/packages/address/src/address.ts +++ b/packages/address/src/address.ts @@ -146,7 +146,7 @@ export default class Address extends AbstractAddress { // If address is a object than we assume it's a AbstractAddress // we don't check by instanceof because it's possible to // that the host app has a different reference to the same class type - if (typeof address !== 'string') { + if (typeof address !== 'string' && 'toB256' in address) { return Address.fromB256(address.toB256()); } if (isPublicKey(address)) { From f6d0b07e52c9d6fc78859d30d5879369fe884b5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luiz=20Est=C3=A1cio=20=7C=20stacio=2Eeth?= <luizstacio@gmail.com> Date: Mon, 20 Feb 2023 15:01:02 -0800 Subject: [PATCH 10/20] Update packages/address/src/address.ts Co-authored-by: Luiz Felipe Bolsoni Gomes <8636507+LuizAsFight@users.noreply.github.com> --- packages/address/src/address.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/address/src/address.ts b/packages/address/src/address.ts index 18ee0dcd90a..936101c205d 100644 --- a/packages/address/src/address.ts +++ b/packages/address/src/address.ts @@ -145,7 +145,7 @@ export default class Address extends AbstractAddress { static fromDynamicInput(address: string | AbstractAddress): Address { // If address is a object than we assume it's a AbstractAddress // we don't check by instanceof because it's possible to - // that the host app has a different reference to the same class type + // the host app to have a different reference to this same class type if (typeof address !== 'string' && 'toB256' in address) { return Address.fromB256(address.toB256()); } From e2fe6abf27206d53732fa77fdee941fb4526bc67 Mon Sep 17 00:00:00 2001 From: luizstacio <luizstacio@gmail.com> Date: Mon, 20 Feb 2023 20:04:23 -0300 Subject: [PATCH 11/20] chore: update docs of account --- packages/account/README.md | 53 +++++++------------- packages/fuel-gauge/src/doc-examples.test.ts | 2 +- 2 files changed, 19 insertions(+), 36 deletions(-) diff --git a/packages/account/README.md b/packages/account/README.md index de9a28bc1fd..bd67e800325 100644 --- a/packages/account/README.md +++ b/packages/account/README.md @@ -1,31 +1,33 @@ -# `@fuel-ts/wallet` +# `@fuel-ts/account` -**@fuel-ts/wallet** is a sub-module for interacting with **Fuel**. +**@fuel-ts/account** is a sub-module for interacting with **Fuel**. -This module contains the class to manage a private key and signing for a standard Externally Owned Account (EOA) +This module contains a class that implements basic Account functionality, including querying the balance of an account and transactions. # Table of contents -- [Documentation](#documentation) -- [Usage](#usage) - - [Installation](#installation) - - [Full SDK Installation](#full-sdk-installation) -- [Contributing](#contributing) -- [Changelog](#changelog) -- [License](#license) +- [`@fuel-ts/account`](#fuel-tsaccount) +- [Table of contents](#table-of-contents) + - [Documentation](#documentation) + - [Usage](#usage) + - [Installation](#installation) + - [Full SDK Installation](#full-sdk-installation) + - [Contributing](#contributing) + - [Changelog](#changelog) + - [License](#license) ## Documentation -See [Fuel-ts Documentation](https://fuellabs.github.io/fuels-ts/packages/fuel-ts-wallet/) +See [Fuel-ts Documentation](https://fuellabs.github.io/fuels-ts/packages/fuel-ts-account/) ## Usage ### Installation ```sh -yarn add @fuel-ts/wallet +yarn add @fuel-ts/account # or -npm add @fuel-ts/wallet +npm add @fuel-ts/account ``` ### Full SDK Installation @@ -38,33 +40,14 @@ yarn add fuels npm add fuels ``` -# Test Utilities - -These test utilities are exported to assist in testing apps using Fuels. - -```ts -import { bn } from "@fuel-ts/math"; -import { NativeAssetId } from "@fuel-ts/constants"; -import { seedTestWallet, generateTestWallet } from "@wallet/test-utils"; - -const provider = new Provider("http://127.0.0.1:4000/graphql"); - -// seeding -const wallet = Wallet.fromPrivateKey("0x...", provider); -seedTestWallet(wallet, [{ assetId: NativeAssetId, amount: bn(100_000) }]); - -// generating -const wallet = await generateTestWallet(provider, [[1_000, NativeAssetId]]); -``` - ## Contributing -In order to contribute to `@fuel-ts/wallet`, please see the main [fuels-ts](https://github.com/FuelLabs/fuels-ts) monorepo. +In order to contribute to `@fuel-ts/account`, please see the main [fuels-ts](https://github.com/FuelLabs/fuels-ts) monorepo. ## Changelog -The `@fuel-ts/wallet` changelog can be found at [CHANGELOG](./CHANGELOG.md). +The `@fuel-ts/account` changelog can be found at [CHANGELOG](./CHANGELOG.md). ## License -The primary license for `@fuel-ts/wallet` is `Apache 2.0`, see [LICENSE](./LICENSE). +The primary license for `@fuel-ts/account` is `Apache 2.0`, see [LICENSE](./LICENSE). diff --git a/packages/fuel-gauge/src/doc-examples.test.ts b/packages/fuel-gauge/src/doc-examples.test.ts index 579c046fb24..cd65a528cc2 100644 --- a/packages/fuel-gauge/src/doc-examples.test.ts +++ b/packages/fuel-gauge/src/doc-examples.test.ts @@ -426,7 +426,7 @@ it('can create a predicate and use', async () => { // #endregion // #region typedoc:Predicate-triple-submit - const depositOnPredicate = await await wallet1.transfer(predicate.address, 200); + const depositOnPredicate = await wallet1.transfer(predicate.address, 200); // Wait for Transaction to succeed await depositOnPredicate.waitForResult(); const updatedPredicateBalance = await predicate.getBalance(); From b6bf8a6efc2595f1abd210cba6e4e98750652fc7 Mon Sep 17 00:00:00 2001 From: luizstacio <luizstacio@gmail.com> Date: Mon, 20 Feb 2023 20:19:52 -0300 Subject: [PATCH 12/20] chore: update fuel-core --- services/fuel-core/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/fuel-core/Dockerfile b/services/fuel-core/Dockerfile index 2050d84e4ff..974b79b1467 100644 --- a/services/fuel-core/Dockerfile +++ b/services/fuel-core/Dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/fuellabs/fuel-core:v0.17.1 +FROM ghcr.io/fuellabs/fuel-core:v0.17.2 ARG IP=0.0.0.0 ARG PORT=4000 From c7b7b708a498c4dbfdd851988632edd716321132 Mon Sep 17 00:00:00 2001 From: luizstacio <luizstacio@gmail.com> Date: Mon, 20 Feb 2023 20:20:05 -0300 Subject: [PATCH 13/20] test: add contract call test using predicate --- packages/fuel-gauge/src/predicate.test.ts | 54 +++++++++++++++++++---- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/packages/fuel-gauge/src/predicate.test.ts b/packages/fuel-gauge/src/predicate.test.ts index e6f0fc6942e..5a2e50f7cf8 100644 --- a/packages/fuel-gauge/src/predicate.test.ts +++ b/packages/fuel-gauge/src/predicate.test.ts @@ -1,17 +1,20 @@ import { generateTestWallet } from '@fuel-ts/wallet/test-utils'; import { readFileSync } from 'fs'; -import { Address, NativeAssetId, bn, toHex, toNumber, Provider, Predicate, Wallet } from 'fuels'; -import type { - AbstractAddress, - BigNumberish, - BN, - BytesLike, - WalletUnlocked, - InputValue, - WalletLocked, +import { + Address, + NativeAssetId, + bn, + toHex, + toNumber, + Provider, + Predicate, + Wallet, + Contract, } from 'fuels'; +import type { BigNumberish, BN, WalletUnlocked, InputValue, WalletLocked } from 'fuels'; import { join } from 'path'; +import contractABIJSON from '../test-projects/call-test-contract/out/debug/call-test-abi.json'; import testPredicateAddress from '../test-projects/predicate-address'; import testPredicateFalse from '../test-projects/predicate-false'; import testPredicateMainArgsStruct from '../test-projects/predicate-main-args-struct'; @@ -20,10 +23,22 @@ import testPredicateStruct from '../test-projects/predicate-struct'; import testPredicateTrue from '../test-projects/predicate-true'; import testPredicateU32 from '../test-projects/predicate-u32'; +import { createSetupConfig } from './utils'; + const testPredicateStructBin = readFileSync( join(__dirname, '../test-projects/predicate-struct/out/debug/predicate-struct.bin') ); +const contractBytecode = readFileSync( + join(__dirname, '../test-projects/call-test-contract/out/debug/call-test.bin') +); + +const setupContract = createSetupConfig({ + contractBytecode, + abi: contractABIJSON, + cache: true, +}); + const setup = async () => { const provider = new Provider('http://127.0.0.1:4000/graphql'); const wallet = await generateTestWallet(provider, [[5_000_000, NativeAssetId]]); @@ -433,4 +448,25 @@ describe('Predicate', () => { }); }).rejects.toThrow(/Invalid transaction/i); }); + + it('Should be able to use a Predicate to call a contract', async () => { + const [wallet] = await setup(); + const contract = await setupContract(); + const amountToPredicate = 100_000; + const predicate = new Predicate<[Validation]>(testPredicateTrue, predicateMainArgsStructAbi); + // Create a instance of the contract with the predicate as the caller Account + const contractPredicate = new Contract(contract.id, contract.interface, predicate); + const predicateBalance = await setupPredicate(wallet, predicate, amountToPredicate); + + const { value } = await contractPredicate.functions + .return_context_amount() + .callParams({ + forward: [500, NativeAssetId], + }) + .call(); + expect(value.toString()).toEqual('500'); + + const finalPredicateBalance = predicate.getBalance(); + expect((await finalPredicateBalance).lt(predicateBalance)).toBeTruthy(); + }); }); From 0c036711c059e3c14310a6f99d650b6174cb2f5a Mon Sep 17 00:00:00 2001 From: luizstacio <luizstacio@gmail.com> Date: Mon, 20 Feb 2023 20:20:50 -0300 Subject: [PATCH 14/20] chore: fix await --- packages/fuel-gauge/src/predicate.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/fuel-gauge/src/predicate.test.ts b/packages/fuel-gauge/src/predicate.test.ts index 5a2e50f7cf8..e128e3c1727 100644 --- a/packages/fuel-gauge/src/predicate.test.ts +++ b/packages/fuel-gauge/src/predicate.test.ts @@ -466,7 +466,7 @@ describe('Predicate', () => { .call(); expect(value.toString()).toEqual('500'); - const finalPredicateBalance = predicate.getBalance(); - expect((await finalPredicateBalance).lt(predicateBalance)).toBeTruthy(); + const finalPredicateBalance = await predicate.getBalance(); + expect(finalPredicateBalance.lt(predicateBalance)).toBeTruthy(); }); }); From cdcf9c61f15a1122a440b8241721a8c1f226f5fe Mon Sep 17 00:00:00 2001 From: luizstacio <luizstacio@gmail.com> Date: Mon, 20 Feb 2023 21:11:51 -0300 Subject: [PATCH 15/20] test: update provider version --- packages/providers/src/provider.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/providers/src/provider.test.ts b/packages/providers/src/provider.test.ts index 297913c13d2..b5196b81ee8 100644 --- a/packages/providers/src/provider.test.ts +++ b/packages/providers/src/provider.test.ts @@ -14,7 +14,7 @@ describe('Provider', () => { const version = await provider.getVersion(); - expect(version).toEqual('0.17.1'); + expect(version).toEqual('0.17.2'); }); it('can call()', async () => { From e7624a1bd5cb9cfa096008ef275da416346ab4ba Mon Sep 17 00:00:00 2001 From: luizstacio <luizstacio@gmail.com> Date: Tue, 21 Feb 2023 11:10:40 -0300 Subject: [PATCH 16/20] refact: move account to wallet package --- packages/account/LICENSE | 201 ------------------ packages/account/README.md | 53 ----- packages/account/package.json | 42 ---- packages/account/src/constants.ts | 2 - packages/account/src/index.ts | 1 - packages/account/tsconfig.json | 10 - packages/account/tsup.config.ts | 13 -- packages/contract/package.json | 3 +- .../src/contracts/contract-factory.ts | 2 +- .../contract/src/contracts/contract.test.ts | 3 +- packages/contract/src/contracts/contract.ts | 2 +- packages/fuels/package.json | 1 - packages/fuels/src/index.ts | 1 - packages/predicate/package.json | 2 +- packages/predicate/src/predicate.test.ts | 2 +- packages/predicate/src/predicate.ts | 2 +- packages/script/package.json | 3 +- packages/script/src/script.test.ts | 2 +- packages/wallet/package.json | 4 +- .../{account => wallet}/src/account.test.ts | 0 packages/{account => wallet}/src/account.ts | 0 packages/wallet/src/base-unlocked-wallet.ts | 2 +- packages/wallet/src/index.ts | 1 + packages/wallet/src/wallets.ts | 2 +- pnpm-lock.yaml | 32 +-- 25 files changed, 15 insertions(+), 371 deletions(-) delete mode 100644 packages/account/LICENSE delete mode 100644 packages/account/README.md delete mode 100644 packages/account/package.json delete mode 100644 packages/account/src/constants.ts delete mode 100644 packages/account/src/index.ts delete mode 100644 packages/account/tsconfig.json delete mode 100644 packages/account/tsup.config.ts rename packages/{account => wallet}/src/account.test.ts (100%) rename packages/{account => wallet}/src/account.ts (100%) diff --git a/packages/account/LICENSE b/packages/account/LICENSE deleted file mode 100644 index 261eeb9e9f8..00000000000 --- a/packages/account/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/packages/account/README.md b/packages/account/README.md deleted file mode 100644 index bd67e800325..00000000000 --- a/packages/account/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# `@fuel-ts/account` - -**@fuel-ts/account** is a sub-module for interacting with **Fuel**. - -This module contains a class that implements basic Account functionality, including querying the balance of an account and transactions. - -# Table of contents - -- [`@fuel-ts/account`](#fuel-tsaccount) -- [Table of contents](#table-of-contents) - - [Documentation](#documentation) - - [Usage](#usage) - - [Installation](#installation) - - [Full SDK Installation](#full-sdk-installation) - - [Contributing](#contributing) - - [Changelog](#changelog) - - [License](#license) - -## Documentation - -See [Fuel-ts Documentation](https://fuellabs.github.io/fuels-ts/packages/fuel-ts-account/) - -## Usage - -### Installation - -```sh -yarn add @fuel-ts/account -# or -npm add @fuel-ts/account -``` - -### Full SDK Installation - -Alternatively, we recommend you install the [complete SDK](https://github.com/FuelLabs/fuels-ts) using the umbrella package: - -```sh -yarn add fuels -# or -npm add fuels -``` - -## Contributing - -In order to contribute to `@fuel-ts/account`, please see the main [fuels-ts](https://github.com/FuelLabs/fuels-ts) monorepo. - -## Changelog - -The `@fuel-ts/account` changelog can be found at [CHANGELOG](./CHANGELOG.md). - -## License - -The primary license for `@fuel-ts/account` is `Apache 2.0`, see [LICENSE](./LICENSE). diff --git a/packages/account/package.json b/packages/account/package.json deleted file mode 100644 index 7200ee8099c..00000000000 --- a/packages/account/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "@fuel-ts/account", - "version": "0.31.0", - "description": "Base Account Class for Fuel", - "author": "Fuel Labs <contact@fuel.sh> (https://fuel.network/)", - "typedoc": { - "entryPoint": "./src/index.ts" - }, - "main": "src/index.ts", - "exports": { - ".": { - "require": "./dist/index.js", - "default": "./dist/index.mjs" - }, - "./test-utils": { - "require": "./dist/test-utils.js", - "default": "./dist/test-utils.mjs" - } - }, - "publishConfig": { - "main": "dist/index.js", - "module": "dist/index.mjs", - "types": "dist/index.d.ts", - "typings": "dist/index.d.ts" - }, - "files": [ - "dist" - ], - "license": "Apache-2.0", - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@fuel-ts/address": "workspace:*", - "@fuel-ts/constants": "workspace:*", - "@fuel-ts/interfaces": "workspace:*", - "@fuel-ts/math": "workspace:*", - "@fuel-ts/providers": "workspace:*", - "@fuel-ts/transactions": "workspace:*" - }, - "scripts": { - "build": "tsup --dts" - } -} diff --git a/packages/account/src/constants.ts b/packages/account/src/constants.ts deleted file mode 100644 index ce37157f9a6..00000000000 --- a/packages/account/src/constants.ts +++ /dev/null @@ -1,2 +0,0 @@ -// TODO: import using .env file -export const FUEL_NETWORK_URL = 'http://127.0.0.1:4000/graphql'; diff --git a/packages/account/src/index.ts b/packages/account/src/index.ts deleted file mode 100644 index 362a768e537..00000000000 --- a/packages/account/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './account'; diff --git a/packages/account/tsconfig.json b/packages/account/tsconfig.json deleted file mode 100644 index c6f86db2c6b..00000000000 --- a/packages/account/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "downlevelIteration": true, - "outDir": "./dist", - "rootDir": "./", - "baseUrl": "./" - }, - "include": ["src", "test"] -} diff --git a/packages/account/tsup.config.ts b/packages/account/tsup.config.ts deleted file mode 100644 index c140f934706..00000000000 --- a/packages/account/tsup.config.ts +++ /dev/null @@ -1,13 +0,0 @@ -// eslint-disable-next-line import/no-extraneous-dependencies -import { defineConfig } from 'tsup'; - -export default defineConfig((options) => ({ - entry: { - index: 'src/index.ts', - }, - format: ['cjs', 'esm', 'iife'], - splitting: false, - sourcemap: true, - clean: false, - minify: !options.watch, -})); diff --git a/packages/contract/package.json b/packages/contract/package.json index 866ca5215c7..535392f110b 100644 --- a/packages/contract/package.json +++ b/packages/contract/package.json @@ -41,8 +41,7 @@ "@fuel-ts/sparsemerkle": "workspace:*", "@fuel-ts/wallet": "workspace:*", "@fuel-ts/transactions": "workspace:*", - "@fuel-ts/versions": "workspace:*", - "@fuel-ts/account": "workspace:*" + "@fuel-ts/versions": "workspace:*" }, "devDependencies": { "forc-bin": "workspace:*" diff --git a/packages/contract/src/contracts/contract-factory.ts b/packages/contract/src/contracts/contract-factory.ts index 014f7cc66c7..1ab3f7974e5 100644 --- a/packages/contract/src/contracts/contract-factory.ts +++ b/packages/contract/src/contracts/contract-factory.ts @@ -3,13 +3,13 @@ import { arrayify } from '@ethersproject/bytes'; import { Logger } from '@ethersproject/logger'; import { Interface } from '@fuel-ts/abi-coder'; import type { JsonAbi } from '@fuel-ts/abi-coder'; -import type { Account } from '@fuel-ts/account'; import { randomBytes } from '@fuel-ts/keystore'; import type { CreateTransactionRequestLike, Provider } from '@fuel-ts/providers'; import { CreateTransactionRequest } from '@fuel-ts/providers'; import type { StorageSlot } from '@fuel-ts/transactions'; import { MAX_GAS_PER_TX } from '@fuel-ts/transactions'; import { versions } from '@fuel-ts/versions'; +import type { Account } from '@fuel-ts/wallet'; import { getContractId, getContractStorageRoot, includeHexPrefix } from '../util'; diff --git a/packages/contract/src/contracts/contract.test.ts b/packages/contract/src/contracts/contract.test.ts index 44b53553571..7289a6c1462 100644 --- a/packages/contract/src/contracts/contract.test.ts +++ b/packages/contract/src/contracts/contract.test.ts @@ -1,6 +1,5 @@ -import { Account } from '@fuel-ts/account'; import { Provider } from '@fuel-ts/providers'; -import { Wallet } from '@fuel-ts/wallet'; +import { Account, Wallet } from '@fuel-ts/wallet'; import Contract from './contract'; diff --git a/packages/contract/src/contracts/contract.ts b/packages/contract/src/contracts/contract.ts index 40759de7a66..5a6495004a8 100644 --- a/packages/contract/src/contracts/contract.ts +++ b/packages/contract/src/contracts/contract.ts @@ -1,10 +1,10 @@ import type { BytesLike } from '@ethersproject/bytes'; import type { FunctionFragment, JsonAbi, JsonFlatAbi } from '@fuel-ts/abi-coder'; import { Interface } from '@fuel-ts/abi-coder'; -import type { Account } from '@fuel-ts/account'; import { Address } from '@fuel-ts/address'; import type { AbstractAddress, AbstractContract } from '@fuel-ts/interfaces'; import type { Provider } from '@fuel-ts/providers'; +import type { Account } from '@fuel-ts/wallet'; import type { InvokeFunctions } from '../types'; diff --git a/packages/fuels/package.json b/packages/fuels/package.json index 0445128ef54..c13a307e139 100644 --- a/packages/fuels/package.json +++ b/packages/fuels/package.json @@ -51,7 +51,6 @@ "@fuel-ts/wallet": "workspace:*", "@fuel-ts/wallet-manager": "workspace:*", "@fuel-ts/wordlists": "workspace:*", - "@fuel-ts/account": "workspace:*", "commander": "^9.4.1" }, "scripts": { diff --git a/packages/fuels/src/index.ts b/packages/fuels/src/index.ts index 15b54d0d911..a6ff9c2050a 100644 --- a/packages/fuels/src/index.ts +++ b/packages/fuels/src/index.ts @@ -3,7 +3,6 @@ export * from '@fuel-ts/abi-coder'; export * from '@fuel-ts/address'; export * from '@fuel-ts/constants'; export * from '@fuel-ts/contract'; -export * from '@fuel-ts/account'; export * from '@fuel-ts/predicate'; export * from '@fuel-ts/hasher'; export * from '@fuel-ts/interfaces'; diff --git a/packages/predicate/package.json b/packages/predicate/package.json index 0c51ec5dc6c..3f97f500000 100644 --- a/packages/predicate/package.json +++ b/packages/predicate/package.json @@ -30,7 +30,7 @@ "@fuel-ts/address": "workspace:*", "@fuel-ts/interfaces": "workspace:*", "@fuel-ts/versions": "workspace:*", - "@fuel-ts/account": "workspace:*", + "@fuel-ts/wallet": "workspace:*", "@fuel-ts/providers": "workspace:*", "@fuel-ts/transactions": "workspace:*", "@fuel-ts/merkle": "workspace:*" diff --git a/packages/predicate/src/predicate.test.ts b/packages/predicate/src/predicate.test.ts index c642e74c184..2b73f26f83b 100644 --- a/packages/predicate/src/predicate.test.ts +++ b/packages/predicate/src/predicate.test.ts @@ -1,10 +1,10 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { hexlify } from '@ethersproject/bytes'; -import { Account } from '@fuel-ts/account'; import { Address } from '@fuel-ts/address'; import { bn } from '@fuel-ts/math'; import { ScriptTransactionRequest, CoinStatus } from '@fuel-ts/providers'; import type { InputCoin } from '@fuel-ts/transactions'; +import { Account } from '@fuel-ts/wallet'; import { Predicate } from './predicate'; diff --git a/packages/predicate/src/predicate.ts b/packages/predicate/src/predicate.ts index 7d8bfcfe392..cafa00463bb 100644 --- a/packages/predicate/src/predicate.ts +++ b/packages/predicate/src/predicate.ts @@ -3,7 +3,6 @@ import { hexlify, arrayify } from '@ethersproject/bytes'; import { Logger } from '@ethersproject/logger'; import { AbiCoder, Interface } from '@fuel-ts/abi-coder'; import type { JsonAbiFragmentType, JsonAbi, InputValue } from '@fuel-ts/abi-coder'; -import { Account } from '@fuel-ts/account'; import { Address } from '@fuel-ts/address'; import type { CallResult, @@ -14,6 +13,7 @@ import type { import { transactionRequestify } from '@fuel-ts/providers'; import { InputType } from '@fuel-ts/transactions'; import { versions } from '@fuel-ts/versions'; +import { Account } from '@fuel-ts/wallet'; import { getContractRoot } from './utils'; diff --git a/packages/script/package.json b/packages/script/package.json index 732879d2042..d03c99eafc3 100644 --- a/packages/script/package.json +++ b/packages/script/package.json @@ -35,8 +35,7 @@ "@fuel-ts/math": "workspace:*", "@fuel-ts/providers": "workspace:*", "@fuel-ts/wallet": "workspace:*", - "@fuel-ts/transactions": "workspace:*", - "@fuel-ts/account": "workspace:*" + "@fuel-ts/transactions": "workspace:*" }, "devDependencies": { "forc-bin": "workspace:*" diff --git a/packages/script/src/script.test.ts b/packages/script/src/script.test.ts index b6b481144ad..33cec184059 100644 --- a/packages/script/src/script.test.ts +++ b/packages/script/src/script.test.ts @@ -1,13 +1,13 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { arrayify } from '@ethersproject/bytes'; import { AbiCoder } from '@fuel-ts/abi-coder'; -import type { Account } from '@fuel-ts/account'; import { NativeAssetId } from '@fuel-ts/constants'; import type { BigNumberish } from '@fuel-ts/math'; import { bn } from '@fuel-ts/math'; import type { CoinQuantityLike, TransactionResponse, TransactionResult } from '@fuel-ts/providers'; import { Provider, ScriptTransactionRequest } from '@fuel-ts/providers'; import { ReceiptType } from '@fuel-ts/transactions'; +import type { Account } from '@fuel-ts/wallet'; import { generateTestWallet } from '@fuel-ts/wallet/test-utils'; import { readFileSync } from 'fs'; import { join } from 'path'; diff --git a/packages/wallet/package.json b/packages/wallet/package.json index 9cc93adbcbf..9177564faea 100644 --- a/packages/wallet/package.json +++ b/packages/wallet/package.json @@ -39,9 +39,7 @@ "@fuel-ts/mnemonic": "workspace:*", "@fuel-ts/providers": "workspace:*", "@fuel-ts/signer": "workspace:*", - "@fuel-ts/transactions": "workspace:*", - "@fuel-ts/predicate": "workspace:*", - "@fuel-ts/account": "workspace:*" + "@fuel-ts/transactions": "workspace:*" }, "devDependencies": { "@fuel-ts/address": "workspace:*", diff --git a/packages/account/src/account.test.ts b/packages/wallet/src/account.test.ts similarity index 100% rename from packages/account/src/account.test.ts rename to packages/wallet/src/account.test.ts diff --git a/packages/account/src/account.ts b/packages/wallet/src/account.ts similarity index 100% rename from packages/account/src/account.ts rename to packages/wallet/src/account.ts diff --git a/packages/wallet/src/base-unlocked-wallet.ts b/packages/wallet/src/base-unlocked-wallet.ts index a3a42f7688e..e3081328337 100644 --- a/packages/wallet/src/base-unlocked-wallet.ts +++ b/packages/wallet/src/base-unlocked-wallet.ts @@ -1,5 +1,4 @@ import type { BytesLike } from '@ethersproject/bytes'; -import { Account } from '@fuel-ts/account'; import { hashMessage, hashTransaction } from '@fuel-ts/hasher'; import type { TransactionResponse, @@ -10,6 +9,7 @@ import type { import { transactionRequestify } from '@fuel-ts/providers'; import { Signer } from '@fuel-ts/signer'; +import { Account } from './account'; import { FUEL_NETWORK_URL } from './constants'; /** diff --git a/packages/wallet/src/index.ts b/packages/wallet/src/index.ts index 79311c9b16c..9e755c6bed0 100644 --- a/packages/wallet/src/index.ts +++ b/packages/wallet/src/index.ts @@ -1,3 +1,4 @@ export * from './base-unlocked-wallet'; +export * from './account'; export * from './wallet'; export * from './wallets'; diff --git a/packages/wallet/src/wallets.ts b/packages/wallet/src/wallets.ts index a8558dd7d68..dc3de3dec36 100644 --- a/packages/wallet/src/wallets.ts +++ b/packages/wallet/src/wallets.ts @@ -4,12 +4,12 @@ // /* eslint-disable max-classes-per-file */ import type { BytesLike } from '@ethersproject/bytes'; -import { Account } from '@fuel-ts/account'; import { HDWallet } from '@fuel-ts/hdwallet'; import { Mnemonic } from '@fuel-ts/mnemonic'; import type { Provider } from '@fuel-ts/providers'; import { Signer } from '@fuel-ts/signer'; +import { Account } from './account'; import { BaseWalletUnlocked } from './base-unlocked-wallet'; import type { GenerateOptions } from './types/GenerateOptions'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ae863252383..74ac5a0ae0e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -153,24 +153,6 @@ importers: '@types/rimraf': 3.0.2 forc-bin: link:../forc-bin - packages/account: - specifiers: - '@ethersproject/bytes': ^5.7.0 - '@fuel-ts/address': workspace:* - '@fuel-ts/constants': workspace:* - '@fuel-ts/interfaces': workspace:* - '@fuel-ts/math': workspace:* - '@fuel-ts/providers': workspace:* - '@fuel-ts/transactions': workspace:* - dependencies: - '@ethersproject/bytes': 5.7.0 - '@fuel-ts/address': link:../address - '@fuel-ts/constants': link:../constants - '@fuel-ts/interfaces': link:../interfaces - '@fuel-ts/math': link:../math - '@fuel-ts/providers': link:../providers - '@fuel-ts/transactions': link:../transactions - packages/address: specifiers: '@ethersproject/bytes': ^5.7.0 @@ -201,7 +183,6 @@ importers: '@ethersproject/logger': ^5.7.0 '@ethersproject/sha2': ^5.7.0 '@fuel-ts/abi-coder': workspace:* - '@fuel-ts/account': workspace:* '@fuel-ts/address': workspace:* '@fuel-ts/interfaces': workspace:* '@fuel-ts/keystore': workspace:* @@ -219,7 +200,6 @@ importers: '@ethersproject/logger': 5.7.0 '@ethersproject/sha2': 5.7.0 '@fuel-ts/abi-coder': link:../abi-coder - '@fuel-ts/account': link:../account '@fuel-ts/address': link:../address '@fuel-ts/interfaces': link:../interfaces '@fuel-ts/keystore': link:../keystore @@ -275,7 +255,6 @@ importers: '@ethersproject/bytes': ^5.7.0 '@fuel-ts/abi-coder': workspace:* '@fuel-ts/abi-typegen': workspace:* - '@fuel-ts/account': workspace:* '@fuel-ts/address': workspace:* '@fuel-ts/constants': workspace:* '@fuel-ts/contract': workspace:* @@ -304,7 +283,6 @@ importers: '@ethersproject/bytes': 5.7.0 '@fuel-ts/abi-coder': link:../abi-coder '@fuel-ts/abi-typegen': link:../abi-typegen - '@fuel-ts/account': link:../account '@fuel-ts/address': link:../address '@fuel-ts/constants': link:../constants '@fuel-ts/contract': link:../contract @@ -435,7 +413,6 @@ importers: '@ethersproject/bytes': ^5.7.0 '@ethersproject/logger': ^5.7.0 '@fuel-ts/abi-coder': workspace:* - '@fuel-ts/account': workspace:* '@fuel-ts/address': workspace:* '@fuel-ts/interfaces': workspace:* '@fuel-ts/math': workspace:* @@ -443,17 +420,18 @@ importers: '@fuel-ts/providers': workspace:* '@fuel-ts/transactions': workspace:* '@fuel-ts/versions': workspace:* + '@fuel-ts/wallet': workspace:* dependencies: '@ethersproject/bytes': 5.7.0 '@ethersproject/logger': 5.7.0 '@fuel-ts/abi-coder': link:../abi-coder - '@fuel-ts/account': link:../account '@fuel-ts/address': link:../address '@fuel-ts/interfaces': link:../interfaces '@fuel-ts/merkle': link:../merkle '@fuel-ts/providers': link:../providers '@fuel-ts/transactions': link:../transactions '@fuel-ts/versions': link:../versions + '@fuel-ts/wallet': link:../wallet devDependencies: '@fuel-ts/math': link:../math @@ -508,7 +486,6 @@ importers: specifiers: '@ethersproject/bytes': ^5.7.0 '@fuel-ts/abi-coder': workspace:* - '@fuel-ts/account': workspace:* '@fuel-ts/constants': workspace:* '@fuel-ts/math': workspace:* '@fuel-ts/providers': workspace:* @@ -518,7 +495,6 @@ importers: dependencies: '@ethersproject/bytes': 5.7.0 '@fuel-ts/abi-coder': link:../abi-coder - '@fuel-ts/account': link:../account '@fuel-ts/constants': link:../constants '@fuel-ts/math': link:../math '@fuel-ts/providers': link:../providers @@ -594,7 +570,6 @@ importers: specifiers: '@ethersproject/bytes': ^5.7.0 '@fuel-ts/abi-coder': workspace:* - '@fuel-ts/account': workspace:* '@fuel-ts/address': workspace:* '@fuel-ts/constants': workspace:* '@fuel-ts/hasher': workspace:* @@ -603,7 +578,6 @@ importers: '@fuel-ts/keystore': workspace:* '@fuel-ts/math': workspace:* '@fuel-ts/mnemonic': workspace:* - '@fuel-ts/predicate': workspace:* '@fuel-ts/providers': workspace:* '@fuel-ts/signer': workspace:* '@fuel-ts/testcases': workspace:* @@ -611,7 +585,6 @@ importers: dependencies: '@ethersproject/bytes': 5.7.0 '@fuel-ts/abi-coder': link:../abi-coder - '@fuel-ts/account': link:../account '@fuel-ts/address': link:../address '@fuel-ts/constants': link:../constants '@fuel-ts/hasher': link:../hasher @@ -619,7 +592,6 @@ importers: '@fuel-ts/interfaces': link:../interfaces '@fuel-ts/math': link:../math '@fuel-ts/mnemonic': link:../mnemonic - '@fuel-ts/predicate': link:../predicate '@fuel-ts/providers': link:../providers '@fuel-ts/signer': link:../signer '@fuel-ts/transactions': link:../transactions From 63b61dcb827bc74ca762121bf091ba06c364c555 Mon Sep 17 00:00:00 2001 From: luizstacio <luizstacio@gmail.com> Date: Tue, 21 Feb 2023 11:11:27 -0300 Subject: [PATCH 17/20] chore: fix changesets --- .changeset/clever-chefs-shop.md | 2 +- .changeset/curly-eggs-think.md | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 .changeset/curly-eggs-think.md diff --git a/.changeset/clever-chefs-shop.md b/.changeset/clever-chefs-shop.md index b09c716af6a..34450f4104f 100644 --- a/.changeset/clever-chefs-shop.md +++ b/.changeset/clever-chefs-shop.md @@ -2,4 +2,4 @@ "@fuel-ts/wallet": minor --- -Remove BaseWalletLocked and use Account package +Create Account pacakge. Moves BaseWalletLocked to a sperate package. diff --git a/.changeset/curly-eggs-think.md b/.changeset/curly-eggs-think.md deleted file mode 100644 index 4297d86662e..00000000000 --- a/.changeset/curly-eggs-think.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fuel-ts/account": minor ---- - -Create Account pacakge. Moves BaseWalletLocked to a sperate package. From b3658f7a62979c0e89ef1c3ce87558615219af91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luiz=20Est=C3=A1cio=20=7C=20stacio=2Eeth?= <luizstacio@gmail.com> Date: Tue, 21 Feb 2023 10:23:56 -0800 Subject: [PATCH 18/20] Update .changeset/clever-chefs-shop.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> --- .changeset/clever-chefs-shop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/clever-chefs-shop.md b/.changeset/clever-chefs-shop.md index 34450f4104f..c1853f1bf57 100644 --- a/.changeset/clever-chefs-shop.md +++ b/.changeset/clever-chefs-shop.md @@ -2,4 +2,4 @@ "@fuel-ts/wallet": minor --- -Create Account pacakge. Moves BaseWalletLocked to a sperate package. +Renaming BaseWalletLocked class to Account while abstracting common code. From f303eaec66cceec50534ae1f440674ab568b58aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luiz=20Est=C3=A1cio=20=7C=20stacio=2Eeth?= <luizstacio@gmail.com> Date: Tue, 21 Feb 2023 10:24:03 -0800 Subject: [PATCH 19/20] Update .changeset/honest-ways-learn.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> --- .changeset/honest-ways-learn.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/honest-ways-learn.md b/.changeset/honest-ways-learn.md index 49dba8a5c77..448182483d2 100644 --- a/.changeset/honest-ways-learn.md +++ b/.changeset/honest-ways-learn.md @@ -2,4 +2,4 @@ "fuels": minor --- -Add packages Account and Predicate to exports +Adding missing export for package Predicate. From c6d7c9ce5bab46149df381a3dcd7dfe332517e9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luiz=20Est=C3=A1cio=20=7C=20stacio=2Eeth?= <luizstacio@gmail.com> Date: Tue, 21 Feb 2023 10:24:09 -0800 Subject: [PATCH 20/20] Update .changeset/nine-bottles-jog.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> --- .changeset/nine-bottles-jog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/nine-bottles-jog.md b/.changeset/nine-bottles-jog.md index dac3cb2d562..8cb38f6f9f4 100644 --- a/.changeset/nine-bottles-jog.md +++ b/.changeset/nine-bottles-jog.md @@ -7,4 +7,4 @@ "@fuel-ts/script": minor --- -Update use of BaseWalletLocked to Account +Updating usages of BaseWalletLocked after renaming it to Account