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!: add main arg support to Scripts #745

Merged
merged 63 commits into from
Feb 23, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
b397f39
add test files and refactor
Jan 19, 2023
f85da44
update export
Jan 19, 2023
cf5c9be
add helpers
Jan 19, 2023
621b714
add and update tests
Jan 19, 2023
5d78edc
Update docs
Jan 19, 2023
a318cbe
add cs
Jan 20, 2023
8fd29aa
Merge branch 'master' into cm/issue-698
Jan 30, 2023
825950d
Code review tweaks
Jan 30, 2023
a70ce89
add tx params
Jan 30, 2023
e509260
add test for failure
Jan 30, 2023
752b122
refactor more like predicates
Jan 30, 2023
4684b73
revise md
Jan 31, 2023
0c3a9fe
adjust default export
Jan 31, 2023
2d92370
revert change
Jan 31, 2023
4f8bf5c
rm unused
Jan 31, 2023
7de0006
rename
Jan 31, 2023
af40629
fix type
Jan 31, 2023
c40e5fe
fix export
Jan 31, 2023
ce4cfba
improve types
Jan 31, 2023
303b41c
improve types
Jan 31, 2023
edf5601
Merge branch 'master' into cm/issue-698
Feb 2, 2023
fded31b
refactor
Jan 31, 2023
89dbf8a
refactor
Feb 2, 2023
bfc56ff
make more strict
Feb 2, 2023
dac16cc
revert
Feb 2, 2023
dc235c3
restore
Feb 2, 2023
70bc9a0
pr tweaks
Feb 7, 2023
d272852
move out of main constructor
Feb 9, 2023
d5a2753
rename
Feb 9, 2023
61f50d4
add
Feb 11, 2023
39d2d0e
simplify
Feb 11, 2023
91ca035
refactor
Feb 11, 2023
978008e
cleanup
Feb 11, 2023
8c8df44
relocate
Feb 11, 2023
7dc8f7f
cleanup
Feb 11, 2023
6c6d967
cleanup
Feb 11, 2023
5356753
fix issue
Feb 11, 2023
fa4f87b
Merge branch 'master' into cm/issue-698
Feb 11, 2023
4c8d8f3
clean up cruft
Feb 11, 2023
d61eaef
Merge branch 'master' into cm/issue-698
Feb 21, 2023
5997ee3
Update provider.ts
Feb 21, 2023
5acdfe6
Add new package
Feb 21, 2023
b7b12a9
reorg
Feb 21, 2023
89c108e
fix type
Feb 21, 2023
2ea384d
reloc
Feb 21, 2023
2d64d7b
add
Feb 21, 2023
2fb5d54
revise
Feb 21, 2023
f65706c
relocate
Feb 21, 2023
d9d1281
adjust
Feb 21, 2023
a204d5a
move
Feb 21, 2023
1fb6c35
fix wires
Feb 21, 2023
7a1ed6e
adjust tests
Feb 21, 2023
dd7d282
abstract
Feb 21, 2023
71306c2
up
Feb 21, 2023
e888a52
rename
Feb 22, 2023
efc4ed0
refactor
Feb 22, 2023
1cb5014
Merge branch 'master' into cm/issue-698
Feb 22, 2023
45368b7
fix post merge
Feb 22, 2023
c6bfe79
adjust
Feb 22, 2023
bda8dbc
rename
Feb 22, 2023
a106ab9
revise
Feb 22, 2023
976e6cd
Merge branch 'master' into cm/issue-698
Feb 22, 2023
28c6871
remove factory
Feb 22, 2023
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
9 changes: 9 additions & 0 deletions .changeset/rotten-dogs-pump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@fuel-ts/abi-coder": minor
"@fuel-ts/contract": minor
"fuels": minor
"@fuel-ts/providers": minor
"@fuel-ts/script": minor
---

Add support for main args in scripts
14 changes: 13 additions & 1 deletion docs/_guide/scripts/calling-a-script.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,16 @@

We will use the `script` instance created in the [previous section](./instantiating-a-script.md) to call the script.

