Skip to content

Commit 4b086e1

Browse files
nicholaspaimrice32
andauthored
fix(CircleCCTPAdapter): Split messages into parts under the limit (#500)
* fix(CircleCCTPAdapter): Split messages into parts under the limit Reads limit for token from token minter, splits amount to send into parts under the limit * Update CircleCCTPAdapter.sol * fix * Update hardhat.config.ts * Update CircleCCTPAdapter.sol * Update CircleCCTPAdapter.sol * fix test Signed-off-by: Matt Rice <[email protected]> * fix --------- Signed-off-by: Matt Rice <[email protected]> Co-authored-by: Matt Rice <[email protected]>
1 parent 95c4f92 commit 4b086e1

19 files changed

+467
-320
lines changed

contracts/external/interfaces/CCTPInterfaces.sol

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,30 @@ interface ITokenMessenger {
4747
bytes32 mintRecipient,
4848
address burnToken
4949
) external returns (uint64 _nonce);
50+
51+
/**
52+
* @notice Minter responsible for minting and burning tokens on the local domain
53+
* @dev A TokenMessenger stores a TokenMinter contract which extends the TokenController contract.
54+
* https://github.com/circlefin/evm-cctp-contracts/blob/817397db0a12963accc08ff86065491577bbc0e5/src/TokenMessenger.sol#L110
55+
* @return minter Token Minter contract.
56+
*/
57+
function localMinter() external view returns (ITokenMinter minter);
58+
}
59+
60+
/**
61+
* A TokenMessenger stores a TokenMinter contract which extends the TokenController contract. The TokenController
62+
* contract has a burnLimitsPerMessage public mapping which can be queried to find the per-message burn limit
63+
* for a given token:
64+
* https://github.com/circlefin/evm-cctp-contracts/blob/817397db0a12963accc08ff86065491577bbc0e5/src/TokenMinter.sol#L33
65+
* https://github.com/circlefin/evm-cctp-contracts/blob/817397db0a12963accc08ff86065491577bbc0e5/src/roles/TokenController.sol#L69C40-L69C60
66+
*
67+
*/
68+
interface ITokenMinter {
69+
/**
70+
* @notice Supported burnable tokens on the local domain
71+
* local token (address) => maximum burn amounts per message
72+
* @param token address of token contract
73+
* @return burnLimit maximum burn amount per message for token
74+
*/
75+
function burnLimitsPerMessage(address token) external view returns (uint256);
5076
}

contracts/libraries/CircleCCTPAdapter.sol

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,16 @@ abstract contract CircleCCTPAdapter {
8181
function _transferUsdc(address to, uint256 amount) internal {
8282
// Only approve the exact amount to be transferred
8383
usdcToken.safeIncreaseAllowance(address(cctpTokenMessenger), amount);
84-
// Submit the amount to be transferred to bridged via the TokenMessenger
85-
cctpTokenMessenger.depositForBurn(amount, recipientCircleDomainId, _addressToBytes32(to), address(usdcToken));
84+
// Submit the amount to be transferred to bridged via the TokenMessenger.
85+
// If the amount to send exceeds the burn limit per message, then split the message into smaller parts.
86+
ITokenMinter cctpMinter = cctpTokenMessenger.localMinter();
87+
uint256 burnLimit = cctpMinter.burnLimitsPerMessage(address(usdcToken));
88+
uint256 remainingAmount = amount;
89+
bytes32 recipient = _addressToBytes32(to);
90+
while (remainingAmount > 0) {
91+
uint256 partAmount = remainingAmount > burnLimit ? burnLimit : remainingAmount;
92+
cctpTokenMessenger.depositForBurn(partAmount, recipientCircleDomainId, recipient, address(usdcToken));
93+
remainingAmount -= partAmount;
94+
}
8695
}
8796
}

