Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement generateFakeResources on Account class #2351

Merged
merged 36 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
e71717a
add generateFakeResources to Account class
Torres-ssf May 20, 2024
809e974
add generateFakeResources to Predicate class
Torres-ssf May 20, 2024
ea4661a
add test case
Torres-ssf May 20, 2024
b37a4bb
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf May 20, 2024
fe85f09
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf May 21, 2024
5f0ba78
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf May 21, 2024
58fe72c
fix method type signature
Torres-ssf May 21, 2024
03624af
add test suite
Torres-ssf May 21, 2024
a74af46
liniting
Torres-ssf May 21, 2024
e3abd53
add test group to test suite
Torres-ssf May 21, 2024
e28b0cb
add changeset
Torres-ssf May 21, 2024
fe9980a
fix changeset
Torres-ssf May 21, 2024
a8ff230
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf May 21, 2024
3d5738c
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf May 22, 2024
6cb2260
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf May 22, 2024
0524495
refact test
Torres-ssf May 22, 2024
a2b87f9
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf May 23, 2024
5bc4020
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
petertonysmith94 May 23, 2024
4c59623
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf May 23, 2024
db61cbb
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf May 24, 2024
5d4ddb1
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf May 27, 2024
a4dc1db
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf May 28, 2024
a298df4
add script to doc snippets
Torres-ssf May 28, 2024
33c4639
add doc page
Torres-ssf May 28, 2024
d73ad04
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf May 28, 2024
f76d8f5
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf May 28, 2024
2be51f8
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
petertonysmith94 May 29, 2024
32023c4
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf May 29, 2024
902a21a
add test group
Torres-ssf May 29, 2024
864357f
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
petertonysmith94 May 30, 2024
4b87af6
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf May 30, 2024
8955f97
fix funding amounts
Torres-ssf May 30, 2024
ef63351
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf May 30, 2024
3b17514
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf Jun 4, 2024
9455713
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf Jun 6, 2024
d71ab2a
Merge branch 'master' into st/feat/add-generate-fake-resources-to-acc…
Torres-ssf Jun 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lazy-readers-flash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@fuel-ts/account": patch
---

feat: implement `generateFakeResources` on `Account` class
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import type { TransactionResultReturnDataReceipt } from 'fuels';
import {
FUEL_NETWORK_URL,
Provider,
ReceiptType,
ScriptTransactionRequest,
Wallet,
bn,
} from 'fuels';

import {
DocSnippetProjectsEnum,
getDocsSnippetsForcProject,
} from '../../../test/fixtures/forc-projects';

