Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
43 changes: 22 additions & 21 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,25 @@ jobs:
# Basic deployment to make sure everything is ok.
# Could be removed in the future if not relevant.
run: npm run deploy
- name: Test Timelock Deployment
run: npm run deploy:timelock
- name: Run coverage
run: npm run coverage
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4.0.1
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: iExecBlockchainComputing/PoCo
- name: Run static analysis with Slither
uses: crytic/slither-action@v0.4.0
with:
target: "contracts/tools/testing/slither/"
solc-version: '0.8.21'
slither-args: --checklist --markdown-root ${{ github.server_url }}/${{ github.repository }}/blob/${{ github.sha }}/
fail-on: none # TODO set this to high or other
sarif: results.sarif
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
# TODO: Re-enable it before merging to develop
# - name: Test Timelock Deployment
# run: npm run deploy:timelock
# - name: Run coverage
# run: npm run coverage
# - name: Upload coverage reports to Codecov
# uses: codecov/codecov-action@v4.0.1
# with:
# token: ${{ secrets.CODECOV_TOKEN }}
# slug: iExecBlockchainComputing/PoCo
# - name: Run static analysis with Slither
# uses: crytic/slither-action@v0.4.0
# with:
# target: "contracts/tools/testing/slither/"
# solc-version: '0.8.21'
# slither-args: --checklist --markdown-root ${{ github.server_url }}/${{ github.repository }}/blob/${{ github.sha }}/
# fail-on: none # TODO set this to high or other
# sarif: results.sarif
# - name: Upload SARIF file
# uses: github/codeql-action/upload-sarif@v3
# with:
# sarif_file: results.sarif
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
- Deployment scripts (#187)
- Tests
- test/*fullchain* (#190)
- IexecAccessors (#189)
- IexecAccessors (#189, #191)
- Migrate scripts to TypeScript: (#184)
- `getFunctionSignatures.js`, `common-test-snapshot.js`, `test-storage.js`, `timelock.js`
- Migrated utility files to TypeScript : (#183)
Expand Down
96 changes: 28 additions & 68 deletions test/utils/IexecWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers';
import { expect } from 'chai';
import {
ContractTransactionReceipt,
Log,
LogDescription,
EventFragment,
EventLog,
Interface,
TypedDataDomain,
ZeroAddress,
} from 'ethers';
Expand All @@ -25,10 +26,12 @@ import {
IexecPocoAccessors__factory,
IexecPocoBoostAccessors__factory,
RLC__factory,
Registry__factory,
WorkerpoolRegistry,
WorkerpoolRegistry__factory,
Workerpool__factory,
} from '../../typechain';
import { TransferEvent } from '../../typechain/contracts/registries/IRegistry';
import { IexecPoco1__factory } from '../../typechain/factories/contracts/modules/interfaces/IexecPoco1.v8.sol/IexecPoco1__factory';
import {
IexecOrders,
Expand Down Expand Up @@ -319,7 +322,7 @@ export class IexecWrapper {
ethers.ZeroHash,
)
.then((tx) => tx.wait());
return await extractRegistryEntryAddress(appReceipt, await appRegistry.getAddress());
return await extractRegistryEntryAddress(appReceipt);
}

async createDataset() {
Expand All @@ -336,10 +339,7 @@ export class IexecWrapper {
ethers.ZeroHash,
)
.then((tx) => tx.wait());
return await extractRegistryEntryAddress(
datasetReceipt,
await datasetRegistry.getAddress(),
);
return await extractRegistryEntryAddress(datasetReceipt);
}

/**
Expand Down Expand Up @@ -474,10 +474,7 @@ export class IexecWrapper {
const workerpoolReceipt = await workerpoolRegistry
.createWorkerpool(this.accounts.scheduler.address, 'my-workerpool')
.then((tx) => tx.wait());
return await extractRegistryEntryAddress(
workerpoolReceipt,
await workerpoolRegistry.getAddress(),
);
return await extractRegistryEntryAddress(workerpoolReceipt);
}

async getInitialFrozens(accounts: SignerWithAddress[]) {
Expand Down Expand Up @@ -520,81 +517,44 @@ export class IexecWrapper {
* Extract address of a newly created entry in a registry contract
* from the tx receipt.
* @param receipt contract receipt
* @param registryInstanceAddress address of the registry contract
* @returns address of the entry in checksum format.
*/
async function extractRegistryEntryAddress(
receipt: ContractTransactionReceipt | null,
registryInstanceAddress: string,
): Promise<string> {
if (!receipt) {
throw new Error('Undefined tx receipt');
}
const eventName = 'Transfer';
const eventAbi = [
'event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)',
];
const events = extractEventsFromReceipt(receipt, registryInstanceAddress, eventName, eventAbi);
if (events.length === 0) {
const registryInterface = Registry__factory.createInterface();
const event = extractEventFromReceipt(
receipt,
registryInterface,
registryInterface.getEvent('Transfer'),
) as any as TransferEvent.OutputObject;
if (!event) {
throw new Error('No event extracted from registry tx');
}
// Get registry address from event.
const lowercaseAddress = ethers.zeroPadValue(
ethers.toBeHex(BigInt(events[0].args.tokenId)),
20,
);
const lowercaseAddress = ethers.zeroPadValue(ethers.toBeHex(BigInt(event.tokenId)), 20);
// To checksum address.
return ethers.getAddress(lowercaseAddress);
}

/**
* Extract a specific event of a contract from tx receipt.
* @param txReceipt
* @param address
* @param eventName
* @param eventAbi
* @returns array of events or empty array.
* @param contractInterface
* @param eventFragment
* @returns event
*/
function extractEventsFromReceipt(
function extractEventFromReceipt(
txReceipt: ContractTransactionReceipt,
address: string,
eventName: string,
eventAbi: string[],
): LogDescription[] {
return extractEvents(txReceipt.logs, address, eventName, eventAbi);
}

/**
* Extract a specific event of a contract from tx logs.
* @param logs
* @param address
* @param eventName
* @param eventAbi
* @returns array of events or empty array.
*/
function extractEvents(
logs: Log[],
address: string,
eventName: string,
eventAbi: string[],
): LogDescription[] {
const eventInterface = new ethers.Interface(eventAbi);
const event = eventInterface.getEvent(eventName);
if (!event) {
throw new Error('Event name and abi mismatch');
}
const eventId = event.topicHash;
let extractedEvents = logs
// Get logs of the target contract.
.filter((log) => log.address === address && log.topics.includes(eventId))
// Parse logs to events.
.map((log) => eventInterface.parseLog(log))
// Get events with the target name.
.filter((event) => event && event.name === eventName);
// Get only non null elements.
// Note: using .filter(...) returns (LogDescription | null)[]
// which is not desired.
const events: LogDescription[] = [];
extractedEvents.forEach((element) => element && events.push(element));
return events;
contractInterface: Interface,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious whether we can use just the ABI of the event (Fragment) instead of all the contract's interface.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ABI of the event would we totally fine yes 👍

eventFragment: EventFragment,
) {
return (
txReceipt.logs.find(
(log) => contractInterface.parseLog(log)?.topic === eventFragment.topicHash,
) as EventLog
).args;
}