[@code:typescript](./packages/script/src/script.test.ts#typedoc:script-call)
[@code:typescript](./packages/script/src/callScript.ts#typedoc:script-call)

You can access this low-level helper using `import { callScript } from 'fuels';`.

## Calling a script with a `main` function that takes arguments

Suppose your Sway script `main` function is written using the arguments passed to the `main` function like so:

[@code:rust](./packages/fuel-gauge/test-projects/script-main-args/src/main.sw#typedoc:script-with-main-args)

You can still hand code out a solution wrapper using `callScript` utility to call your script with data. However, if you prefer to use the ABI generated from your script, you can use the `ScriptFactory` helper:
camsjams marked this conversation as resolved.
Show resolved Hide resolved

[@code:typescript](./packages/fuel-gauge/src/script-main-args.test.ts#typedoc:script-call-factory)
1 change: 1 addition & 0 deletions packages/abi-coder/src/abi-coder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ export default class AbiCoder {
types: types.length,
nonEmptyTypes: nonEmptyTypes.length,
values: bytes.length,
newOffset,
},
value: {
types,
Expand Down
9 changes: 7 additions & 2 deletions packages/abi-coder/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ export default class Interface {
encodeFunctionData(
functionFragment: FunctionFragment | string,
values: Array<InputValue>,
offset = 0
offset = 0,
isMainArgs = false
): Uint8Array {
const fragment =
typeof functionFragment === 'string' ? this.getFunction(functionFragment) : functionFragment;
Expand All @@ -145,8 +146,12 @@ export default class Interface {
return selector;
}

const isRef = inputs.length > 1 || isReferenceType(inputs[0].type);
const args = this.abiCoder.encode(inputs, values, offset);
if (isMainArgs) {
return args;
}

const isRef = inputs.length > 1 || isReferenceType(inputs[0].type);
return concat([selector, new BooleanCoder().encode(isRef), args]);
}

Expand Down
16 changes: 2 additions & 14 deletions packages/contract/src/contracts/functions/invocation-results.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable max-classes-per-file */
import { U64Coder } from '@fuel-ts/abi-coder';
import type { BN } from '@fuel-ts/math';
import { bn } from '@fuel-ts/math';
import type {
Expand All @@ -9,6 +8,7 @@ import type {
TransactionResponse,
TransactionResultReceipt,
} from '@fuel-ts/providers';
import { getDecodedLogs } from '@fuel-ts/providers';
import type { ReceiptScriptResult } from '@fuel-ts/transactions';
import { ReceiptType } from '@fuel-ts/transactions';

Expand Down Expand Up @@ -57,19 +57,7 @@ export class InvocationResult<T = any> {

const { contract } = this.functionScopes[0].getCallConfig();

return receipts.reduce((logs, r) => {
if (r.type === ReceiptType.LogData) {
return logs.concat(...contract.interface.decodeLog(r.data, r.val1.toNumber(), r.id));
}

if (r.type === ReceiptType.Log) {
return logs.concat(
...contract.interface.decodeLog(new U64Coder().encode(r.val0), r.val1.toNumber(), r.id)
);
}

return logs;
}, []);
return getDecodedLogs(receipts, contract.interface);
}
}

Expand Down
82 changes: 82 additions & 0 deletions packages/fuel-gauge/src/script-main-args.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { generateTestWallet } from '@fuel-ts/wallet/test-utils';
import { readFileSync } from 'fs';
import type { BigNumberish } from 'fuels';
import { NativeAssetId, Provider, bn, ScriptFactory } from 'fuels';
import { join } from 'path';

import scriptAbi from '../test-projects/script-main-args/out/debug/script-main-args-abi.json';

import { getScript } from './utils';

const scriptBin = readFileSync(
join(__dirname, '../test-projects/script-main-args/out/debug/script-main-args.bin')
);

const setup = async () => {
const provider = new Provider('http://127.0.0.1:4000/graphql');

// Create wallet
const wallet = await generateTestWallet(provider, [[5_000_000, NativeAssetId]]);

return wallet;
};

type Baz = {
x: number;
};

describe('Script Coverage', () => {
it('can call script and use main arguments', async () => {
const wallet = await setup();
// #region typedoc:script-call-factory
const scriptInstance = new ScriptFactory<BigNumberish>(scriptBin, scriptAbi).script;
const foo = 33;

const { value, logs } = await wallet.callScript<BigNumberish[], BigNumberish>(scriptInstance, [
camsjams marked this conversation as resolved.
Show resolved Hide resolved
foo,
]);
camsjams marked this conversation as resolved.
Show resolved Hide resolved
// #endregion

expect(value.toString()).toEqual(bn(foo).toString());
expect(logs).toEqual(['u8 foo', 33]);
});

it('can call script and use main arguments [two args, read logs]', async () => {
const wallet = await setup();
const scriptInstance = getScript<Baz>('script-main-two-args').script;
const foo = 33;
const bar: Baz = {
x: 12,
};

const { value, logs } = await wallet.callScript(scriptInstance, [foo, bar]);

expect(value.toString()).toEqual(bn(foo + bar.x).toString());
expect(logs).toEqual(['u8 foo', 33, 'u8 bar', 12, 'u8 bar', 12]);
});

it('can call script and use main arguments [two args, struct return]', async () => {
const wallet = await setup();
const scriptInstance = getScript<Baz>('script-main-return-struct').script;
const foo = 1;
const bar: Baz = {
x: 2,
};

const { value } = await wallet.callScript(scriptInstance, [foo, bar]);

expect(value).toEqual({
x: 3,
});
});

it('can call script and use main arguments [tx params]', async () => {
const wallet = await setup();
const scriptInstance = new ScriptFactory<BigNumberish>(scriptBin, scriptAbi).script;
const foo = 42;

expect(async () => {
await wallet.callScript(scriptInstance, [foo], { gasLimit: 1, gasPrice: 400 });
}).rejects.toThrow(/gasLimit\(1\) is lower than the required/);
});
});
22 changes: 16 additions & 6 deletions packages/fuel-gauge/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { generateTestWallet } from '@fuel-ts/wallet/test-utils';
import { readFileSync } from 'fs';
import type { Interface, JsonAbi, Contract, BytesLike, WalletUnlocked } from 'fuels';
import { NativeAssetId, Provider, ContractFactory } from 'fuels';
import { ScriptFactory, NativeAssetId, Provider, ContractFactory } from 'fuels';
import { join } from 'path';

let contractInstance: Contract;
Expand Down Expand Up @@ -44,15 +44,25 @@ export const createSetupConfig =
...config,
});

const getFullPath = (
contractName: string,
next: (fullPath: string) => (config?: Partial<SetupConfig>) => Promise<Contract>
) => next(join(__dirname, `../test-projects/${contractName}/out/debug/${contractName}`));
const getFullPath = (contractName: string, next: (fullPath: string) => any) =>
camsjams marked this conversation as resolved.
Show resolved Hide resolved
next(join(__dirname, `../test-projects/${contractName}/out/debug/${contractName}`));

export const getSetupContract = (contractName: string) =>
export const getSetupContract = (
contractName: string
): ((config?: Partial<SetupConfig>) => Promise<Contract>) =>
getFullPath(contractName, (fullPath: string) =>
createSetupConfig({
contractBytecode: readFileSync(`${fullPath}.bin`),
abi: JSON.parse(readFileSync(`${fullPath}-abi.json`, 'utf8')),
})
);

export const getScript = <T>(scriptName: string): ScriptFactory<T> =>
getFullPath(
scriptName,
(fullPath: string) =>
new ScriptFactory(
readFileSync(`${fullPath}.bin`),
JSON.parse(readFileSync(`${fullPath}-abi.json`, 'utf8'))
)
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[project]
license = "Apache-2.0"
name = "script-main-args"

[dependencies]
11 changes: 11 additions & 0 deletions packages/fuel-gauge/test-projects/script-main-args/src/main.sw
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// #region typedoc:script-with-main-args
script;

use std::logging::log;

fn main(foo: u8) -> u8 {
log("u8 foo");
log(foo);
foo
}
// #endregion
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[project]
license = "Apache-2.0"
name = "script-main-return-struct"

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
script;

struct Baz {
x: u8,
}

fn main(foo: u8, bar: Baz) -> Baz {
Baz {
x: bar.x + foo
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[project]
license = "Apache-2.0"
name = "script-main-two-args"

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
script;

use std::logging::log;

struct Baz {
x: u8,
}

fn main(foo: u8, bar: Baz) -> u8 {
log("u8 foo");
log(foo);
log("u8 bar");
log(bar.x);
log("u8 bar");
log(bar.x);
foo + bar.x
}
2 changes: 1 addition & 1 deletion packages/fuels/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ export * from '@fuel-ts/providers';
export * from '@fuel-ts/signer';
export * from '@fuel-ts/transactions';
export * from '@fuel-ts/wallet';
export { ScriptResultDecoderError } from '@fuel-ts/script';
export { ScriptResultDecoderError, Script, callScript, ScriptFactory } from '@fuel-ts/script';
5 changes: 3 additions & 2 deletions packages/interfaces/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ export type Bech32Address = `fuel${string}`;
// #endregion
export type B256Address = string;

export abstract class AbstractScript<T> {
export abstract class AbstractScript<TData, TResult = any> {
camsjams marked this conversation as resolved.
Show resolved Hide resolved
abstract bytes: Uint8Array;
abstract encodeScriptData: (data: T) => Uint8Array;
abstract encodeScriptData: (data: TData) => Uint8Array;
abstract decodeCallResult: (callResult: { receipts: any }, logs?: Array<any>) => TResult;
camsjams marked this conversation as resolved.
Show resolved Hide resolved
}

// #region typedoc:AbstractAddress
Expand Down
4 changes: 4 additions & 0 deletions packages/providers/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ export type BuildPredicateOptions = {
fundTransaction?: boolean;
} & Pick<TransactionRequestLike, 'gasLimit' | 'gasPrice' | 'maturity'>;

export type BuildScriptOptions = {
fundTransaction?: boolean;
} & Pick<TransactionRequestLike, 'gasLimit' | 'gasPrice' | 'maturity'>;

camsjams marked this conversation as resolved.
Show resolved Hide resolved
/**
* Provider Call transaction params
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export const returnZeroScript: AbstractScript<void> = {
// TODO: Don't use hardcoded scripts: https://github.com/FuelLabs/fuels-ts/issues/281
bytes: arrayify('0x24000000'),
encodeScriptData: () => new Uint8Array(0),
decodeCallResult: () => null,
};

export const withdrawScript: AbstractScript<void> = {
Expand All @@ -75,6 +76,7 @@ export const withdrawScript: AbstractScript<void> = {
// TODO: Don't use hardcoded scripts: https://github.com/FuelLabs/fuels-ts/issues/281
bytes: arrayify('0x5040C0105D44C0064C40001124000000'),
encodeScriptData: () => new Uint8Array(0),
decodeCallResult: () => null,
};

interface BaseTransactionRequestLike {
Expand Down
24 changes: 24 additions & 0 deletions packages/providers/src/transaction-response/getDecodedLogs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Interface } from '@fuel-ts/abi-coder';
import { U64Coder } from '@fuel-ts/abi-coder';
import { ReceiptType } from '@fuel-ts/transactions';

import type { TransactionResultReceipt } from './transaction-response';

export default function getDecodedLogs<T = any>(
camsjams marked this conversation as resolved.
Show resolved Hide resolved
camsjams marked this conversation as resolved.
Show resolved Hide resolved
receipts: Array<TransactionResultReceipt>,
abiInterface: Interface
): T[] {
return receipts.reduce((logs, r) => {
if (r.type === ReceiptType.LogData) {
return logs.concat(...abiInterface.decodeLog(r.data, r.val1.toNumber(), r.id));
}

if (r.type === ReceiptType.Log) {
return logs.concat(
...abiInterface.decodeLog(new U64Coder().encode(r.val0), r.val1.toNumber(), r.id)
);
}

return logs;
}, []);
}
1 change: 1 addition & 0 deletions packages/providers/src/transaction-response/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './transaction-response';
export { default as getDecodedLogs } from './getDecodedLogs';
4 changes: 3 additions & 1 deletion packages/script/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@
},
"dependencies": {
"@ethersproject/bytes": "^5.7.0",
"@ethersproject/logger": "^5.7.0",
"@fuel-ts/abi-coder": "workspace:*",
"@fuel-ts/constants": "workspace:*",
"@fuel-ts/math": "workspace:*",
"@fuel-ts/providers": "workspace:*",
"@fuel-ts/wallet": "workspace:*",
"@fuel-ts/transactions": "workspace:*"
"@fuel-ts/transactions": "workspace:*",
"@fuel-ts/versions": "workspace:*"
},
"devDependencies": {
"forc-bin": "workspace:*"
Expand Down
Loading