Skip to content

Commit 5f20945

Browse files
authored
Merge pull request #932 from PhilippeR26/decodeParameters
feat: add provider.decodeParameters
2 parents 12fa1bc + be6eec9 commit 5f20945

File tree

3 files changed

+173
-0
lines changed

3 files changed

+173
-0
lines changed

__tests__/cairo1v2.test.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
compiledC210,
3232
compiledC210Casm,
3333
compiledComplexSierra,
34+
compiledHelloSierra,
3435
getTestAccount,
3536
getTestProvider,
3637
} from './config/fixtures';
@@ -673,6 +674,83 @@ describe('Cairo 1', () => {
673674
expect(callDataFromObject).toStrictEqual(expectedResult);
674675
expect(callDataFromArray).toStrictEqual(expectedResult);
675676
});
677+
678+
test('myCallData.decodeParameters for Cairo 1', async () => {
679+
const Cairo1HelloAbi = compiledHelloSierra;
680+
const Cairo1Abi = compiledC1v2;
681+
const helloCallData = new CallData(Cairo1HelloAbi.abi);
682+
const c1v2CallData = new CallData(Cairo1Abi.abi);
683+
684+
const res2 = helloCallData.decodeParameters('hello::hello::UserData', ['0x123456', '0x1']);
685+
expect(res2).toEqual({ address: 1193046n, is_claimed: true });
686+
const res3 = helloCallData.decodeParameters(
687+
['hello::hello::UserData', 'hello::hello::UserData'],
688+
['0x123456', '0x1', '0x98765', '0x0']
689+
);
690+
expect(res3).toEqual([
691+
{ address: 1193046n, is_claimed: true },
692+
{ address: 624485n, is_claimed: false },
693+
]);
694+
const res4 = helloCallData.decodeParameters('core::integer::u8', ['0x123456']);
695+
expect(res4).toBe(1193046n);
696+
const res5 = helloCallData.decodeParameters('core::bool', ['0x1']);
697+
expect(res5).toBe(true);
698+
const res6 = helloCallData.decodeParameters('core::felt252', ['0x123456']);
699+
expect(res6).toBe(1193046n);
700+
const res7 = helloCallData.decodeParameters('core::integer::u256', ['0x123456', '0x789']);
701+
expect(num.toHex(res7.toString())).toBe('0x78900000000000000000000000000123456');
702+
const res8 = helloCallData.decodeParameters('core::array::Array::<core::integer::u16>', [
703+
'2',
704+
'0x123456',
705+
'0x789',
706+
]);
707+
expect(res8).toEqual([1193046n, 1929n]);
708+
const res9 = helloCallData.decodeParameters('core::array::Span::<core::integer::u16>', [
709+
'2',
710+
'0x123456',
711+
'0x789',
712+
]);
713+
expect(res9).toEqual([1193046n, 1929n]);
714+
const res10 = helloCallData.decodeParameters('(core::felt252, core::integer::u16)', [
715+
'0x123456',
716+
'0x789',
717+
]);
718+
expect(res10).toEqual({ '0': 1193046n, '1': 1929n });
719+
const res11 = helloCallData.decodeParameters('core::starknet::eth_address::EthAddress', [
720+
'0x123456',
721+
]);
722+
expect(res11).toBe(1193046n);
723+
const res12 = helloCallData.decodeParameters(
724+
'core::starknet::contract_address::ContractAddress',
725+
['0x123456']
726+
);
727+
expect(res12).toBe(1193046n);
728+
const res13 = helloCallData.decodeParameters('core::starknet::class_hash::ClassHash', [
729+
'0x123456',
730+
]);
731+
expect(res13).toBe(1193046n);
732+
const res14 = c1v2CallData.decodeParameters('core::option::Option::<core::integer::u8>', [
733+
'0',
734+
'0x12',
735+
]);
736+
expect(res14).toEqual({ Some: 18n, None: undefined });
737+
const res15 = c1v2CallData.decodeParameters(
738+
'core::result::Result::<hello_res_events_newTypes::hello_res_events_newTypes::Order, core::integer::u16>',
739+
['0', '0x12', '0x345']
740+
);
741+
expect(res15).toEqual({ Ok: { p1: 18n, p2: 837n }, Err: undefined });
742+
const res16 = c1v2CallData.decodeParameters(
743+
'hello_res_events_newTypes::hello_res_events_newTypes::MyEnum',
744+
['0', '0x12', '0x5678']
745+
);
746+
expect(res16).toEqual({
747+
variant: {
748+
Response: { p1: 18n, p2: 22136n },
749+
Warning: undefined,
750+
Error: undefined,
751+
},
752+
});
753+
});
676754
});
677755

