Skip to content

Commit 69e1ba8

Browse files
fix: incorrect function coder offset usage (#3589)
* fix: incorrect offset * chore: changeset * chore: added missing @groups * chore: change name of variable * chore: added expectations for the script result
1 parent 71691a2 commit 69e1ba8

File tree

6 files changed

+121
-2
lines changed

6 files changed

+121
-2
lines changed

.changeset/nasty-carrots-report.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@fuel-ts/abi-coder": patch
3+
---
4+
5+
fix: incorrect function coder offset usage

packages/abi-coder/src/FunctionFragment.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,11 @@ export class FunctionFragment {
105105
const result = this.jsonFnOld.inputs.reduce(
106106
(obj: { decoded: unknown[]; offset: number }, input) => {
107107
const coder = AbiCoder.getCoder(this.jsonAbiOld, input, { encoding: this.encoding });
108-
const [decodedValue, decodedValueByteSize] = coder.decode(bytes, obj.offset);
108+
const [decodedValue, decodedOffset] = coder.decode(bytes, obj.offset);
109109

110110
return {
111111
decoded: [...obj.decoded, decodedValue],
112-
offset: obj.offset + decodedValueByteSize,
112+
offset: decodedOffset,
113113
};
114114
},
115115
{ decoded: [], offset: 0 }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { getRandomB256 } from 'fuels';
2+
import { launchTestNode } from 'fuels/test-utils';
3+
4+
import { ScriptMainReturnStruct } from '../../test/typegen/scripts/ScriptMainReturnStruct';
5+
import type { ScriptMainReturnStructInputs } from '../../test/typegen/scripts/ScriptMainReturnStruct';
6+
import {
7+
ScriptWithComplexArgs,
8+
type AssetIdInput,
9+
type ScriptWithComplexArgsInputs,
10+
} from '../../test/typegen/scripts/ScriptWithComplexArgs';
11+
import type { Vec } from '../../test/typegen/scripts/common';
12+
13+
/**
14+
* @group browser
15+
* @group node
16+
*/
17+
describe('abi-script', () => {
18+
describe('decodeArguments', () => {
19+
it('should decode arguments with a simple script', async () => {
20+
using launched = await launchTestNode();
21+
const {
22+
wallets: [funder],
23+
} = launched;
24+
25+
const args: ScriptMainReturnStructInputs = [1, { x: 2 }];
26+
27+
// Run script
28+
const script = new ScriptMainReturnStruct(funder);
29+
const tx = await script.functions.main(...args).call();
30+
const { value, transactionResult } = await tx.waitForResult();
31+
expect(value).toEqual({ x: 3 });
32+
33+
// Assert script data
34+
const scriptData = transactionResult.transaction.scriptData;
35+
if (!scriptData) {
36+
throw new Error('No script data');
37+
}
38+
39+
// Assert the decoded script data matches the input arguments
40+
const fn = script.interface.getFunction('main');
41+
const decoded = fn.decodeArguments(scriptData);
42+
expect(decoded).toEqual(args);
43+
});
44+
45+
it('should decode arguments with a complex script', async () => {
46+
using launched = await launchTestNode();
47+
48+
const {
49+
wallets: [wallet],
50+
} = launched;
51+
52+
const arg1 = 100;
53+
const arg2 = { bits: getRandomB256() };
54+
const arg3 = 100;
55+
const arg4 = [[{ bits: getRandomB256() }, { bits: getRandomB256() }, true]] as Vec<
56+
[AssetIdInput, AssetIdInput, boolean]
57+
>;
58+
const arg5 = { Address: { bits: getRandomB256() } };
59+
const arg6 = 100;
60+
const expected = [
61+
expect.toEqualBn(arg1),
62+
arg2,
63+
expect.toEqualBn(arg3),
64+
arg4,
65+
arg5,
66+
expect.toEqualBn(arg6),
67+
];
68+
69+
// Run script
70+
const script = new ScriptWithComplexArgs(wallet);
71+
const args: ScriptWithComplexArgsInputs = [arg1, arg2, arg3, arg4, arg5, arg6];
72+
const tx = await script.functions.main(...args).call();
73+
const { value, transactionResult } = await tx.waitForResult();
74+
expect(value).toEqual(expected);
75+
76+
// Assert script data
77+
const scriptData = transactionResult.transaction.scriptData;
78+
if (!scriptData) {
79+
throw new Error('No script data');
80+
}
81+
82+
// Assert the decoded script data matches the input arguments
83+
const fn = script.interface.getFunction('main');
84+
const decoded = fn.decodeArguments(scriptData);
85+
expect(decoded).toEqual(expected);
86+
});
87+
});
88+
});

packages/fuel-gauge/test/fixtures/forc-projects/Forc.toml

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ members = [
6464
"script-with-more-configurable",
6565
"script-with-vector",
6666
"script-with-options",
67+
"script-with-complex-args",
6768
"script-with-vector-advanced",
6869
"script-with-vector-mixed",
6970
"small-bytes",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[project]
2+
authors = ["Fuel Labs <[email protected]>"]
3+
entry = "main.sw"
4+
license = "Apache-2.0"
5+
name = "script-with-complex-args"
6+
7+
[dependencies]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
script;
2+
3+
use std::bytes::Bytes;
4+
5+
type PoolId = (AssetId, AssetId, bool);
6+
7+
type ScriptResult = (u64, AssetId, u64, Vec<PoolId>, Identity, u32);
8+
9+
fn main(
10+
amount_in: u64,
11+
asset_in: AssetId,
12+
amount_out_min: u64,
13+
pools: Vec<PoolId>,
14+
recipient: Identity,
15+
deadline: u32,
16+
) -> ScriptResult {
17+
return (amount_in, asset_in, amount_out_min, pools, recipient, deadline);
18+
}

0 commit comments

Comments
 (0)