-
Notifications
You must be signed in to change notification settings - Fork 0
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: tvl by chain #39
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from "./invalidArgument.exception"; | ||
export * from "./dataDecode.exception"; | ||
export * from "./multicallNotFound.exception"; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export class MulticallNotFound extends Error { | ||
constructor() { | ||
super("Multicall contract address not found"); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ import { | |
ContractConstructorArgs, | ||
ContractFunctionArgs, | ||
ContractFunctionName, | ||
ContractFunctionParameters, | ||
ContractFunctionReturnType, | ||
createPublicClient, | ||
decodeAbiParameters, | ||
|
@@ -17,10 +18,16 @@ import { | |
Hex, | ||
http, | ||
HttpTransport, | ||
MulticallParameters, | ||
MulticallReturnType, | ||
toHex, | ||
} from "viem"; | ||
|
||
import { DataDecodeException, InvalidArgumentException } from "@zkchainhub/providers/exceptions"; | ||
import { | ||
DataDecodeException, | ||
InvalidArgumentException, | ||
MulticallNotFound, | ||
} from "@zkchainhub/providers/exceptions"; | ||
import { AbiWithConstructor } from "@zkchainhub/providers/types"; | ||
|
||
/** | ||
|
@@ -159,4 +166,22 @@ export class EvmProviderService { | |
throw new DataDecodeException("Error decoding return data with given AbiParameters"); | ||
} | ||
} | ||
|
||
/** | ||
* Similar to readContract, but batches up multiple functions | ||
* on a contract in a single RPC call via the multicall3 contract. | ||
* @param {MulticallParameters} args - The parameters for the multicall. | ||
* @returns — An array of results. If allowFailure is true, with accompanying status | ||
* @throws {MulticallNotFound} if the Multicall contract is not found. | ||
*/ | ||
async multicall< | ||
contracts extends readonly unknown[] = readonly ContractFunctionParameters[], | ||
allowFailure extends boolean = true, | ||
>( | ||
args: MulticallParameters<contracts, allowFailure>, | ||
): Promise<MulticallReturnType<contracts, allowFailure>> { | ||
if (!this.chain.contracts?.multicall3?.address) throw new MulticallNotFound(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good catch here |
||
|
||
return this.client.multicall<contracts, allowFailure>(args); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ import { localhost } from "viem/chains"; | |
import { Logger } from "winston"; | ||
|
||
import { EvmProviderService } from "@zkchainhub/providers"; | ||
import { DataDecodeException } from "@zkchainhub/providers/exceptions"; | ||
import { DataDecodeException, MulticallNotFound } from "@zkchainhub/providers/exceptions"; | ||
import { | ||
arrayAbiFixture, | ||
structAbiFixture, | ||
|
@@ -27,14 +27,14 @@ export const mockLogger: Partial<Logger> = { | |
error: jest.fn(), | ||
debug: jest.fn(), | ||
}; | ||
const testAbi = parseAbi([ | ||
"constructor(uint256 totalSupply)", | ||
"function balanceOf(address owner) view returns (uint256)", | ||
"function tokenURI(uint256 tokenId) pure returns (string)", | ||
]); | ||
|
||
describe("EvmProviderService", () => { | ||
let viemProvider: EvmProviderService; | ||
const testAbi = parseAbi([ | ||
"constructor(uint256 totalSupply)", | ||
"function balanceOf(address owner) view returns (uint256)", | ||
"function tokenURI(uint256 tokenId) pure returns (string)", | ||
]); | ||
|
||
beforeEach(async () => { | ||
const app: TestingModule = await Test.createTestingModule({ | ||
|
@@ -269,4 +269,91 @@ describe("EvmProviderService", () => { | |
expect(returnValue).toEqual(arrayAbiFixture.args[0]); | ||
}); | ||
}); | ||
describe("multicall", () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lets also add a test for the happy path |
||
it("throws a MulticallNotFound error if the Multicall contract is not found", async () => { | ||
const contracts = [ | ||
{ | ||
address: "0x123456789", | ||
abi: testAbi, | ||
functionName: "balanceOf", | ||
args: ["0x987654321"], | ||
} as const, | ||
]; | ||
|
||
await expect(viemProvider.multicall({ contracts })).rejects.toThrowError( | ||
MulticallNotFound, | ||
); | ||
}); | ||
}); | ||
}); | ||
|
||
describe("EvmProviderService (with mocked chain)", () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. may we just mock the chain instead of splitting the tests into 2 describes ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah you're right, in spanish criollo: "flashie" |
||
let viemProvider: EvmProviderService; | ||
|
||
beforeEach(async () => { | ||
const app: TestingModule = await Test.createTestingModule({ | ||
providers: [ | ||
{ | ||
provide: WINSTON_MODULE_PROVIDER, | ||
useValue: mockLogger, | ||
}, | ||
{ | ||
provide: EvmProviderService, | ||
useFactory: () => { | ||
const rpcUrl = "http://localhost:8545"; | ||
const chain = { | ||
...localhost, | ||
contracts: { multicall3: { address: "0x123456789" as viem.Address } }, | ||
}; | ||
return new EvmProviderService(rpcUrl, chain, mockLogger as Logger); | ||
}, | ||
}, | ||
], | ||
}).compile(); | ||
|
||
viemProvider = app.get<EvmProviderService>(EvmProviderService); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
jest.resetModules(); | ||
}); | ||
describe("multicall", () => { | ||
it("calls the multicall method of the Viem client with the correct arguments", async () => { | ||
const contracts = [ | ||
{ | ||
address: "0x123456789", | ||
abi: testAbi, | ||
functionName: "balanceOf", | ||
args: ["0x987654321"], | ||
} as const, | ||
{ | ||
address: "0x123456789", | ||
abi: testAbi, | ||
functionName: "tokenURI", | ||
args: [1n], | ||
} as const, | ||
{ | ||
address: "0x987654321", | ||
abi: testAbi, | ||
functionName: "totalSupply", | ||
args: [], | ||
} as const, | ||
]; | ||
|
||
const expectedReturnValue = [ | ||
{ result: 100n, status: true }, | ||
{ result: "tokenUri", status: true }, | ||
{ result: 1000n, status: true }, | ||
]; | ||
|
||
// Mock the multicall method of the Viem client | ||
jest.spyOn(mockClient, "multicall").mockResolvedValue(expectedReturnValue); | ||
|
||
const returnValue = await viemProvider.multicall({ contracts }); | ||
|
||
expect(returnValue).toEqual(expectedReturnValue); | ||
expect(mockClient.multicall).toHaveBeenCalledWith({ contracts }); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { Address } from "abitype"; | ||
|
||
// This is the address given to native ETH on L2 chains. | ||
// See: https://github.com/matter-labs/era-contracts/blob/8a70bbbc48125f5bde6189b4e3c6a3ee79631678/l1-contracts/contracts/common/Config.sol#L105 | ||
Comment on lines
+3
to
+4
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💯 |
||
export const ETH_TOKEN_ADDRESS: Address = "0x0000000000000000000000000000000000000001"; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from "./l1"; | ||
export * from "./addresses"; | ||
export const TOKEN_CACHE_TTL_IN_SEC = 60; | ||
export const BASE_CURRENCY = "usd"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we also use
multicall
to fetchTokenBalances of the SharedBridge ??? I mean, watching this now, makes me wonder that we are adding some overhead by using a batching contract for just iterating over multiple calls and having no computation on it.Let me know if you agree and i will added to
tech debt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah I thought it too jaja, sure add it to tech debt ser 🫡