678756
describe('Cairo1 Account contract', () => {

__tests__/contract.test.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,75 @@ describe('Complex interaction', () => {
717717
expect(callDataFromArray).toStrictEqual(expectedResult);
718718
});
719719

720+
test('myCallData.decodeParameters for Cairo 0', async () => {
721+
const myCallData = new CallData(erc20Echo20Contract.abi);
722+
723+
const res0 = myCallData.decodeParameters('felt', ['474107654995566025798705']);
724+
expect(res0).toBe(474107654995566025798705n);
725+
const res1 = myCallData.decodeParameters('StructY', [
726+
'474107654995566025798705',
727+
'3534634645645',
728+
]);
729+
expect(res1).toEqual({ y1: 474107654995566025798705n, y2: 3534634645645n });
730+
731+
const res2 = myCallData.decodeParameters('Uint256', ['47410765', '35346645']);
732+
expect(res2).toEqual({ low: 47410765n, high: 35346645n });
733+
const res3 = myCallData.decodeParameters('Struct32', ['47410765', '35346645', '1', '2', '3']);
734+
expect(res3).toEqual({ b: 47410765n, c: { '0': 35346645n, '1': 1n, '2': 2n, '3': 3n } });
735+
736+
const res4 = myCallData.decodeParameters('(felt, felt, felt, felt)', [
737+
'47410765',
738+
'35346645',
739+
'1',
740+
'2',
741+
]);
742+
expect(res4).toEqual({ '0': 47410765n, '1': 35346645n, '2': 1n, '3': 2n });
743+
744+
const res5 = myCallData.decodeParameters('Struct2', ['47410765', '35346645', '1', '2', '3']);
745+
expect(res5).toEqual({
746+
info: { discount_fix_bps: 47410765n, discount_transfer_bps: 35346645n },
747+
data: 1n,
748+
data2: { min: 2n, max: 3n },
749+
});
750+
const res6 = myCallData.decodeParameters('Struct3', [
751+
'47410765',
752+
'35346645',
753+
'1',
754+
'2',
755+
'3',
756+
'4',
757+
]);
758+
expect(res6).toEqual({
759+
a: 47410765n,
760+
b: { b: 35346645n, c: { '0': 1n, '1': 2n, '2': 3n, '3': 4n } },
761+
});
762+
const res7 = myCallData.decodeParameters('(t1: felt, t2: StructX, t3: felt)', [
763+
'47410765',
764+
'35346645',
765+
'1',
766+
'2',
767+
'3',
768+
'4',
769+
'5',
770+
'6',
771+
'7',
772+
'8',
773+
'9',
774+
]);
775+
expect(res7).toEqual({
776+
t1: 47410765n,
777+
t2: {
778+
x1: 35346645n,
779+
x2: { y1: 1n, y2: 2n },
780+
x3: {
781+
tx1: { '0': 3n, '1': 4n },
782+
tx2: { tx21: { tx211: 5n, tx212: 6n }, tx22: { '0': 7n, '1': 8n } },
783+
},
784+
},
785+
t3: 9n,
786+
});
787+
});
788+
720789
test('invoke compiled data', async () => {
721790
const result = await erc20Echo20Contract.iecho(CallData.compile(request));
722791
const transaction = await provider.waitForTransaction(result.transaction_hash);

src/utils/calldata/index.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
Abi,
44
AbiEnums,
55
AbiStructs,
6+
AllowArray,
67
Args,
78
ArgsOrCalldata,
89
Calldata,
@@ -325,4 +326,29 @@ export class CallData {
325326
const calldata = CallData.compile(raw);
326327
return calldata.map((it) => toHex(it));
327328
}
329+
330+
/**
331+
* Parse the elements of a contract response and structure them into one or several Result.
332+
* In Cairo 0, arrays are not supported.
333+
* @param typeCairo string or string[] - Cairo type name, ex : "hello::hello::UserData"
334+
* @param response string[] - serialized data corresponding to typeCairo.
335+
* @return Result or Result[] - parsed response corresponding to typeData.
336+
* @example
337+
* const res2=helloCallData.decodeParameters("hello::hello::UserData",["0x123456","0x1"]);
338+
* result = { address: 1193046n, is_claimed: true }
339+
*/
340+
public decodeParameters(typeCairo: AllowArray<string>, response: string[]): AllowArray<Result> {
341+
const typeCairoArray = Array.isArray(typeCairo) ? typeCairo : [typeCairo];
342+
const responseIterator = response.flat()[Symbol.iterator]();
343+
const decodedArray = typeCairoArray.map(
344+
(typeParam) =>
345+
responseParser(
346+
responseIterator,
347+
{ name: '', type: typeParam },
348+
this.structs,
349+
this.enums
350+
) as Result
351+
);
352+
return decodedArray.length === 1 ? decodedArray[0] : decodedArray;
353+
}
328354
}

0 commit comments

Comments
 (0)