/**
* @group node
*/
describe(__filename, () => {
it('should generate fake resources just fine', async () => {
const provider = await Provider.create(FUEL_NETWORK_URL);
const wallet = Wallet.generate({ provider });
const baseAssetId = provider.getBaseAssetId();

const { binHexlified: scriptHexBytes } = getDocsSnippetsForcProject(
DocSnippetProjectsEnum.RETURN_SCRIPT
);

// #region generate-fake-resources-2
const transactionRequest = new ScriptTransactionRequest({
gasLimit: bn(62_000),
maxFee: bn(60_000),
script: scriptHexBytes,
});

const resources = wallet.generateFakeResources([
{
amount: bn(100_000),
assetId: baseAssetId,
},
]);

transactionRequest.addResources(resources);

const dryrunResult = await provider.call(transactionRequest);

const returnReceipt = dryrunResult.receipts.find(
(receipt) => receipt.type === ReceiptType.ReturnData
) as TransactionResultReturnDataReceipt;

const { data: returnedValue } = returnReceipt;
// #endregion generate-fake-resources-2

expect(bn(returnedValue).toNumber()).toBe(1337);
expect(dryrunResult.dryRunStatus?.type).toBe('DryRunSuccessStatus');
});
});
1 change: 1 addition & 0 deletions apps/docs-snippets/test/fixtures/forc-projects/Forc.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ members = [
"simple-token-abi",
"echo-configurables",
"transfer-to-address",
"return-script",
"return-true-predicate",
"echo-employee-data-vector",
"whitelisted-address-predicate",
Expand Down
1 change: 1 addition & 0 deletions apps/docs-snippets/test/fixtures/forc-projects/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export enum DocSnippetProjectsEnum {
SUM_OPTION_U8 = 'sum-option-u8',
ECHO_U64_ARRAY = 'echo-u64-array',
RETURN_CONTEXT = 'return-context',
RETURN_SCRIPT = 'return-script',
TOKEN_DEPOSITOR = 'token-depositor',
TOKEN = 'token',
LIQUIDITY_POOL = 'liquidity-pool',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[project]
entry = "main.sw"
license = "Apache-2.0"
name = "return-script"

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// #region generate-fake-resources-1
script;

fn main() -> u64 {
return 1337;
}
// #endregion generate-fake-resources-1
4 changes: 4 additions & 0 deletions apps/docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,10 @@ export default defineConfig({
text: 'Custom Transactions from Contract Calls',
link: '/guide/cookbook/custom-transactions-from-contract-calls',
},
{
text: 'Generate Fake Resources',
link: '/guide/cookbook/generate-fake-resources',
},
{
text: 'Transactions with Multiple Signers',
link: '/guide/cookbook/transactions-with-multiple-signers',
Expand Down
13 changes: 13 additions & 0 deletions apps/docs/src/guide/cookbook/generate-fake-resources.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Generate Fake Resources

When working with an unfunded account, you can generate fake resources to perform a dry-run on your transactions. This is useful for testing purposes without the need for real funds.

Below is an example script that returns the value `1337`. You can use fake resources to execute a dry-run of this script and obtain the returned value.

<<< @/../../docs-snippets/test/fixtures/forc-projects/return-script/src/main.sw#generate-fake-resources-1{rust:line-numbers}

To execute a dry-run, use the `Provider.call` method. Ensure you set the `utxo_validation` flag to true, as this script uses fake UTXOs:
arboleya marked this conversation as resolved.
Show resolved Hide resolved

<<< @/../../docs-snippets/src/guide/cookbook/generate-fake-resources.test.ts#generate-fake-resources-2{ts:line-numbers}

By setting `utxo_validation` to `true`, you can successfully execute the dry-run and retrieve the returned value from the script without requiring actual funds.
37 changes: 36 additions & 1 deletion packages/account/src/account.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { bn } from '@fuel-ts/math';
import { PolicyType } from '@fuel-ts/transactions';
import { ASSET_A, ASSET_B } from '@fuel-ts/utils/test-utils';

import type { TransferParams } from './account';
import type { FakeResources, TransferParams } from './account';
import { Account } from './account';
import { FUEL_NETWORK_URL } from './configs';
import { ScriptTransactionRequest, Provider } from './providers';
Expand Down Expand Up @@ -659,6 +659,41 @@ describe('Account', () => {
expect(receiverBalances).toEqual([{ assetId: baseAssetId, amount: bn(110) }]);
});

it('can generate and use fake coins', async () => {
const sender = Wallet.generate({
provider,
});

const amount1 = bn(100_000);
const amount2 = bn(200_000);
const amount3 = bn(300_000);
const amountToTransferBaseAsset = bn(1000);

const fakeCoinsConfig: FakeResources[] = [
{ amount: amount1, assetId: baseAssetId },
{ amount: amount2, assetId: ASSET_A },
{ amount: amount3, assetId: ASSET_B },
];

const fakeCoins = sender.generateFakeResources(fakeCoinsConfig);
const request = new ScriptTransactionRequest({
gasLimit: bn(60_000),
maxFee: bn(62_000),
});

request.addResources(fakeCoins);
request.addCoinOutput(Address.fromRandom(), amountToTransferBaseAsset, baseAssetId);
request.addCoinOutput(Address.fromRandom(), amount2, ASSET_A);
request.addCoinOutput(Address.fromRandom(), amount3, ASSET_B);

const { dryRunStatus } = await provider.call(request, {
utxoValidation: false,
estimateTxDependencies: false,
});

expect(dryRunStatus?.type).toBe('DryRunSuccessStatus');
});

it('can withdraw an amount of base asset using mutiple uxtos', async () => {
const sender = Wallet.generate({
provider,
Expand Down
22 changes: 21 additions & 1 deletion packages/account/src/account.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { UTXO_ID_LEN } from '@fuel-ts/abi-coder';
import { Address } from '@fuel-ts/address';
import { randomBytes } from '@fuel-ts/crypto';
import { ErrorCode, FuelError } from '@fuel-ts/errors';
import { AbstractAccount } from '@fuel-ts/interfaces';
import type { AbstractAddress, BytesLike } from '@fuel-ts/interfaces';
import type { BigNumberish, BN } from '@fuel-ts/math';
import { bn } from '@fuel-ts/math';
import { arrayify, isDefined } from '@fuel-ts/utils';
import { arrayify, hexlify, isDefined } from '@fuel-ts/utils';
import { clone } from 'ramda';

import type { FuelConnector } from './connectors';
Expand Down Expand Up @@ -56,6 +58,8 @@ export type EstimatedTxParams = Pick<
>;
const MAX_FUNDING_ATTEMPTS = 2;

export type FakeResources = Partial<Coin> & Required<Pick<Coin, 'amount' | 'assetId'>>;

/**
* `Account` provides an abstraction for interacting with accounts or wallets on the network.
*/
Expand Down Expand Up @@ -640,6 +644,22 @@ export class Account extends AbstractAccount {
return this.provider.simulate(transactionRequest, { estimateTxDependencies: false });
}

/**
* Generates an array of fake resources based on the provided coins.
*
maschad marked this conversation as resolved.
Show resolved Hide resolved
* @param coins - An array of `FakeResources` objects representing the coins.
* @returns An array of `Resource` objects with generated properties.
*/
generateFakeResources(coins: FakeResources[]): Array<Resource> {
Torres-ssf marked this conversation as resolved.
Show resolved Hide resolved
return coins.map((coin) => ({
id: hexlify(randomBytes(UTXO_ID_LEN)),
owner: this.address,
blockCreated: bn(1),
txCreatedIdx: bn(1),
...coin,
}));
}

/** @hidden * */
private validateTransferAmount(amount: BigNumberish) {
if (bn(amount).lte(0)) {
Expand Down
15 changes: 15 additions & 0 deletions packages/account/src/predicate/predicate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors';
import type { BytesLike } from '@fuel-ts/interfaces';
import { arrayify, hexlify } from '@fuel-ts/utils';

import type { FakeResources } from '../account';
import { Account } from '../account';
import {
transactionRequestify,
Expand Down Expand Up @@ -196,6 +197,20 @@ export class Predicate<TInputData extends InputValue[]> extends Account {
}));
}

/**
* Generates an array of fake resources based on the provided coins.
*
maschad marked this conversation as resolved.
Show resolved Hide resolved
* @param coins - An array of `FakeResources` objects representing the coins.
* @returns An array of `Resource` objects with generated properties.
*/
generateFakeResources(coins: FakeResources[]): Array<Resource> {
return super.generateFakeResources(coins).map((coin) => ({
...coin,
predicate: hexlify(this.bytes),
predicateData: hexlify(this.getPredicateData()),
}));
}

/**
* Sets the configurable constants for the predicate.
*
Expand Down
72 changes: 72 additions & 0 deletions packages/fuel-gauge/src/predicate/predicate-general.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { ASSET_A, ASSET_B } from '@fuel-ts/utils/test-utils';
import type { BN, FakeResources } from 'fuels';
import {
Address,
FUEL_NETWORK_URL,
Predicate,
Provider,
ScriptTransactionRequest,
bn,
} from 'fuels';

import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../../test/fixtures';

/**
* @group node
*/
describe('Predicate', () => {
it('can generate and use fake predicate coins', async () => {
const provider = await Provider.create(FUEL_NETWORK_URL);
const baseAssetId = provider.getBaseAssetId();
const { binHexlified, abiContents } = getFuelGaugeForcProject(
FuelGaugeProjectsEnum.PREDICATE_SUM
);

const amount1 = bn(500_000);
const amount2 = bn(200_000);
const amount3 = bn(300_000);
const amountToTransferBaseAsset = bn(1000);

const fakeCoinsConfig: FakeResources[] = [
{ amount: amount1, assetId: baseAssetId },
{ amount: amount2, assetId: ASSET_A },
{ amount: amount3, assetId: ASSET_B },
];

const value2 = bn(200);
const value1 = bn(100);

const predicate = new Predicate<[BN, BN]>({
bytecode: binHexlified,
abi: abiContents,
provider,
inputData: [value1, value2],
});

const fakeCoins = predicate.generateFakeResources(fakeCoinsConfig);

let request = new ScriptTransactionRequest({
gasLimit: bn(270_000),
maxFee: bn(250_000),
});

fakeCoins.forEach((coin) => {
expect(coin.predicate).toBeDefined();
expect(coin.predicateData).toBeDefined();
});

request.addResources(fakeCoins);
request.addCoinOutput(Address.fromRandom(), amountToTransferBaseAsset, baseAssetId);
request.addCoinOutput(Address.fromRandom(), amount2, ASSET_A);
request.addCoinOutput(Address.fromRandom(), amount3, ASSET_B);

request = await provider.estimatePredicates(request);

const { dryRunStatus } = await provider.call(request, {
utxoValidation: false,
estimateTxDependencies: false,
});

expect(dryRunStatus?.type).toBe('DryRunSuccessStatus');
});
});
Loading