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/parse events #704

Merged
merged 7 commits into from
Aug 9, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
7,908 changes: 2,603 additions & 5,305 deletions __mocks__/cairo/helloCairo2/compiled.casm

Large diffs are not rendered by default.

14,147 changes: 8,423 additions & 5,724 deletions __mocks__/cairo/helloCairo2/compiled.json

Large diffs are not rendered by default.

92 changes: 92 additions & 0 deletions __mocks__/cairo/helloCairo2/hello.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,22 @@ trait IHelloStarknet<TContractState> {
fn test_u128(self: @TContractState, p1: u128) -> u128;
fn test_u256(self: @TContractState, p1: u256) -> u256;

// event test
fn emitEventRegular(
ref self: TContractState,
simpleKeyVariable: u8,
simpleKeyStruct: HelloStarknet::SimpleStruct,
simpleKeyArray: Array<u8>,
simpleDataVariable: u8,
simpleDataStruct: HelloStarknet::SimpleStruct,
simpleDataArray: Array<u8>
);
fn emitEventNested(
ref self: TContractState,
nestedKeyStruct: HelloStarknet::NestedStruct,
nestedDataStruct: HelloStarknet::NestedStruct
);

// echo Array
fn echo_array(self: @TContractState, data: Array<u8>) -> Array<u8>;
fn echo_array_u256(self: @TContractState, data: Array<u256>) -> Array<u256>;
Expand Down Expand Up @@ -168,6 +184,45 @@ mod HelloStarknet {
user1: UserData,
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
EventRegular: EventRegular,
EventNested: EventNested,
}

#[derive(Drop, Serde)]
struct SimpleStruct {
first: u8,
second: u16,
}

#[derive(Drop, Serde)]
struct NestedStruct {
simpleStruct: SimpleStruct,
simpleArray: Array<u8>,
}

#[derive(Drop, starknet::Event)]
struct EventRegular {
#[key]
simpleKeyVariable: u8,
#[key]
simpleKeyStruct: SimpleStruct,
#[key]
simpleKeyArray: Array<u8>,
simpleDataVariable: u8,
simpleDataStruct: SimpleStruct,
simpleDataArray: Array<u8>,
}

#[derive(Drop, starknet::Event)]
struct EventNested {
#[key]
nestedKeyStruct: NestedStruct,
nestedDataStruct: NestedStruct,
}

#[l1_handler]
fn increase_bal(ref self: ContractState, from_address: felt252, amount: felt252) {
let current = self.balance.read();
Expand Down Expand Up @@ -238,6 +293,43 @@ mod HelloStarknet {
p1 + to_add
}

// event test
fn emitEventRegular(
ref self: ContractState,
simpleKeyVariable: u8,
simpleKeyStruct: SimpleStruct,
simpleKeyArray: Array<u8>,
simpleDataVariable: u8,
simpleDataStruct: SimpleStruct,
simpleDataArray: Array<u8>
) {
self
.emit(
Event::EventRegular(
EventRegular {
simpleKeyVariable: simpleKeyVariable,
simpleKeyStruct: simpleKeyStruct,
simpleKeyArray: simpleKeyArray,
simpleDataVariable: simpleDataVariable,
simpleDataStruct: simpleDataStruct,
simpleDataArray: simpleDataArray
}
)
);
}
fn emitEventNested(
ref self: ContractState, nestedKeyStruct: NestedStruct, nestedDataStruct: NestedStruct
) {
self
.emit(
Event::EventNested(
EventNested {
nestedKeyStruct: nestedKeyStruct, nestedDataStruct: nestedDataStruct,
}
)
)
}

// echo Array
fn echo_array(self: @ContractState, data: Array<u8>) -> Array<u8> {
data
Expand Down
133 changes: 129 additions & 4 deletions __tests__/cairo1v2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
selector,
shortString,
stark,
types,
} from '../src';
import {
compiledC1Account,
Expand All @@ -34,9 +35,9 @@ const { toHex } = num;
const { starknetKeccak } = selector;

describe('Cairo 1 Devnet', () => {
const provider = getTestProvider();
const account = getTestAccount(provider);
describe('API & Contract interactions', () => {
const provider = getTestProvider();
const account = getTestAccount(provider);
let dd: DeclareDeployUDCResponse;
let cairo1Contract: Contract;
initializeMatcher(expect);
Expand Down Expand Up @@ -501,8 +502,6 @@ describe('Cairo 1 Devnet', () => {
});

describe('Cairo1 Account contract', () => {
const provider = getTestProvider();
const account = getTestAccount(provider);
let accountC1: Account;

beforeAll(async () => {
Expand Down Expand Up @@ -556,4 +555,130 @@ describe('Cairo 1 Devnet', () => {
expect(accountC1).toBeInstanceOf(Account);
});
});

describe('Event Parsing', () => {
let eventContract: Contract;
const simpleKeyVariable = 0n;
const simpleKeyStruct = {
first: 1n,
second: 2n,
};
const simpleKeyArray = [3n, 4n, 5n];
const simpleDataVariable = 6n;
const simpleDataStruct = {
first: 7n,
second: 8n,
};
const simpleDataArray = [9n, 10n, 11n];
const nestedKeyStruct = {
simpleStruct: {
first: 0n,
second: 1n,
},
simpleArray: [2n, 3n, 4n, 5n],
};
const nestedDataStruct = {
simpleStruct: {
first: 6n,
second: 7n,
},
simpleArray: [8n, 9n, 10n, 11n],
};
beforeAll(async () => {
const { deploy } = await account.declareAndDeploy({
contract: compiledC1v2,
casm: compiledC1v2Casm,
});

eventContract = new Contract(compiledC1v2.abi, deploy.contract_address!, account);
});

test('parse event returning a regular struct', async () => {
const { transaction_hash } = await eventContract.emitEventRegular(
simpleKeyVariable,
simpleKeyStruct,
simpleKeyArray,
simpleDataVariable,
simpleDataStruct,
simpleDataArray
);
const shouldBe: types.ParsedEvents = {
EventRegular: [
{
simpleKeyVariable,
simpleKeyStruct,
simpleKeyArray,
simpleDataVariable,
simpleDataStruct,
simpleDataArray,
},
],
};
const tx = await provider.waitForTransaction(transaction_hash);
const events = eventContract.parseEvents(tx);
return expect(events).toStrictEqual(shouldBe);
});

test('parse event returning a nested struct', async () => {
const { transaction_hash } = await eventContract.emitEventNested(
nestedKeyStruct,
nestedDataStruct
);
const shouldBe: types.ParsedEvents = {
EventNested: [
{
nestedKeyStruct,
nestedDataStruct,
},
],
};
const tx = await provider.waitForTransaction(transaction_hash);
const events = eventContract.parseEvents(tx);
return expect(events).toStrictEqual(shouldBe);
});

test('parse tx returning multiple events', async () => {
const anotherKeyVariable = 100n;
const shouldBe: types.ParsedEvents = {
EventRegular: [
{
simpleKeyVariable,
simpleKeyStruct,
simpleKeyArray,
simpleDataVariable,
simpleDataStruct,
simpleDataArray,
},
{
simpleKeyVariable: anotherKeyVariable,
simpleKeyStruct,
simpleKeyArray,
simpleDataVariable,
simpleDataStruct,
simpleDataArray,
},
],
};
const callData1 = eventContract.populate('emitEventRegular', [
simpleKeyVariable,
simpleKeyStruct,
simpleKeyArray,
simpleDataVariable,
simpleDataStruct,
simpleDataArray,
]);
const callData2 = eventContract.populate('emitEventRegular', [
anotherKeyVariable,
simpleKeyStruct,
simpleKeyArray,
simpleDataVariable,
simpleDataStruct,
simpleDataArray,
]);
const { transaction_hash } = await account.execute([callData1, callData2]);
const tx = await provider.waitForTransaction(transaction_hash);
const events = eventContract.parseEvents(tx);
return expect(events).toStrictEqual(shouldBe);
});
});
});
46 changes: 46 additions & 0 deletions __tests__/contract.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { BigNumberish, Contract, ContractFactory, RawArgs, json, stark } from '../src';
import { ParsedEvents } from '../src/types';
import { CallData } from '../src/utils/calldata';
import { felt, isCairo1Abi, tuple, uint256 } from '../src/utils/calldata/cairo';
import { getSelectorFromName } from '../src/utils/hash';
Expand Down Expand Up @@ -96,6 +97,51 @@ describe('contract module', () => {
});
});

describe('Event Parsing', () => {
let erc20Echo20Contract: Contract;
const factoryClassHash =
'0x011ab8626b891bcb29f7cc36907af7670d6fb8a0528c7944330729d8f01e9ea3'!;
let factory: ContractFactory;
beforeAll(async () => {
factory = new ContractFactory({
compiledContract: compiledErc20Echo,
classHash: factoryClassHash,
account,
});

erc20Echo20Contract = await factory.deploy(
'Token',
'ERC20',
18,
uint256('1000000000'),
account.address,
['0x823d5a0c0eefdc9a6a1cb0e064079a6284f3b26566b677a32c71bbe7bf9f8c'],
22
);
});

test('parse legacy event structure', async () => {
const to = stark.randomAddress();
const amount = uint256(1);
const { transaction_hash } = await erc20Echo20Contract.transfer(to, amount);
const tx = await provider.waitForTransaction(transaction_hash);
const events: ParsedEvents = erc20Echo20Contract.parseEvents(tx);
const shouldBe: ParsedEvents = {
Transfer: [
{
from_: BigInt(account.address),
to: BigInt(to),
value: {
low: BigInt(amount.low),
high: BigInt(amount.high),
},
},
],
};
return expect(events).toStrictEqual(shouldBe);
});
});

describe('Type Transformation', () => {
let typeTransformedContract: Contract;

Expand Down
20 changes: 20 additions & 0 deletions src/contract/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { AccountInterface } from '../account';
import { ProviderInterface, defaultProvider } from '../provider';
import {
Abi,
AbiEvents,
ArgsOrCalldata,
ArgsOrCalldataWithOptions,
AsyncContractFunction,
Expand All @@ -12,8 +13,11 @@ import {
ContractOptions,
EstimateFeeResponse,
FunctionAbi,
GetTransactionReceiptResponse,
InvokeFunctionResponse,
InvokeOptions,
InvokeTransactionReceiptResponse,
ParsedEvents,
RawArgs,
Result,
StructAbi,
Expand All @@ -22,6 +26,8 @@ import {
import assert from '../utils/assert';
import { CallData, cairo } from '../utils/calldata';
import { createAbiParser } from '../utils/calldata/parser';
import { getAbiEvents, parseEvents as parseRawEvents } from '../utils/events/index';
import { cleanHex } from '../utils/num';
import { ContractInterface } from './interface';

export const splitArgsAndOptions = (args: ArgsOrCalldataWithOptions) => {
Expand Down Expand Up @@ -124,6 +130,8 @@ export class Contract implements ContractInterface {

protected readonly structs: { [name: string]: StructAbi };

protected readonly events: AbiEvents;

readonly functions!: { [name: string]: AsyncContractFunction };

readonly callStatic!: { [name: string]: AsyncContractFunction };
Expand Down Expand Up @@ -152,6 +160,7 @@ export class Contract implements ContractInterface {
this.providerOrAccount = providerOrAccount;
this.callData = new CallData(abi);
this.structs = CallData.getAbiStruct(abi);
this.events = getAbiEvents(abi);
const parser = createAbiParser(abi);
this.abi = parser.getLegacyFormat();

Expand Down Expand Up @@ -323,6 +332,17 @@ export class Contract implements ContractInterface {
};
}

public parseEvents(receipt: GetTransactionReceiptResponse): ParsedEvents {
return parseRawEvents(
(receipt as InvokeTransactionReceiptResponse).events?.filter(
(event) => cleanHex(event.from_address) === cleanHex(this.address),
[]
) || [],
this.events,
this.structs
);
}

public isCairo1(): boolean {
return cairo.isCairo1Abi(this.abi);
}
Expand Down
Loading
Loading