@across-protocol/sdk 4.1.63-beta.1 → 4.1.63-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/arch/evm/BlockUtils.d.ts +15 -0
- package/dist/cjs/arch/evm/BlockUtils.js +218 -0
- package/dist/cjs/arch/evm/BlockUtils.js.map +1 -0
- package/dist/cjs/arch/evm/index.d.ts +1 -0
- package/dist/cjs/arch/evm/index.js +1 -0
- package/dist/cjs/arch/evm/index.js.map +1 -1
- package/dist/cjs/arch/svm/SpokeUtils.d.ts +3 -2
- package/dist/cjs/arch/svm/SpokeUtils.js +42 -12
- package/dist/cjs/arch/svm/SpokeUtils.js.map +1 -1
- package/dist/cjs/arch/svm/eventsClient.js +6 -6
- package/dist/cjs/arch/svm/eventsClient.js.map +1 -1
- package/dist/cjs/arch/svm/utils.d.ts +1 -0
- package/dist/cjs/arch/svm/utils.js +10 -2
- package/dist/cjs/arch/svm/utils.js.map +1 -1
- package/dist/cjs/clients/HubPoolClient.d.ts +3 -2
- package/dist/cjs/clients/HubPoolClient.js +2 -1
- package/dist/cjs/clients/HubPoolClient.js.map +1 -1
- package/dist/cjs/clients/SpokePoolClient/SVMSpokePoolClient.d.ts +1 -1
- package/dist/cjs/clients/SpokePoolClient/SVMSpokePoolClient.js +29 -2
- package/dist/cjs/clients/SpokePoolClient/SVMSpokePoolClient.js.map +1 -1
- package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.js +4 -3
- package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.js.map +1 -1
- package/dist/cjs/clients/mocks/MockSvmCpiEventsClient.d.ts +33 -0
- package/dist/cjs/clients/mocks/MockSvmCpiEventsClient.js +184 -0
- package/dist/cjs/clients/mocks/MockSvmCpiEventsClient.js.map +1 -0
- package/dist/cjs/clients/mocks/MockSvmSpokePoolClient.d.ts +30 -0
- package/dist/cjs/clients/mocks/MockSvmSpokePoolClient.js +90 -0
- package/dist/cjs/clients/mocks/MockSvmSpokePoolClient.js.map +1 -0
- package/dist/cjs/clients/mocks/index.d.ts +2 -0
- package/dist/cjs/clients/mocks/index.js +2 -0
- package/dist/cjs/clients/mocks/index.js.map +1 -1
- package/dist/cjs/constants.d.ts +1 -0
- package/dist/cjs/constants.js +2 -1
- package/dist/cjs/constants.js.map +1 -1
- package/dist/cjs/providers/index.d.ts +1 -1
- package/dist/cjs/providers/index.js +1 -2
- package/dist/cjs/providers/index.js.map +1 -1
- package/dist/cjs/providers/mocks/MockCachedSolanaRpcFactory.d.ts +5 -0
- package/dist/cjs/providers/mocks/MockCachedSolanaRpcFactory.js +21 -0
- package/dist/cjs/providers/mocks/MockCachedSolanaRpcFactory.js.map +1 -0
- package/dist/cjs/providers/mocks/MockRateLimitedSolanaRpcFactory.d.ts +5 -0
- package/dist/cjs/providers/mocks/MockRateLimitedSolanaRpcFactory.js +20 -0
- package/dist/cjs/providers/mocks/MockRateLimitedSolanaRpcFactory.js.map +1 -0
- package/dist/cjs/providers/mocks/MockSolanaRpcFactory.d.ts +13 -0
- package/dist/cjs/providers/mocks/MockSolanaRpcFactory.js +76 -0
- package/dist/cjs/providers/mocks/MockSolanaRpcFactory.js.map +1 -0
- package/dist/cjs/providers/mocks/index.d.ts +4 -0
- package/dist/cjs/providers/mocks/index.js +8 -0
- package/dist/cjs/providers/mocks/index.js.map +1 -0
- package/dist/cjs/providers/{mockProvider.js → mocks/mockEthersProvider.js} +2 -2
- package/dist/cjs/providers/mocks/mockEthersProvider.js.map +1 -0
- package/dist/cjs/relayFeeCalculator/chain-queries/baseQuery.js +5 -4
- package/dist/cjs/relayFeeCalculator/chain-queries/baseQuery.js.map +1 -1
- package/dist/cjs/relayFeeCalculator/chain-queries/factory.d.ts +9 -0
- package/dist/cjs/relayFeeCalculator/chain-queries/factory.js +1 -1
- package/dist/cjs/relayFeeCalculator/chain-queries/factory.js.map +1 -1
- package/dist/cjs/relayFeeCalculator/chain-queries/svmQuery.d.ts +6 -0
- package/dist/cjs/relayFeeCalculator/chain-queries/svmQuery.js +69 -34
- package/dist/cjs/relayFeeCalculator/chain-queries/svmQuery.js.map +1 -1
- package/dist/cjs/relayFeeCalculator/relayFeeCalculator.d.ts +11 -0
- package/dist/cjs/relayFeeCalculator/relayFeeCalculator.js +9 -3
- package/dist/cjs/relayFeeCalculator/relayFeeCalculator.js.map +1 -1
- package/dist/cjs/utils/BlockFinder.d.ts +22 -0
- package/dist/cjs/utils/BlockFinder.js +10 -0
- package/dist/cjs/utils/BlockFinder.js.map +1 -0
- package/dist/cjs/utils/BlockUtils.d.ts +2 -27
- package/dist/cjs/utils/BlockUtils.js +2 -208
- package/dist/cjs/utils/BlockUtils.js.map +1 -1
- package/dist/cjs/utils/TokenUtils.d.ts +18 -0
- package/dist/cjs/utils/index.d.ts +1 -0
- package/dist/cjs/utils/index.js +1 -0
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/esm/arch/evm/BlockUtils.d.ts +24 -0
- package/dist/esm/arch/evm/BlockUtils.js +250 -0
- package/dist/esm/arch/evm/BlockUtils.js.map +1 -0
- package/dist/esm/arch/evm/index.d.ts +1 -0
- package/dist/esm/arch/evm/index.js +1 -0
- package/dist/esm/arch/evm/index.js.map +1 -1
- package/dist/esm/arch/svm/SpokeUtils.d.ts +37 -2
- package/dist/esm/arch/svm/SpokeUtils.js +80 -13
- package/dist/esm/arch/svm/SpokeUtils.js.map +1 -1
- package/dist/esm/arch/svm/eventsClient.js +6 -6
- package/dist/esm/arch/svm/eventsClient.js.map +1 -1
- package/dist/esm/arch/svm/utils.d.ts +4 -0
- package/dist/esm/arch/svm/utils.js +11 -1
- package/dist/esm/arch/svm/utils.js.map +1 -1
- package/dist/esm/clients/HubPoolClient.d.ts +3 -2
- package/dist/esm/clients/HubPoolClient.js +3 -2
- package/dist/esm/clients/HubPoolClient.js.map +1 -1
- package/dist/esm/clients/SpokePoolClient/SVMSpokePoolClient.d.ts +1 -2
- package/dist/esm/clients/SpokePoolClient/SVMSpokePoolClient.js +34 -5
- package/dist/esm/clients/SpokePoolClient/SVMSpokePoolClient.js.map +1 -1
- package/dist/esm/clients/SpokePoolClient/SpokePoolClient.js +6 -4
- package/dist/esm/clients/SpokePoolClient/SpokePoolClient.js.map +1 -1
- package/dist/esm/clients/mocks/MockSvmCpiEventsClient.d.ts +33 -0
- package/dist/esm/clients/mocks/MockSvmCpiEventsClient.js +183 -0
- package/dist/esm/clients/mocks/MockSvmCpiEventsClient.js.map +1 -0
- package/dist/esm/clients/mocks/MockSvmSpokePoolClient.d.ts +30 -0
- package/dist/esm/clients/mocks/MockSvmSpokePoolClient.js +89 -0
- package/dist/esm/clients/mocks/MockSvmSpokePoolClient.js.map +1 -0
- package/dist/esm/clients/mocks/index.d.ts +2 -0
- package/dist/esm/clients/mocks/index.js +2 -0
- package/dist/esm/clients/mocks/index.js.map +1 -1
- package/dist/esm/constants.d.ts +1 -0
- package/dist/esm/constants.js +1 -0
- package/dist/esm/constants.js.map +1 -1
- package/dist/esm/providers/index.d.ts +1 -1
- package/dist/esm/providers/index.js +1 -2
- package/dist/esm/providers/index.js.map +1 -1
- package/dist/esm/providers/mocks/MockCachedSolanaRpcFactory.d.ts +5 -0
- package/dist/esm/providers/mocks/MockCachedSolanaRpcFactory.js +19 -0
- package/dist/esm/providers/mocks/MockCachedSolanaRpcFactory.js.map +1 -0
- package/dist/esm/providers/mocks/MockRateLimitedSolanaRpcFactory.d.ts +5 -0
- package/dist/esm/providers/mocks/MockRateLimitedSolanaRpcFactory.js +18 -0
- package/dist/esm/providers/mocks/MockRateLimitedSolanaRpcFactory.js.map +1 -0
- package/dist/esm/providers/mocks/MockSolanaRpcFactory.d.ts +13 -0
- package/dist/esm/providers/mocks/MockSolanaRpcFactory.js +74 -0
- package/dist/esm/providers/mocks/MockSolanaRpcFactory.js.map +1 -0
- package/dist/esm/providers/mocks/index.d.ts +4 -0
- package/dist/esm/providers/mocks/index.js +5 -0
- package/dist/esm/providers/mocks/index.js.map +1 -0
- package/dist/esm/providers/{mockProvider.js → mocks/mockEthersProvider.js} +2 -2
- package/dist/esm/providers/mocks/mockEthersProvider.js.map +1 -0
- package/dist/esm/relayFeeCalculator/chain-queries/baseQuery.js +6 -5
- package/dist/esm/relayFeeCalculator/chain-queries/baseQuery.js.map +1 -1
- package/dist/esm/relayFeeCalculator/chain-queries/factory.d.ts +9 -0
- package/dist/esm/relayFeeCalculator/chain-queries/factory.js +3 -3
- package/dist/esm/relayFeeCalculator/chain-queries/factory.js.map +1 -1
- package/dist/esm/relayFeeCalculator/chain-queries/svmQuery.d.ts +18 -0
- package/dist/esm/relayFeeCalculator/chain-queries/svmQuery.js +83 -36
- package/dist/esm/relayFeeCalculator/chain-queries/svmQuery.js.map +1 -1
- package/dist/esm/relayFeeCalculator/relayFeeCalculator.d.ts +21 -1
- package/dist/esm/relayFeeCalculator/relayFeeCalculator.js +9 -4
- package/dist/esm/relayFeeCalculator/relayFeeCalculator.js.map +1 -1
- package/dist/esm/utils/BlockFinder.d.ts +22 -0
- package/dist/esm/utils/BlockFinder.js +7 -0
- package/dist/esm/utils/BlockFinder.js.map +1 -0
- package/dist/esm/utils/BlockUtils.d.ts +2 -36
- package/dist/esm/utils/BlockUtils.js +2 -243
- package/dist/esm/utils/BlockUtils.js.map +1 -1
- package/dist/esm/utils/TokenUtils.d.ts +18 -0
- package/dist/esm/utils/index.d.ts +1 -0
- package/dist/esm/utils/index.js +1 -0
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/types/arch/evm/BlockUtils.d.ts +25 -0
- package/dist/types/arch/evm/BlockUtils.d.ts.map +1 -0
- package/dist/types/arch/evm/index.d.ts +1 -0
- package/dist/types/arch/evm/index.d.ts.map +1 -1
- package/dist/types/arch/svm/SpokeUtils.d.ts +37 -2
- package/dist/types/arch/svm/SpokeUtils.d.ts.map +1 -1
- package/dist/types/arch/svm/eventsClient.d.ts.map +1 -1
- package/dist/types/arch/svm/utils.d.ts +4 -0
- package/dist/types/arch/svm/utils.d.ts.map +1 -1
- package/dist/types/clients/HubPoolClient.d.ts +3 -2
- package/dist/types/clients/HubPoolClient.d.ts.map +1 -1
- package/dist/types/clients/SpokePoolClient/SVMSpokePoolClient.d.ts +1 -2
- package/dist/types/clients/SpokePoolClient/SVMSpokePoolClient.d.ts.map +1 -1
- package/dist/types/clients/SpokePoolClient/SpokePoolClient.d.ts.map +1 -1
- package/dist/types/clients/mocks/MockSvmCpiEventsClient.d.ts +34 -0
- package/dist/types/clients/mocks/MockSvmCpiEventsClient.d.ts.map +1 -0
- package/dist/types/clients/mocks/MockSvmSpokePoolClient.d.ts +31 -0
- package/dist/types/clients/mocks/MockSvmSpokePoolClient.d.ts.map +1 -0
- package/dist/types/clients/mocks/index.d.ts +2 -0
- package/dist/types/clients/mocks/index.d.ts.map +1 -1
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/constants.d.ts.map +1 -1
- package/dist/types/providers/index.d.ts +1 -1
- package/dist/types/providers/index.d.ts.map +1 -1
- package/dist/types/providers/mocks/MockCachedSolanaRpcFactory.d.ts +6 -0
- package/dist/types/providers/mocks/MockCachedSolanaRpcFactory.d.ts.map +1 -0
- package/dist/types/providers/mocks/MockRateLimitedSolanaRpcFactory.d.ts +6 -0
- package/dist/types/providers/mocks/MockRateLimitedSolanaRpcFactory.d.ts.map +1 -0
- package/dist/types/providers/mocks/MockSolanaRpcFactory.d.ts +14 -0
- package/dist/types/providers/mocks/MockSolanaRpcFactory.d.ts.map +1 -0
- package/dist/types/providers/mocks/index.d.ts +5 -0
- package/dist/types/providers/mocks/index.d.ts.map +1 -0
- package/dist/types/providers/{mockProvider.d.ts → mocks/mockEthersProvider.d.ts} +1 -1
- package/dist/types/providers/mocks/mockEthersProvider.d.ts.map +1 -0
- package/dist/types/relayFeeCalculator/chain-queries/baseQuery.d.ts.map +1 -1
- package/dist/types/relayFeeCalculator/chain-queries/factory.d.ts +9 -0
- package/dist/types/relayFeeCalculator/chain-queries/factory.d.ts.map +1 -1
- package/dist/types/relayFeeCalculator/chain-queries/svmQuery.d.ts +18 -0
- package/dist/types/relayFeeCalculator/chain-queries/svmQuery.d.ts.map +1 -1
- package/dist/types/relayFeeCalculator/relayFeeCalculator.d.ts +21 -1
- package/dist/types/relayFeeCalculator/relayFeeCalculator.d.ts.map +1 -1
- package/dist/types/utils/BlockFinder.d.ts +23 -0
- package/dist/types/utils/BlockFinder.d.ts.map +1 -0
- package/dist/types/utils/BlockUtils.d.ts +2 -36
- package/dist/types/utils/BlockUtils.d.ts.map +1 -1
- package/dist/types/utils/TokenUtils.d.ts +18 -0
- package/dist/types/utils/TokenUtils.d.ts.map +1 -1
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/index.d.ts.map +1 -1
- package/package.json +2 -3
- package/src/arch/evm/BlockUtils.ts +209 -0
- package/src/arch/evm/index.ts +1 -0
- package/src/arch/svm/SpokeUtils.ts +87 -17
- package/src/arch/svm/eventsClient.ts +13 -5
- package/src/arch/svm/utils.ts +12 -1
- package/src/clients/HubPoolClient.ts +3 -3
- package/src/clients/SpokePoolClient/SVMSpokePoolClient.ts +27 -3
- package/src/clients/SpokePoolClient/SpokePoolClient.ts +6 -3
- package/src/clients/mocks/MockSvmCpiEventsClient.ts +226 -0
- package/src/clients/mocks/MockSvmSpokePoolClient.ts +119 -0
- package/src/clients/mocks/index.ts +2 -0
- package/src/constants.ts +1 -0
- package/src/providers/index.ts +1 -1
- package/src/providers/mocks/MockCachedSolanaRpcFactory.ts +15 -0
- package/src/providers/mocks/MockRateLimitedSolanaRpcFactory.ts +14 -0
- package/src/providers/mocks/MockSolanaRpcFactory.ts +55 -0
- package/src/providers/mocks/index.ts +4 -0
- package/src/providers/{mockProvider.ts → mocks/mockEthersProvider.ts} +1 -1
- package/src/relayFeeCalculator/chain-queries/baseQuery.ts +6 -6
- package/src/relayFeeCalculator/chain-queries/factory.ts +3 -3
- package/src/relayFeeCalculator/chain-queries/svmQuery.ts +59 -27
- package/src/relayFeeCalculator/relayFeeCalculator.ts +15 -3
- package/src/utils/BlockFinder.ts +26 -0
- package/src/utils/BlockUtils.ts +5 -215
- package/src/utils/index.ts +1 -0
- package/dist/cjs/providers/mockProvider.js.map +0 -1
- package/dist/esm/providers/mockProvider.js.map +0 -1
- package/dist/types/providers/mockProvider.d.ts.map +0 -1
- /package/dist/cjs/providers/{mockProvider.d.ts → mocks/mockEthersProvider.d.ts} +0 -0
- /package/dist/esm/providers/{mockProvider.d.ts → mocks/mockEthersProvider.d.ts} +0 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import assert from "assert";
|
|
2
|
+
import { Provider, Block as EthersBlock } from "@ethersproject/abstract-provider";
|
|
3
|
+
import { clamp, sortedIndexBy } from "lodash";
|
|
4
|
+
import { chainIsOPStack, getNetworkName } from "../../utils/NetworkUtils";
|
|
5
|
+
import { isDefined } from "../../utils/TypeGuards";
|
|
6
|
+
import {
|
|
7
|
+
BlockFinder,
|
|
8
|
+
type Block,
|
|
9
|
+
type BlockFinderOpts as Opts,
|
|
10
|
+
type BlockTimeAverage,
|
|
11
|
+
type BlockFinderHints,
|
|
12
|
+
} from "../../utils/BlockFinder";
|
|
13
|
+
import { getCurrentTime } from "../../utils/TimeUtils";
|
|
14
|
+
import { CHAIN_IDs } from "../../constants";
|
|
15
|
+
|
|
16
|
+
// Extension of the EthersBlock type which implements `Block`.
|
|
17
|
+
interface EVMBlock extends Block, EthersBlock {}
|
|
18
|
+
|
|
19
|
+
// Archive requests typically commence at 128 blocks past the head of the chain.
|
|
20
|
+
// Round down to 120 blocks to avoid slipping into archive territory.
|
|
21
|
+
const defaultBlockRange = 120;
|
|
22
|
+
|
|
23
|
+
// Default offset to the high block number. This is subtracted from the block number of the high block
|
|
24
|
+
// when it is queried from the network, rather than having been specified by the caller. This is useful
|
|
25
|
+
// since the supplied Provider instance may be backed by multiple RPC providers, which can lead to some
|
|
26
|
+
// providers running slower than others and taking time to synchronise on the latest block.
|
|
27
|
+
const defaultHighBlockOffset = 10;
|
|
28
|
+
|
|
29
|
+
// Retain computations for 15 minutes.
|
|
30
|
+
const cacheTTL = 60 * 15;
|
|
31
|
+
const now = getCurrentTime(); // Seed the cache with initial values.
|
|
32
|
+
const blockTimes: { [chainId: number]: BlockTimeAverage } = {
|
|
33
|
+
[CHAIN_IDs.INK]: { average: 1, timestamp: now, blockRange: 1 },
|
|
34
|
+
[CHAIN_IDs.LINEA]: { average: 3, timestamp: now, blockRange: 1 },
|
|
35
|
+
[CHAIN_IDs.MAINNET]: { average: 12.5, timestamp: now, blockRange: 1 },
|
|
36
|
+
[CHAIN_IDs.OPTIMISM]: { average: 2, timestamp: now, blockRange: 1 },
|
|
37
|
+
[CHAIN_IDs.UNICHAIN]: { average: 1, timestamp: now, blockRange: 1 },
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @description Compute the average block time over a block range.
|
|
42
|
+
* @returns Average number of seconds per block.
|
|
43
|
+
*/
|
|
44
|
+
export async function averageBlockTime(
|
|
45
|
+
provider: Provider,
|
|
46
|
+
{ highBlock, highBlockOffset, blockRange }: Opts = {}
|
|
47
|
+
): Promise<Pick<BlockTimeAverage, "average" | "blockRange">> {
|
|
48
|
+
// Does not block for StaticJsonRpcProvider.
|
|
49
|
+
const { chainId } = await provider.getNetwork();
|
|
50
|
+
|
|
51
|
+
// OP stack chains inherit Optimism block times, but can be overridden.
|
|
52
|
+
const cache = blockTimes[chainId] ?? (chainIsOPStack(chainId) ? blockTimes[CHAIN_IDs.OPTIMISM] : undefined);
|
|
53
|
+
|
|
54
|
+
const now = getCurrentTime();
|
|
55
|
+
if (isDefined(cache) && now < cache.timestamp + cacheTTL) {
|
|
56
|
+
return { average: cache.average, blockRange: cache.blockRange };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// If the caller was not specific about highBlock, resolve it via the RPC provider. Subtract an offset
|
|
60
|
+
// to account for various RPC provider sync issues that might occur when querting the latest block.
|
|
61
|
+
if (!isDefined(highBlock)) {
|
|
62
|
+
highBlock = await provider.getBlockNumber();
|
|
63
|
+
highBlock -= highBlockOffset ?? defaultHighBlockOffset;
|
|
64
|
+
}
|
|
65
|
+
blockRange ??= defaultBlockRange;
|
|
66
|
+
|
|
67
|
+
const earliestBlockNumber = highBlock - blockRange;
|
|
68
|
+
const [firstBlock, lastBlock] = await Promise.all([
|
|
69
|
+
provider.getBlock(earliestBlockNumber),
|
|
70
|
+
provider.getBlock(highBlock),
|
|
71
|
+
]);
|
|
72
|
+
[firstBlock, lastBlock].forEach((block: Block | undefined) => {
|
|
73
|
+
if (!isDefined(block?.timestamp)) {
|
|
74
|
+
const network = getNetworkName(chainId);
|
|
75
|
+
const blockNumber = block === firstBlock ? earliestBlockNumber : highBlock;
|
|
76
|
+
throw new Error(`BlockFinder: Failed to fetch block ${blockNumber} on ${network}`);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const average = (lastBlock.timestamp - firstBlock.timestamp) / blockRange;
|
|
81
|
+
blockTimes[chainId] = { timestamp: now, average, blockRange };
|
|
82
|
+
|
|
83
|
+
return { average, blockRange };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function estimateBlocksElapsed(seconds: number, cushionPercentage = 0.0, provider: Provider): Promise<number> {
|
|
87
|
+
const cushionMultiplier = cushionPercentage + 1.0;
|
|
88
|
+
const { average } = await averageBlockTime(provider);
|
|
89
|
+
return Math.floor((seconds * cushionMultiplier) / average);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export class EVMBlockFinder extends BlockFinder<EVMBlock> {
|
|
93
|
+
constructor(
|
|
94
|
+
private readonly provider: Provider,
|
|
95
|
+
private readonly blocks: EVMBlock[] = []
|
|
96
|
+
) {
|
|
97
|
+
super();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @notice Gets the latest block whose timestamp is <= the provided timestamp.
|
|
102
|
+
* @param number Timestamp timestamp to search.
|
|
103
|
+
* @param hints Optional low and high block to bound the search space.
|
|
104
|
+
*/
|
|
105
|
+
public async getBlockForTimestamp(timestamp: number | string, hints: BlockFinderHints = {}): Promise<EVMBlock> {
|
|
106
|
+
timestamp = Number(timestamp);
|
|
107
|
+
assert(timestamp !== undefined && timestamp !== null, "timestamp must be provided");
|
|
108
|
+
// If the last block we have stored is too early, grab the latest block.
|
|
109
|
+
if (this.blocks.length === 0 || this.blocks[this.blocks.length - 1].timestamp < timestamp) {
|
|
110
|
+
const block = await this.getLatestBlock();
|
|
111
|
+
if (timestamp >= block.timestamp) return block;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Prime the BlockFinder cache with any supplied hints.
|
|
115
|
+
// If the hint is accurate, then this will bypass the subsequent estimation.
|
|
116
|
+
await Promise.all(
|
|
117
|
+
Object.values(hints)
|
|
118
|
+
.filter((blockNumber) => isDefined(blockNumber))
|
|
119
|
+
.map((blockNumber) => this.getBlock(blockNumber))
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
// Check the first block. If it's greater than our timestamp, we need to find an earlier block.
|
|
123
|
+
if (this.blocks[0].timestamp > timestamp) {
|
|
124
|
+
const initialBlock = this.blocks[0];
|
|
125
|
+
// We use a 2x cushion to reduce the number of iterations in the following loop and increase the chance
|
|
126
|
+
// that the first block we find sets a floor for the target timestamp. The loop converges on the correct block
|
|
127
|
+
// slower than the following incremental search performed by `findBlock`, so we want to minimize the number of
|
|
128
|
+
// loop iterations in favor of searching more blocks over the `findBlock` search.
|
|
129
|
+
const cushion = 1;
|
|
130
|
+
const incrementDistance = Math.max(
|
|
131
|
+
// Ensure the increment block distance is _at least_ a single block to prevent an infinite loop.
|
|
132
|
+
await estimateBlocksElapsed(initialBlock.timestamp - timestamp, cushion, this.provider),
|
|
133
|
+
1
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
// Search backwards by a constant increment until we find a block before the timestamp or hit block 0.
|
|
137
|
+
for (let multiplier = 1; ; multiplier++) {
|
|
138
|
+
const distance = multiplier * incrementDistance;
|
|
139
|
+
const blockNumber = Math.max(0, initialBlock.number - distance);
|
|
140
|
+
const block = await this.getBlock(blockNumber);
|
|
141
|
+
if (block.timestamp <= timestamp) break; // Found an earlier block.
|
|
142
|
+
assert(blockNumber > 0, "timestamp is before block 0"); // Block 0 was not earlier than this timestamp. The row.
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Find the index where the block would be inserted and use that as the end block (since it is >= the timestamp).
|
|
147
|
+
const index = sortedIndexBy(this.blocks, { timestamp } as Block, "timestamp");
|
|
148
|
+
return this.findBlock(this.blocks[index - 1], this.blocks[index], timestamp);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Grabs the most recent block and caches it.
|
|
152
|
+
private async getLatestBlock() {
|
|
153
|
+
const block = await this.provider.getBlock("latest");
|
|
154
|
+
const index = sortedIndexBy(this.blocks, block, "number");
|
|
155
|
+
if (this.blocks[index]?.number !== block.number) this.blocks.splice(index, 0, block);
|
|
156
|
+
return this.blocks[index];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Grabs the block for a particular number and caches it.
|
|
160
|
+
private async getBlock(number: number) {
|
|
161
|
+
let index = sortedIndexBy(this.blocks, { number } as Block, "number");
|
|
162
|
+
if (this.blocks[index]?.number === number) return this.blocks[index]; // Return early if block already exists.
|
|
163
|
+
const block = await this.provider.getBlock(number);
|
|
164
|
+
|
|
165
|
+
// Recompute the index after the async call since the state of this.blocks could have changed!
|
|
166
|
+
index = sortedIndexBy(this.blocks, { number } as Block, "number");
|
|
167
|
+
|
|
168
|
+
// Rerun this check to avoid duplicate insertion.
|
|
169
|
+
if (this.blocks[index]?.number === number) return this.blocks[index];
|
|
170
|
+
this.blocks.splice(index, 0, block); // A simple insert at index.
|
|
171
|
+
return block;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Return the latest block, between startBlock and endBlock, whose timestamp is <= timestamp.
|
|
175
|
+
// Effectively, this is an interpolation search algorithm to minimize block requests.
|
|
176
|
+
// Note: startBlock and endBlock _must_ be different blocks.
|
|
177
|
+
private async findBlock(_startBlock: EVMBlock, _endBlock: EVMBlock, timestamp: number): Promise<EVMBlock> {
|
|
178
|
+
const [startBlock, endBlock] = [_startBlock, _endBlock];
|
|
179
|
+
// In the case of equality, the endBlock is expected to be passed as the one whose timestamp === the requested
|
|
180
|
+
// timestamp.
|
|
181
|
+
if (endBlock.timestamp === timestamp) return endBlock;
|
|
182
|
+
|
|
183
|
+
// If there's no equality, but the blocks are adjacent, return the startBlock, since we want the returned block's
|
|
184
|
+
// timestamp to be <= the requested timestamp.
|
|
185
|
+
if (endBlock.number === startBlock.number + 1) return startBlock;
|
|
186
|
+
|
|
187
|
+
assert(endBlock.number !== startBlock.number, "startBlock cannot equal endBlock");
|
|
188
|
+
assert(
|
|
189
|
+
timestamp < endBlock.timestamp && timestamp > startBlock.timestamp,
|
|
190
|
+
"timestamp not in between start and end blocks"
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
// Interpolating the timestamp we're searching for to block numbers.
|
|
194
|
+
const totalTimeDifference = endBlock.timestamp - startBlock.timestamp;
|
|
195
|
+
const totalBlockDistance = endBlock.number - startBlock.number;
|
|
196
|
+
const blockPercentile = (timestamp - startBlock.timestamp) / totalTimeDifference;
|
|
197
|
+
const estimatedBlock = startBlock.number + Math.round(blockPercentile * totalBlockDistance);
|
|
198
|
+
|
|
199
|
+
// Clamp ensures the estimated block is strictly greater than the start block and strictly less than the end block.
|
|
200
|
+
const newBlock = await this.getBlock(clamp(estimatedBlock, startBlock.number + 1, endBlock.number - 1));
|
|
201
|
+
|
|
202
|
+
// Depending on whether the new block is below or above the timestamp, narrow the search space accordingly.
|
|
203
|
+
if (newBlock.timestamp < timestamp) {
|
|
204
|
+
return this.findBlock(newBlock, endBlock, timestamp);
|
|
205
|
+
} else {
|
|
206
|
+
return this.findBlock(startBlock, newBlock, timestamp);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
package/src/arch/evm/index.ts
CHANGED
|
@@ -21,22 +21,29 @@ import {
|
|
|
21
21
|
import assert from "assert";
|
|
22
22
|
import { arrayify, hexZeroPad, hexlify } from "ethers/lib/utils";
|
|
23
23
|
import { Logger } from "winston";
|
|
24
|
+
|
|
24
25
|
import { CHAIN_IDs } from "../../constants";
|
|
25
|
-
import { Deposit, FillStatus, FillWithBlock, RelayData } from "../../interfaces";
|
|
26
|
+
import { Deposit, DepositWithBlock, FillStatus, FillWithBlock, RelayData } from "../../interfaces";
|
|
26
27
|
import {
|
|
27
28
|
BigNumber,
|
|
29
|
+
isUnsafeDepositId,
|
|
28
30
|
SvmAddress,
|
|
29
|
-
chainIsSvm,
|
|
30
|
-
chunk,
|
|
31
31
|
getTokenInfo,
|
|
32
32
|
isDefined,
|
|
33
|
-
isUnsafeDepositId,
|
|
34
|
-
keccak256,
|
|
35
33
|
toAddressType,
|
|
34
|
+
keccak256,
|
|
35
|
+
chainIsSvm,
|
|
36
|
+
chunk,
|
|
36
37
|
} from "../../utils";
|
|
37
|
-
import {
|
|
38
|
+
import { getStatePda, SvmCpiEventsClient, getFillStatusPda, unwrapEventData, getEventAuthority } from "./";
|
|
38
39
|
import { SVMEventNames, SVMProvider } from "./types";
|
|
39
40
|
|
|
41
|
+
/**
|
|
42
|
+
* @note: Average Solana slot duration is about 400-500ms. We can be conservative
|
|
43
|
+
* and choose 400 to ensure that the most slots get included in our ranges
|
|
44
|
+
*/
|
|
45
|
+
export const SLOT_DURATION_MS = 400;
|
|
46
|
+
|
|
40
47
|
/**
|
|
41
48
|
* @param spokePool SpokePool Contract instance.
|
|
42
49
|
* @param deposit V3Deopsit instance.
|
|
@@ -81,17 +88,76 @@ export function getDepositIdAtBlock(_contract: unknown, _blockTag: number): Prom
|
|
|
81
88
|
throw new Error("getDepositIdAtBlock: not implemented");
|
|
82
89
|
}
|
|
83
90
|
|
|
84
|
-
|
|
85
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Finds deposit events within a 2-day window ending at the specified slot.
|
|
93
|
+
*
|
|
94
|
+
* @remarks
|
|
95
|
+
* This implementation uses a slot-limited search approach because Solana PDA state has
|
|
96
|
+
* limitations that prevent directly referencing old deposit IDs. Unlike EVM chains where
|
|
97
|
+
* we might use binary search across the entire chain history, in Solana we must query within
|
|
98
|
+
* a constrained slot range.
|
|
99
|
+
*
|
|
100
|
+
* The search window is calculated by:
|
|
101
|
+
* 1. Using the provided slot (or current confirmed slot if none is provided)
|
|
102
|
+
* 2. Looking back 2 days worth of slots from that point
|
|
103
|
+
*
|
|
104
|
+
* We use a 2-day window because:
|
|
105
|
+
* 1. Most valid deposits that need to be processed will be recent
|
|
106
|
+
* 2. This covers multiple bundle submission periods
|
|
107
|
+
* 3. It balances performance with practical deposit age
|
|
108
|
+
*
|
|
109
|
+
* @important
|
|
110
|
+
* This function may return `undefined` for valid deposit IDs that are older than the search
|
|
111
|
+
* window (approximately 2 days before the specified slot). This is an acceptable limitation
|
|
112
|
+
* as deposits this old are typically not relevant to current operations.
|
|
113
|
+
*
|
|
114
|
+
* @param eventClient - SvmCpiEventsClient instance
|
|
115
|
+
* @param depositId - The deposit ID to search for
|
|
116
|
+
* @param slot - The slot to search up to (defaults to current slot). The search will look
|
|
117
|
+
* for deposits between (slot - secondsLookback) and slot.
|
|
118
|
+
* @param secondsLookback - The number of seconds to look back for deposits (defaults to 2 days).
|
|
119
|
+
* @returns The deposit if found within the slot window, undefined otherwise
|
|
120
|
+
*/
|
|
121
|
+
export async function findDeposit(
|
|
122
|
+
eventClient: SvmCpiEventsClient,
|
|
86
123
|
depositId: BigNumber,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
): Promise<
|
|
124
|
+
slot?: bigint,
|
|
125
|
+
secondsLookback = 2 * 24 * 60 * 60 // 2 days
|
|
126
|
+
): Promise<DepositWithBlock | undefined> {
|
|
90
127
|
// We can only perform this search when we have a safe deposit ID.
|
|
91
128
|
if (isUnsafeDepositId(depositId)) {
|
|
92
129
|
throw new Error(`Cannot binary search for depositId ${depositId}`);
|
|
93
130
|
}
|
|
94
|
-
|
|
131
|
+
|
|
132
|
+
const provider = eventClient.getRpc();
|
|
133
|
+
const currentSlot = await provider.getSlot({ commitment: "confirmed" }).send();
|
|
134
|
+
|
|
135
|
+
// If no slot is provided, use the current slot
|
|
136
|
+
// If a slot is provided, ensure it's not in the future
|
|
137
|
+
const endSlot = slot !== undefined ? BigInt(Math.min(Number(slot), Number(currentSlot))) : currentSlot;
|
|
138
|
+
|
|
139
|
+
// Calculate start slot (approximately secondsLookback seconds earlier)
|
|
140
|
+
const slotsInElapsed = BigInt(Math.round((secondsLookback * 1000) / SLOT_DURATION_MS));
|
|
141
|
+
const startSlot = endSlot - slotsInElapsed;
|
|
142
|
+
|
|
143
|
+
// Query for the deposit events with this limited slot range. Filter by deposit id.
|
|
144
|
+
const depositEvent = (await eventClient.queryEvents("FundsDeposited", startSlot, endSlot))?.find((event) =>
|
|
145
|
+
depositId.eq((event.data as unknown as { depositId: BigNumber }).depositId)
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
// If no deposit event is found, return undefined
|
|
149
|
+
if (!depositEvent) {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Return the deposit event with block info
|
|
154
|
+
return {
|
|
155
|
+
txnRef: depositEvent.signature.toString(),
|
|
156
|
+
blockNumber: Number(depositEvent.slot),
|
|
157
|
+
txnIndex: 0,
|
|
158
|
+
logIndex: 0,
|
|
159
|
+
...(unwrapEventData(depositEvent.data) as Record<string, unknown>),
|
|
160
|
+
} as DepositWithBlock;
|
|
95
161
|
}
|
|
96
162
|
|
|
97
163
|
/**
|
|
@@ -318,9 +384,9 @@ export async function fillRelayInstruction(
|
|
|
318
384
|
getFillStatusPda(spokePool.toV2Address(), deposit, deposit.destinationChainId),
|
|
319
385
|
getEventAuthority(),
|
|
320
386
|
]);
|
|
321
|
-
const depositIdBuffer =
|
|
322
|
-
const shortenedBuffer = Buffer.from(deposit.depositId.toHexString().slice(2), "hex");
|
|
323
|
-
|
|
387
|
+
const depositIdBuffer = new Uint8Array(32);
|
|
388
|
+
const shortenedBuffer = new Uint8Array(Buffer.from(deposit.depositId.toHexString().slice(2), "hex"));
|
|
389
|
+
depositIdBuffer.set(shortenedBuffer, 32 - shortenedBuffer.length);
|
|
324
390
|
|
|
325
391
|
return SvmSpokeClient.getFillRelayInstruction({
|
|
326
392
|
signer: relayer,
|
|
@@ -343,7 +409,7 @@ export async function fillRelayInstruction(
|
|
|
343
409
|
originChainId: BigInt(deposit.originChainId),
|
|
344
410
|
fillDeadline: deposit.fillDeadline,
|
|
345
411
|
exclusivityDeadline: deposit.exclusivityDeadline,
|
|
346
|
-
depositId:
|
|
412
|
+
depositId: depositIdBuffer,
|
|
347
413
|
message: new Uint8Array(Buffer.from(deposit.message.slice(2), "hex")),
|
|
348
414
|
}),
|
|
349
415
|
repaymentChainId: some(BigInt(repaymentChainId)),
|
|
@@ -409,7 +475,11 @@ export async function getAssociatedTokenAddress(
|
|
|
409
475
|
): Promise<Address<string>> {
|
|
410
476
|
const [associatedToken] = await getProgramDerivedAddress({
|
|
411
477
|
programAddress: ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
|
|
412
|
-
seeds: [
|
|
478
|
+
seeds: [
|
|
479
|
+
new Uint8Array(owner.toBuffer()),
|
|
480
|
+
new Uint8Array(SvmAddress.from(tokenProgramId).toBuffer()),
|
|
481
|
+
new Uint8Array(mint.toBuffer()),
|
|
482
|
+
],
|
|
413
483
|
});
|
|
414
484
|
return associatedToken;
|
|
415
485
|
}
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { Idl } from "@coral-xyz/anchor";
|
|
2
2
|
import { getDeployedAddress, SvmSpokeIdl } from "@across-protocol/contracts";
|
|
3
3
|
import { getSolanaChainId } from "@across-protocol/contracts/dist/src/svm/web3-v1";
|
|
4
|
-
import
|
|
4
|
+
import {
|
|
5
|
+
address,
|
|
6
|
+
Address,
|
|
7
|
+
Commitment,
|
|
8
|
+
getProgramDerivedAddress,
|
|
9
|
+
GetSignaturesForAddressApi,
|
|
10
|
+
GetTransactionApi,
|
|
11
|
+
Signature,
|
|
12
|
+
} from "@solana/kit";
|
|
5
13
|
import { bs58, chainIsSvm, getMessageHash } from "../../utils";
|
|
6
14
|
import { EventName, EventWithData, SVMProvider } from "./types";
|
|
7
15
|
import { decodeEvent, isDevnet } from "./utils";
|
|
@@ -56,12 +64,12 @@ export class SvmCpiEventsClient {
|
|
|
56
64
|
}
|
|
57
65
|
|
|
58
66
|
public static async createFor(rpc: SVMProvider, programId: string, idl: Idl): Promise<SvmCpiEventsClient> {
|
|
59
|
-
const
|
|
60
|
-
const [eventAuthority] = await
|
|
61
|
-
programAddress
|
|
67
|
+
const programAddress = address(programId);
|
|
68
|
+
const [eventAuthority] = await getProgramDerivedAddress({
|
|
69
|
+
programAddress,
|
|
62
70
|
seeds: ["__event_authority"],
|
|
63
71
|
});
|
|
64
|
-
return new SvmCpiEventsClient(rpc,
|
|
72
|
+
return new SvmCpiEventsClient(rpc, programAddress, eventAuthority, idl);
|
|
65
73
|
}
|
|
66
74
|
|
|
67
75
|
/**
|
package/src/arch/svm/utils.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import bs58 from "bs58";
|
|
2
|
+
import { ethers } from "ethers";
|
|
2
3
|
import { BN, BorshEventCoder, Idl } from "@coral-xyz/anchor";
|
|
3
4
|
import {
|
|
4
5
|
Address,
|
|
@@ -9,6 +10,7 @@ import {
|
|
|
9
10
|
isAddress,
|
|
10
11
|
type TransactionSigner,
|
|
11
12
|
} from "@solana/kit";
|
|
13
|
+
import { SvmSpokeClient } from "@across-protocol/contracts";
|
|
12
14
|
import { FillType, RelayData } from "../../interfaces";
|
|
13
15
|
import { BigNumber, SvmAddress, getRelayDataHash, isUint8Array } from "../../utils";
|
|
14
16
|
import { EventName, SVMEventNames, SVMProvider } from "./types";
|
|
@@ -220,3 +222,12 @@ export const getEventAuthority = async () => {
|
|
|
220
222
|
});
|
|
221
223
|
return eventAuthority;
|
|
222
224
|
};
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Returns a random SVM address.
|
|
228
|
+
*/
|
|
229
|
+
export function getRandomSvmAddress() {
|
|
230
|
+
const bytes = ethers.utils.randomBytes(32);
|
|
231
|
+
const base58Address = bs58.encode(bytes);
|
|
232
|
+
return address(base58Address);
|
|
233
|
+
}
|
|
@@ -22,9 +22,9 @@ import {
|
|
|
22
22
|
TokenRunningBalance,
|
|
23
23
|
} from "../interfaces";
|
|
24
24
|
import * as lpFeeCalculator from "../lpFeeCalculator";
|
|
25
|
+
import { EVMBlockFinder } from "../arch/evm";
|
|
25
26
|
import {
|
|
26
27
|
BigNumber,
|
|
27
|
-
BlockFinder,
|
|
28
28
|
bnZero,
|
|
29
29
|
dedupArray,
|
|
30
30
|
EventSearchConfig,
|
|
@@ -97,7 +97,7 @@ export class HubPoolClient extends BaseAbstractClient {
|
|
|
97
97
|
protected pendingRootBundle: PendingRootBundle | undefined;
|
|
98
98
|
|
|
99
99
|
public currentTime: number | undefined;
|
|
100
|
-
public readonly blockFinder:
|
|
100
|
+
public readonly blockFinder: EVMBlockFinder;
|
|
101
101
|
|
|
102
102
|
constructor(
|
|
103
103
|
readonly logger: winston.Logger,
|
|
@@ -121,7 +121,7 @@ export class HubPoolClient extends BaseAbstractClient {
|
|
|
121
121
|
this.firstHeightToSearch = eventSearchConfig.from;
|
|
122
122
|
|
|
123
123
|
const provider = this.hubPool.provider;
|
|
124
|
-
this.blockFinder = new
|
|
124
|
+
this.blockFinder = new EVMBlockFinder(provider);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
protected hubPoolEventFilters(): Record<HubPoolEvent, EventFilter> {
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
getTimestampForSlot,
|
|
8
8
|
getStatePda,
|
|
9
9
|
SvmCpiEventsClient,
|
|
10
|
+
findDeposit,
|
|
10
11
|
relayFillStatus,
|
|
11
12
|
fillStatusArray,
|
|
12
13
|
} from "../../arch/svm";
|
|
@@ -15,6 +16,8 @@ import {
|
|
|
15
16
|
BigNumber,
|
|
16
17
|
DepositSearchResult,
|
|
17
18
|
EventSearchConfig,
|
|
19
|
+
InvalidFill,
|
|
20
|
+
isZeroAddress,
|
|
18
21
|
MakeOptional,
|
|
19
22
|
sortEventsAscendingInPlace,
|
|
20
23
|
} from "../../utils";
|
|
@@ -208,10 +211,31 @@ export class SvmSpokePoolClient extends SpokePoolClient {
|
|
|
208
211
|
|
|
209
212
|
/**
|
|
210
213
|
* Finds a deposit based on its deposit ID on the SVM chain.
|
|
211
|
-
* TODO: Implement SVM state query for deposit details.
|
|
212
214
|
*/
|
|
213
|
-
public findDeposit(
|
|
214
|
-
|
|
215
|
+
public async findDeposit(depositId: BigNumber): Promise<DepositSearchResult> {
|
|
216
|
+
const deposit = await findDeposit(this.svmEventsClient, depositId);
|
|
217
|
+
if (!deposit) {
|
|
218
|
+
return {
|
|
219
|
+
found: false,
|
|
220
|
+
code: InvalidFill.DepositIdNotFound,
|
|
221
|
+
reason: `Deposit with ID ${depositId} not found`,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
// Because we have additional context about this deposit, we can enrich it
|
|
225
|
+
// with additional information.
|
|
226
|
+
return {
|
|
227
|
+
found: true,
|
|
228
|
+
deposit: {
|
|
229
|
+
...deposit,
|
|
230
|
+
quoteBlockNumber: await this.getBlockNumber(Number(deposit.quoteTimestamp)),
|
|
231
|
+
originChainId: this.chainId,
|
|
232
|
+
fromLiteChain: this.isOriginLiteChain(deposit),
|
|
233
|
+
toLiteChain: this.isDestinationLiteChain(deposit),
|
|
234
|
+
outputToken: isZeroAddress(deposit.outputToken)
|
|
235
|
+
? this.getDestinationTokenForDeposit(deposit)
|
|
236
|
+
: deposit.outputToken,
|
|
237
|
+
},
|
|
238
|
+
};
|
|
215
239
|
}
|
|
216
240
|
|
|
217
241
|
/**
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
toAddress,
|
|
19
19
|
validateFillForDeposit,
|
|
20
20
|
chainIsEvm,
|
|
21
|
+
chainIsProd,
|
|
21
22
|
} from "../../utils";
|
|
22
23
|
import { duplicateEvent, sortEventsAscendingInPlace } from "../../utils/EventUtils";
|
|
23
24
|
import { ZERO_ADDRESS } from "../../constants";
|
|
@@ -349,7 +350,7 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
|
|
|
349
350
|
fillCount: number;
|
|
350
351
|
invalidFills: FillWithBlock[];
|
|
351
352
|
} {
|
|
352
|
-
const { outputAmount } = deposit;
|
|
353
|
+
const { outputAmount, originChainId } = deposit;
|
|
353
354
|
const fillsForDeposit = this.depositHashesToFills[this.getDepositHash(deposit)];
|
|
354
355
|
// If no fills then the full amount is remaining.
|
|
355
356
|
if (fillsForDeposit === undefined || fillsForDeposit.length === 0) {
|
|
@@ -405,8 +406,10 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
|
|
|
405
406
|
}
|
|
406
407
|
return newInvalidFill;
|
|
407
408
|
});
|
|
409
|
+
// Log invalid and unrepayable fills as warns if we are on a production network.
|
|
410
|
+
const logLevel = chainIsProd(originChainId) ? "warn" : "debug";
|
|
408
411
|
if (invalidFillsForDeposit.length > 0) {
|
|
409
|
-
this.logger
|
|
412
|
+
this.logger[logLevel]({
|
|
410
413
|
at: "SpokePoolClient",
|
|
411
414
|
chainId: this.chainId,
|
|
412
415
|
message: "Invalid fills found matching deposit ID",
|
|
@@ -417,7 +420,7 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
|
|
|
417
420
|
}
|
|
418
421
|
const unrepayableFillsForDeposit = unrepayableFills.filter((x) => x.depositId.eq(deposit.depositId));
|
|
419
422
|
if (unrepayableFillsForDeposit.length > 0) {
|
|
420
|
-
this.logger
|
|
423
|
+
this.logger[logLevel]({
|
|
421
424
|
at: "SpokePoolClient",
|
|
422
425
|
chainId: this.chainId,
|
|
423
426
|
message: "Unrepayable fills found where we need to switch repayment address and or chain",
|