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

fix: add predicateData to predicate resources and inputs #2380

Merged
merged 11 commits into from
May 24, 2024
5 changes: 5 additions & 0 deletions .changeset/giant-jobs-buy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@fuel-ts/account": patch
---

fix: add `predicateData` to predicate resources and inputs
1 change: 1 addition & 0 deletions packages/account/src/predicate/predicate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ export class Predicate<TInputData extends InputValue[]> extends Account {
return resources.map((resource) => ({
...resource,
predicate: hexlify(this.bytes),
predicateData: hexlify(this.getPredicateData()),
}));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ import { normalizeJSON } from '../utils';
import { getMaxGas, getMinGas } from '../utils/gas';

import { NoWitnessAtIndexError } from './errors';
import { isRequestInputResource } from './helpers';
import {
getRequestInputResourceOwner,
isRequestInputResource,
isRequestInputResourceFromOwner,
} from './helpers';
import type {
TransactionRequestInput,
CoinTransactionRequestInput,
Expand Down Expand Up @@ -348,7 +352,7 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi
* @param coin - Coin resource.
*/
addCoinInput(coin: Coin) {
const { assetId, owner, amount, id, predicate } = coin;
const { assetId, owner, amount, id, predicate, predicateData } = coin;

let witnessIndex;

Expand All @@ -372,6 +376,7 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi
txPointer: '0x00000000000000000000000000000000',
witnessIndex,
predicate,
predicateData,
};

// Insert the Input
Expand All @@ -388,7 +393,7 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi
* @param message - Message resource.
*/
addMessageInput(message: MessageCoin) {
const { recipient, sender, amount, predicate, nonce, assetId } = message;
const { recipient, sender, amount, predicate, nonce, assetId, predicateData } = message;

let witnessIndex;

Expand All @@ -411,6 +416,7 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi
amount,
witnessIndex,
predicate,
predicateData,
};

// Insert the Input
Expand Down Expand Up @@ -660,29 +666,19 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi
}

updatePredicateGasUsed(inputs: TransactionRequestInput[]) {
this.inputs.forEach((i) => {
let correspondingInput: TransactionRequestInput | undefined;
switch (i.type) {
case InputType.Coin:
correspondingInput = inputs.find((x) => x.type === InputType.Coin && x.owner === i.owner);
break;
case InputType.Message:
correspondingInput = inputs.find(
(x) => x.type === InputType.Message && x.sender === i.sender
);
break;
default:
return;
}
const inputsToExtractGasUsed = inputs.filter(isRequestInputResource);

this.inputs.filter(isRequestInputResource).forEach((i) => {
const owner = getRequestInputResourceOwner(i);
const correspondingInput = inputsToExtractGasUsed.find((x) =>
isRequestInputResourceFromOwner(x, Address.fromString(String(owner)))
);

if (
correspondingInput &&
'predicateGasUsed' in correspondingInput &&
bn(correspondingInput.predicateGasUsed).gt(0)
) {
// eslint-disable-next-line no-param-reassign
i.predicate = correspondingInput.predicate;
// eslint-disable-next-line no-param-reassign
i.predicateData = correspondingInput.predicateData;
// eslint-disable-next-line no-param-reassign
i.predicateGasUsed = correspondingInput.predicateGasUsed;
}
Expand Down
25 changes: 13 additions & 12 deletions packages/fuel-gauge/src/predicate/predicate-arguments.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { seedTestWallet } from '@fuel-ts/account/test-utils';
import type { WalletLocked, WalletUnlocked, BigNumberish } from 'fuels';
import { Provider, FUEL_NETWORK_URL, toHex, Predicate } from 'fuels';

import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../../test/fixtures';
import type { Validation } from '../types/predicate';

import { setupWallets, assertBalances, fundPredicate } from './utils/predicate';
import { setupWallets, assertBalances } from './utils/predicate';

/**
* @group node
Expand All @@ -31,7 +32,7 @@ describe('Predicate', () => {
let provider: Provider;
let baseAssetId: string;
const amountToReceiver = 50;
const amountToPredicate = 300_000;
const amountToPredicate = 900_000;

beforeAll(async () => {
provider = await Provider.create(FUEL_NETWORK_URL);
Expand All @@ -51,7 +52,7 @@ describe('Predicate', () => {
inputData: ['0xef86afa9696cf0dc6385e2c407a6e159a1103cefb7e2ae0636fb33d3cb2a9e4a'],
});

await fundPredicate(wallet, predicate, amountToPredicate);
await seedTestWallet(predicate, [[amountToPredicate, baseAssetId]], 3);
const initialReceiverBalance = await receiver.getBalance();

const tx = await predicate.transfer(receiver.address, amountToReceiver, baseAssetId, {
Expand All @@ -70,7 +71,7 @@ describe('Predicate', () => {
provider,
inputData: ['0xbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbada'],
});
await fundPredicate(wallet, predicate, amountToPredicate);
await seedTestWallet(predicate, [[amountToPredicate, baseAssetId]], 3);
const initialReceiverBalance = await receiver.getBalance();

expect(initialReceiverBalance.toHex()).toEqual(toHex(0));
Expand All @@ -88,7 +89,7 @@ describe('Predicate', () => {
inputData: [1078],
});

await fundPredicate(wallet, predicate, amountToPredicate);
await seedTestWallet(predicate, [[amountToPredicate, baseAssetId]], 3);
const initialReceiverBalance = await receiver.getBalance();

const tx = await predicate.transfer(receiver.address, amountToReceiver, baseAssetId, {
Expand All @@ -108,7 +109,7 @@ describe('Predicate', () => {
inputData: [100],
});

await fundPredicate(wallet, predicate, amountToPredicate);
await seedTestWallet(predicate, [[amountToPredicate, baseAssetId]], 3);
const initialReceiverBalance = await receiver.getBalance();

expect(initialReceiverBalance.toHex()).toEqual(toHex(0));
Expand All @@ -127,7 +128,7 @@ describe('Predicate', () => {
provider,
inputData: [{ has_account: true, total_complete: 100 }],
});
await fundPredicate(wallet, predicateInstanceForBalance, amountToPredicate);
await seedTestWallet(predicateInstanceForBalance, [[amountToPredicate, baseAssetId]], 3);
const initialReceiverBalance = await receiver.getBalance();

// #region predicate-struct-arg
Expand Down Expand Up @@ -160,7 +161,7 @@ describe('Predicate', () => {
],
});

await fundPredicate(wallet, predicate, amountToPredicate);
await seedTestWallet(predicate, [[amountToPredicate, baseAssetId]], 3);

await expect(
predicate.transfer(receiver.address, 50, baseAssetId, { gasLimit: 1000 })
Expand All @@ -175,7 +176,7 @@ describe('Predicate', () => {
inputData: [[42]],
});

await fundPredicate(wallet, predicate, amountToPredicate);
await seedTestWallet(predicate, [[amountToPredicate, baseAssetId]], 3);
const initialReceiverBalance = await receiver.getBalance();

const tx = await predicate.transfer(receiver.address, amountToReceiver, baseAssetId, {
Expand All @@ -195,7 +196,7 @@ describe('Predicate', () => {
inputData: [20, 30],
});

await fundPredicate(wallet, predicateForBalance, amountToPredicate);
await seedTestWallet(predicateForBalance, [[amountToPredicate, baseAssetId]], 3);
const initialReceiverBalance = await receiver.getBalance();

// #region predicate-multi-args
Expand Down Expand Up @@ -223,7 +224,7 @@ describe('Predicate', () => {
inputData: [20, 30],
});

await fundPredicate(wallet, predicate, amountToPredicate);
await seedTestWallet(predicate, [[amountToPredicate, baseAssetId]], 3);
const initialReceiverBalance = await receiver.getBalance();

const tx = await predicate.transfer(receiver.address, amountToReceiver, baseAssetId, {
Expand All @@ -243,7 +244,7 @@ describe('Predicate', () => {
inputData: [20, 20],
});

await fundPredicate(wallet, predicate, amountToPredicate);
await seedTestWallet(predicate, [[amountToPredicate, baseAssetId]], 3);

await expect(
predicate.transfer(receiver.address, 50, baseAssetId, { gasLimit: 1000 })
Expand Down
54 changes: 52 additions & 2 deletions packages/fuel-gauge/src/predicate/predicate-estimations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
FUEL_NETWORK_URL,
getRandomB256,
WalletUnlocked,
isRequestInputResource,
} from 'fuels';

import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../../test/fixtures';
Expand All @@ -35,8 +36,9 @@ describe('Predicate', () => {
let predicateTrue: Predicate<[]>;
let predicateStruct: Predicate<[Validation]>;
let baseAssetId: string;
const fundingAmount = 10_000;

beforeEach(async () => {
beforeAll(async () => {
provider = await Provider.create(FUEL_NETWORK_URL);
baseAssetId = provider.getBaseAssetId();
predicateTrue = new Predicate({
Expand All @@ -48,10 +50,13 @@ describe('Predicate', () => {
abi: predicateAbiMainArgsStruct,
provider,
});
});

beforeEach(async () => {
await seedTestWallet(predicateStruct, [
{
assetId: baseAssetId,
amount: bn(10_000),
amount: bn(fundingAmount),
},
]);
});
Expand Down Expand Up @@ -204,5 +209,50 @@ describe('Predicate', () => {
expect(estimatePredicatesSpy).toHaveBeenCalledTimes(1);
expect(dryRunSpy).toHaveBeenCalledOnce();
});

describe('predicate resource fetching and predicateData population', () => {
test('getting predicate resources via the predicate automatically populates predicateData', async () => {
const transactionRequest = new ScriptTransactionRequest();

const resources = await predicateStruct.getResourcesToSpend([[fundingAmount, baseAssetId]]);
resources.forEach((resource) => {
expect(resource.predicateData).toBeDefined();
});

transactionRequest.addResources(resources);
const inputs = transactionRequest.inputs.filter(isRequestInputResource);

expect(inputs.length).toBeGreaterThan(0);
inputs.forEach((resource) => {
expect(resource.predicateData).toBeDefined();
});
});

test('getting predicate resources via the provider requires manual predicateData population', async () => {
const transactionRequest = new ScriptTransactionRequest();

const resources = await provider.getResourcesToSpend(predicateStruct.address, [
[fundingAmount, baseAssetId],
]);

resources.forEach((resource) => {
expect(resource.predicateData).toBeUndefined();
});

transactionRequest.addResources(resources);
const inputs = transactionRequest.inputs.filter(isRequestInputResource);

expect(inputs.length).toBeGreaterThan(0);
inputs.forEach((resource) => {
expect(resource.predicateData).toBeUndefined();
});

predicateStruct.populateTransactionPredicateData(transactionRequest);

inputs.forEach((resource) => {
expect(resource.predicateData).toBeDefined();
});
});
});
});
});
Loading