-
Notifications
You must be signed in to change notification settings - Fork 209
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: fetch token deposits from event logs #2168
base: master
Are you sure you want to change the base?
Changes from 3 commits
1e8f2c0
69f7c33
ea9a9aa
4f7631c
70786f4
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 |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import { fetchTokenDepositsFromEventLogs } from '../fetchTokenDepositsFromEventLogs' | ||
import { | ||
getQueryCoveringClassicAndNitroWithResults, | ||
getQueryCoveringClassicOnlyWithoutResults, | ||
getQueryCoveringClassicOnlyWithResults | ||
} from './fetchDepositsTestHelpers' | ||
|
||
const TIMEOUT = 30_000 | ||
|
||
describe('fetchTokenDepositsFromEventLogs', () => { | ||
it( | ||
'fetches no token deposits from event logs pre-nitro', | ||
async () => { | ||
const result = await fetchTokenDepositsFromEventLogs( | ||
getQueryCoveringClassicOnlyWithoutResults() | ||
) | ||
|
||
expect(result).toHaveLength(0) | ||
}, | ||
TIMEOUT | ||
) | ||
|
||
it( | ||
'fetches some token deposits from event logs pre-nitro', | ||
async () => { | ||
const result = await fetchTokenDepositsFromEventLogs({ | ||
...getQueryCoveringClassicOnlyWithResults(), | ||
sender: '0x981EA2202d2d33D26583E96f6e6449C1F9b6Bbb1' | ||
}) | ||
|
||
expect(result).toHaveLength(1) | ||
expect(result).toEqual( | ||
expect.arrayContaining([ | ||
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. How are the results significantly different from 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.
in fact, we need to add tests for token deposits fetches to the subgraph test |
||
// 14387620 | ||
expect.objectContaining({ | ||
txHash: | ||
'0xc112c54c261dabbd919132149226fc8a4c0196948e18dda947aa06e8b8b69064' | ||
}) | ||
]) | ||
) | ||
}, | ||
TIMEOUT | ||
) | ||
|
||
it( | ||
'fetches some token deposits from event logs pre-nitro and post-nitro', | ||
async () => { | ||
const result1 = await fetchTokenDepositsFromEventLogs({ | ||
...getQueryCoveringClassicAndNitroWithResults(), | ||
sender: '0x5049FEB67800e5BA82626c9f78FF9C458E0Eb66f' | ||
}) | ||
|
||
expect(result1).toHaveLength(1) | ||
expect(result1).toEqual( | ||
expect.arrayContaining([ | ||
// 15417417 | ||
expect.objectContaining({ | ||
txHash: | ||
'0xd9e72eba4548811425fd57def8aad238fcfdb0ced5a2af1d6b99f48ef51d52f0' | ||
}) | ||
]) | ||
) | ||
|
||
const result2 = await fetchTokenDepositsFromEventLogs({ | ||
...getQueryCoveringClassicAndNitroWithResults(), | ||
sender: '0x8594D8e9483473626908648A5539D9d65Ca2fe8d' | ||
}) | ||
|
||
expect(result2).toHaveLength(149) | ||
}, | ||
TIMEOUT | ||
) | ||
}) | ||
|
||
it( | ||
'fetches some token deposits from event logs post-nitro', | ||
async () => { | ||
const result = await fetchTokenDepositsFromEventLogs({ | ||
...getQueryCoveringClassicOnlyWithResults(), | ||
sender: '0x07aE8551Be970cB1cCa11Dd7a11F47Ae82e70E67', | ||
fromBlock: 21502346, | ||
toBlock: 21502471 | ||
}) | ||
|
||
expect(result).toHaveLength(2) | ||
expect(result).toEqual( | ||
expect.arrayContaining([ | ||
// 14310032 | ||
expect.objectContaining({ | ||
txHash: | ||
'0x583bea616664fa32f68d25822bb64f18c8186221c35919a567b3de5eb9c1ae7e' | ||
}), | ||
// 14309826 | ||
expect.objectContaining({ | ||
txHash: | ||
'0x012ef30f19eb89951590790f6e2882fe6a5dc7671e8cbddb2b09b6efd7ad892a' | ||
}) | ||
]) | ||
) | ||
}, | ||
TIMEOUT | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import { EventArgs, EventFetcher } from '@arbitrum/sdk' | ||
import { L1ERC20Gateway__factory } from '@arbitrum/sdk/dist/lib/abi/factories/L1ERC20Gateway__factory' | ||
import { DepositInitiatedEvent } from '@arbitrum/sdk/dist/lib/abi/L1ERC20Gateway' | ||
import { BlockTag } from '@ethersproject/providers' | ||
|
||
import { getProviderForChainId } from '@/token-bridge-sdk/utils' | ||
import { dedupeEvents } from './helpers' | ||
|
||
/** | ||
* Get the parent network events created by a deposit | ||
* @param parentChainId | ||
* @param gatewayAddress | ||
* @param filter | ||
* @param parentTokenAddress | ||
* @param fromAddress | ||
* @param toAddress | ||
* @returns | ||
*/ | ||
export async function getDepositEvents( | ||
parentChainId: number, | ||
gatewayAddress: string, | ||
filter: { fromBlock: BlockTag; toBlock: BlockTag }, | ||
parentTokenAddress?: string, | ||
fromAddress?: string, | ||
toAddress?: string | ||
): Promise<(EventArgs<DepositInitiatedEvent> & { txHash: string })[]> { | ||
const parentProvider = getProviderForChainId(parentChainId) | ||
|
||
const eventFetcher = new EventFetcher(parentProvider) | ||
const events = ( | ||
await eventFetcher.getEvents( | ||
L1ERC20Gateway__factory, | ||
contract => | ||
contract.filters.DepositInitiated( | ||
null, // parentToken | ||
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. Can't we pass 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. |
||
fromAddress || null, // _from | ||
toAddress || null // _to | ||
), | ||
{ ...filter, address: gatewayAddress } | ||
) | ||
).map(a => ({ txHash: a.transactionHash, ...a.event })) | ||
|
||
return parentTokenAddress | ||
? events.filter( | ||
log => | ||
log.l1Token.toLocaleLowerCase() === | ||
parentTokenAddress.toLocaleLowerCase() | ||
) | ||
: events | ||
} | ||
|
||
export type FetchTokenDepositsFromEventLogsParams = { | ||
sender?: string | ||
receiver?: string | ||
fromBlock: BlockTag | ||
toBlock: BlockTag | ||
parentChainId: number | ||
parentGatewayAddresses?: string[] | ||
} | ||
|
||
/** | ||
* Fetches initiated token deposits from event logs in range of [fromBlock, toBlock]. | ||
* | ||
* @param query Query params | ||
* @param query.sender Address that initiated the withdrawal | ||
* @param query.receiver Address that received the funds | ||
* @param query.fromBlock Start at this block number (including) | ||
* @param query.toBlock Stop at this block number (including) | ||
* @param query.childChainId child chain id | ||
* @param query.parentGatewayAddresses L2 gateway addresses to use | ||
*/ | ||
export async function fetchTokenDepositsFromEventLogs({ | ||
sender, | ||
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. We must decide between 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.
|
||
receiver, | ||
fromBlock, | ||
toBlock, | ||
parentChainId, | ||
parentGatewayAddresses = [] | ||
}: FetchTokenDepositsFromEventLogsParams) { | ||
const promises: ReturnType<typeof getDepositEvents>[] = [] | ||
|
||
parentGatewayAddresses.forEach(gatewayAddress => { | ||
// funds sent by this address | ||
if (sender) { | ||
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. Are we okay with returning empty data if no 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. This is how we're handling it at the moment with |
||
promises.push( | ||
getDepositEvents( | ||
parentChainId, | ||
gatewayAddress, | ||
{ fromBlock, toBlock }, | ||
undefined, | ||
sender, | ||
undefined | ||
) | ||
) | ||
} | ||
|
||
// funds received by this address | ||
if (receiver) { | ||
promises.push( | ||
getDepositEvents( | ||
parentChainId, | ||
gatewayAddress, | ||
{ fromBlock, toBlock }, | ||
undefined, | ||
undefined, | ||
receiver | ||
) | ||
) | ||
} | ||
}) | ||
|
||
// when getting funds received by this address we will also get duplicate txs returned in 'funds sent by this address' | ||
return dedupeEvents<DepositInitiatedEvent>( | ||
(await Promise.all(promises)).flat() | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,7 @@ | ||
import { Provider, BlockTag } from '@ethersproject/providers' | ||
import { Erc20Bridger, EventArgs } from '@arbitrum/sdk' | ||
import { Erc20Bridger } from '@arbitrum/sdk' | ||
import { WithdrawalInitiatedEvent } from '@arbitrum/sdk/dist/lib/abi/L2ArbitrumGateway' | ||
|
||
function dedupeEvents( | ||
events: (EventArgs<WithdrawalInitiatedEvent> & { | ||
txHash: string | ||
})[] | ||
) { | ||
return [...new Map(events.map(item => [item.txHash, item])).values()] | ||
} | ||
import { dedupeEvents } from '../deposits/helpers' | ||
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. Withdrawals shouldn't really import from deposits helpers, maybe we can move it to |
||
|
||
export type FetchTokenWithdrawalsFromEventLogsParams = { | ||
sender?: string | ||
|
@@ -72,5 +65,7 @@ export async function fetchTokenWithdrawalsFromEventLogs({ | |
}) | ||
|
||
// when getting funds received by this address we will also get duplicate txs returned in 'funds sent by this address' | ||
return dedupeEvents((await Promise.all(promises)).flat()) | ||
return dedupeEvents<WithdrawalInitiatedEvent>( | ||
(await Promise.all(promises)).flat() | ||
) | ||
} |
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.
nit: we could have
getArbitrumNetwork(42161)
as a variable