Skip to content

Commit 39595f3

Browse files
PhilippeR26penovicp
authored andcommitted
feat: add provider.decodeParameters
1 parent 8aa74bb commit 39595f3

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
describeIfDevnetSequencer,
3536
getTestAccount,
3637
getTestProvider,
@@ -675,6 +676,83 @@ describe('Cairo 1', () => {
675676
expect(callDataFromArray).toStrictEqual(expectedResult);
676677
});
677678

679+
test('myCallData.decodeParameters for Cairo 1', async () => {
680+
const Cairo1HelloAbi = compiledHelloSierra;
681+
const Cairo1Abi = compiledC1v2;
682+
const helloCallData = new CallData(Cairo1HelloAbi.abi);
683+
const c1v2CallData = new CallData(Cairo1Abi.abi);
684+
685+
const res2 = helloCallData.decodeParameters('hello::hello::UserData', ['0x123456', '0x1']);
686+
expect(res2).toEqual({ address: 1193046n, is_claimed: true });
687+
const res3 = helloCallData.decodeParameters(
688+
['hello::hello::UserData', 'hello::hello::UserData'],
689+
['0x123456', '0x1', '0x98765', '0x0']
690+
);
691+
expect(res3).toEqual([
692+
{ address: 1193046n, is_claimed: true },
693+
{ address: 624485n, is_claimed: false },
694+
]);
695+
const res4 = helloCallData.decodeParameters('core::integer::u8', ['0x123456']);
696+
expect(res4).toBe(1193046n);
697+
const res5 = helloCallData.decodeParameters('core::bool', ['0x1']);
698+
expect(res5).toBe(true);
699+
const res6 = helloCallData.decodeParameters('core::felt252', ['0x123456']);
700+
expect(res6).toBe(1193046n);
701+
const res7 = helloCallData.decodeParameters('core::integer::u256', ['0x123456', '0x789']);
702+
expect(num.toHex(res7.toString())).toBe('0x78900000000000000000000000000123456');
703+
const res8 = helloCallData.decodeParameters('core::array::Array::<core::integer::u16>', [
704+
'2',
705+
'0x123456',
706+
'0x789',
707+
]);
708+
expect(res8).toEqual([1193046n, 1929n]);
709+
const res9 = helloCallData.decodeParameters('core::array::Span::<core::integer::u16>', [
710+
'2',
711+
'0x123456',
712+
'0x789',
713+
]);
714+
expect(res9).toEqual([1193046n, 1929n]);
715+
const res10 = helloCallData.decodeParameters('(core::felt252, core::integer::u16)', [
716+
'0x123456',
717+
'0x789',
718+
]);
719+
expect(res10).toEqual({ '0': 1193046n, '1': 1929n });
720+
const res11 = helloCallData.decodeParameters('core::starknet::eth_address::EthAddress', [
721+
'0x123456',
722+
]);
723+
expect(res11).toBe(1193046n);
724+
const res12 = helloCallData.decodeParameters(
725+
'core::starknet::contract_address::ContractAddress',
726+
['0x123456']
727+
);
728+
expect(res12).toBe(1193046n);
729+
const res13 = helloCallData.decodeParameters('core::starknet::class_hash::ClassHash', [
730+
'0x123456',
731+
]);
732+
expect(res13).toBe(1193046n);
733+
const res14 = c1v2CallData.decodeParameters('core::option::Option::<core::integer::u8>', [
734+
'0',
735+
'0x12',
736+
]);
737+
expect(res14).toEqual({ Some: 18n, None: undefined });
738+
const res15 = c1v2CallData.decodeParameters(
739+
'core::result::Result::<hello_res_events_newTypes::hello_res_events_newTypes::Order, core::integer::u16>',
740+
['0', '0x12', '0x345']
741+
);
742+
expect(res15).toEqual({ Ok: { p1: 18n, p2: 837n }, Err: undefined });
743+
const res16 = c1v2CallData.decodeParameters(
744+
'hello_res_events_newTypes::hello_res_events_newTypes::MyEnum',
745+
['0', '0x12', '0x5678']
746+
);
747+
expect(res16).toEqual({
748+
variant: {
749+
Response: { p1: 18n, p2: 22136n },
750+
Warning: undefined,
751+
Error: undefined,
752+
},
753+
});
754+
});
755+
678756
describeIfDevnetSequencer('Sequencer only', () => {
679757
test('getCompiledClassByClassHash', async () => {
680758
const compiledClass = await (provider as SequencerProvider).getCompiledClassByClassHash(

__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)