hardhat.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ const config: HardhatUserConfig = {
7979
// See https://docs.linea.build/build-on-linea/ethereum-differences#evm-opcodes
8080
version: "0.8.19",
8181
},
82+
"contracts/Blast_SpokePool.sol": LARGE_CONTRACT_COMPILER_SETTINGS,
8283
},
8384
},
8485
zksolc: {

storage-layouts/Arbitrum_SpokePool.json

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,199 +1,199 @@
11
{
22
"storage": [
33
{
4-
"astId": 65286,
4+
"astId": 65577,
55
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
66
"label": "_initialized",
77
"offset": 0,
88
"slot": "0",
99
"type": "t_uint8"
1010
},
1111
{
12-
"astId": 65289,
12+
"astId": 65580,
1313
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
1414
"label": "_initializing",
1515
"offset": 1,
1616
"slot": "0",
1717
"type": "t_bool"
1818
},
1919
{
20-
"astId": 65268,
20+
"astId": 65559,
2121
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
2222
"label": "__gap",
2323
"offset": 0,
2424
"slot": "1",
2525
"type": "t_array(t_uint256)50_storage"
2626
},
2727
{
28-
"astId": 65584,
28+
"astId": 65875,
2929
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
3030
"label": "__gap",
3131
"offset": 0,
3232
"slot": "51",
3333
"type": "t_array(t_uint256)50_storage"
3434
},
3535
{
36-
"astId": 65600,
36+
"astId": 65891,
3737
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
3838
"label": "_status",
3939
"offset": 0,
4040
"slot": "101",
4141
"type": "t_uint256"
4242
},
4343
{
44-
"astId": 65669,
44+
"astId": 65960,
4545
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
4646
"label": "__gap",
4747
"offset": 0,
4848
"slot": "102",
4949
"type": "t_array(t_uint256)49_storage"
5050
},
5151
{
52-
"astId": 17700,
52+
"astId": 17991,
5353
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
5454
"label": "__gap",
5555
"offset": 0,
5656
"slot": "151",
5757
"type": "t_array(t_uint256)1000_storage"
5858
},
5959
{
60-
"astId": 17432,
60+
"astId": 17723,
6161
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
6262
"label": "_HASHED_NAME",
6363
"offset": 0,
6464
"slot": "1151",
6565
"type": "t_bytes32"
6666
},
6767
{
68-
"astId": 17434,
68+
"astId": 17725,
6969
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
7070
"label": "_HASHED_VERSION",
7171
"offset": 0,
7272
"slot": "1152",
7373
"type": "t_bytes32"
7474
},
7575
{
76-
"astId": 17533,
76+
"astId": 17824,
7777
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
7878
"label": "__gap",
7979
"offset": 0,
8080
"slot": "1153",
8181
"type": "t_array(t_uint256)1000_storage"
8282
},
8383
{
84-
"astId": 5884,
84+
"astId": 5938,
8585
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
8686
"label": "crossDomainAdmin",
8787
"offset": 0,
8888
"slot": "2153",
8989
"type": "t_address"
9090
},
9191
{
92-
"astId": 5886,
92+
"astId": 5940,
9393
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
9494
"label": "hubPool",
9595
"offset": 0,
9696
"slot": "2154",
9797
"type": "t_address"
9898
},
9999
{
100-
"astId": 5889,
100+
"astId": 5943,
101101
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
102102
"label": "DEPRECATED_wrappedNativeToken",
103103
"offset": 0,
104104
"slot": "2155",
105-
"type": "t_contract(WETH9Interface)13213"
105+
"type": "t_contract(WETH9Interface)13461"
106106
},
107107
{
108-
"astId": 5891,
108+
"astId": 5945,
109109
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
110110
"label": "DEPRECATED_depositQuoteTimeBuffer",
111111
"offset": 20,
112112
"slot": "2155",
113113
"type": "t_uint32"
114114
},
115115
{
116-
"astId": 5893,
116+
"astId": 5947,
117117
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
118118
"label": "numberOfDeposits",
119119
"offset": 24,
120120
"slot": "2155",
121121
"type": "t_uint32"
122122
},
123123
{
124-
"astId": 5895,
124+
"astId": 5949,
125125
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
126126
"label": "pausedFills",
127127
"offset": 28,
128128
"slot": "2155",
129129
"type": "t_bool"
130130
},
131131
{
132-
"astId": 5897,
132+
"astId": 5951,
133133
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
134134
"label": "pausedDeposits",
135135
"offset": 29,
136136
"slot": "2155",
137137
"type": "t_bool"
138138
},
139139
{
140-
"astId": 5901,
140+
"astId": 5955,
141141
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
142142
"label": "rootBundles",
143143
"offset": 0,
144144
"slot": "2156",
145-
"type": "t_array(t_struct(RootBundle)13790_storage)dyn_storage"
145+
"type": "t_array(t_struct(RootBundle)14038_storage)dyn_storage"
146146
},
147147
{
148-
"astId": 5907,
148+
"astId": 5961,
149149
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
150150
"label": "enabledDepositRoutes",
151151
"offset": 0,
152152
"slot": "2157",
153153
"type": "t_mapping(t_address,t_mapping(t_uint256,t_bool))"
154154
},
155155
{
156-
"astId": 5911,
156+
"astId": 5965,
157157
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
158158
"label": "DEPRECATED_relayFills",
159159
"offset": 0,
160160
"slot": "2158",
161161
"type": "t_mapping(t_bytes32,t_uint256)"
162162
},
163163
{
164-
"astId": 5915,
164+
"astId": 5969,
165165
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
166166
"label": "DEPRECATED_fillCounter",
167167
"offset": 0,
168168
"slot": "2159",
169169
"type": "t_mapping(t_address,t_uint256)"
170170
},
171171
{
172-
"astId": 5919,
172+
"astId": 5973,
173173
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
174174
"label": "DEPRECATED_depositCounter",
175175
"offset": 0,
176176
"slot": "2160",
177177
"type": "t_mapping(t_address,t_uint256)"
178178
},
179179
{
180-
"astId": 5923,
180+
"astId": 5977,
181181
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
182182
"label": "DEPRECATED_refundsRequested",
183183
"offset": 0,
184184
"slot": "2161",
185185
"type": "t_mapping(t_bytes32,t_uint256)"
186186
},
187187
{
188-
"astId": 5927,
188+
"astId": 5981,
189189
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
190190
"label": "fillStatuses",
191191
"offset": 0,
192192
"slot": "2162",
193193
"type": "t_mapping(t_bytes32,t_uint256)"
194194
},
195195
{
196-
"astId": 7828,
196+
"astId": 7882,
197197
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
198198
"label": "__gap",
199199
"offset": 0,
@@ -223,11 +223,11 @@
223223
"label": "address",
224224
"numberOfBytes": "20"
225225
},
226-
"t_array(t_struct(RootBundle)13790_storage)dyn_storage": {
226+
"t_array(t_struct(RootBundle)14038_storage)dyn_storage": {
227227
"encoding": "dynamic_array",
228228
"label": "struct SpokePoolInterface.RootBundle[]",
229229
"numberOfBytes": "32",
230-
"base": "t_struct(RootBundle)13790_storage"
230+
"base": "t_struct(RootBundle)14038_storage"
231231
},
232232
"t_array(t_uint256)1000_storage": {
233233
"encoding": "inplace",
@@ -263,7 +263,7 @@
263263
"label": "bytes32",
264264
"numberOfBytes": "32"
265265
},
266-
"t_contract(WETH9Interface)13213": {
266+
"t_contract(WETH9Interface)13461": {
267267
"encoding": "inplace",
268268
"label": "contract WETH9Interface",
269269
"numberOfBytes": "20"
@@ -310,29 +310,29 @@
310310
"numberOfBytes": "32",
311311
"value": "t_uint256"
312312
},
313-
"t_struct(RootBundle)13790_storage": {
313+
"t_struct(RootBundle)14038_storage": {
314314
"encoding": "inplace",
315315
"label": "struct SpokePoolInterface.RootBundle",
316316
"numberOfBytes": "96",
317317
"members": [
318318
{
319-
"astId": 13783,
319+
"astId": 14031,
320320
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
321321
"label": "slowRelayRoot",
322322
"offset": 0,
323323
"slot": "0",
324324
"type": "t_bytes32"
325325
},
326326
{
327-
"astId": 13785,
327+
"astId": 14033,
328328
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
329329
"label": "relayerRefundRoot",
330330
"offset": 0,
331331
"slot": "1",
332332
"type": "t_bytes32"
333333
},
334334
{
335-
"astId": 13789,
335+
"astId": 14037,
336336
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
337337
"label": "claimedBitmap",
338338
"offset": 0,

0 commit comments

Comments
 (0)