@keep-network/tbtc-v2 1.2.0-dev.0 → 1.2.0-dev.1

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.
Files changed (131) hide show
  1. package/artifacts/BLS.json +1 -1
  2. package/artifacts/Bank.json +8 -8
  3. package/artifacts/BeaconAuthorization.json +1 -1
  4. package/artifacts/BeaconDkg.json +1 -1
  5. package/artifacts/BeaconDkgValidator.json +1 -1
  6. package/artifacts/BeaconInactivity.json +1 -1
  7. package/artifacts/BeaconSortitionPool.json +3 -3
  8. package/artifacts/Bridge.json +5 -5
  9. package/artifacts/BridgeGovernance.json +2 -2
  10. package/artifacts/BridgeGovernanceParameters.json +2 -2
  11. package/artifacts/Deposit.json +2 -2
  12. package/artifacts/DepositSweep.json +2 -2
  13. package/artifacts/DonationVault.json +5 -5
  14. package/artifacts/EcdsaDkgValidator.json +1 -1
  15. package/artifacts/EcdsaInactivity.json +1 -1
  16. package/artifacts/EcdsaSortitionPool.json +3 -3
  17. package/artifacts/Fraud.json +2 -2
  18. package/artifacts/KeepRegistry.json +1 -1
  19. package/artifacts/KeepStake.json +2 -2
  20. package/artifacts/KeepToken.json +2 -2
  21. package/artifacts/KeepTokenStaking.json +1 -1
  22. package/artifacts/LightRelay.json +19 -19
  23. package/artifacts/MaintainerProxy.json +22 -22
  24. package/artifacts/MovingFunds.json +2 -2
  25. package/artifacts/NuCypherStakingEscrow.json +1 -1
  26. package/artifacts/NuCypherToken.json +2 -2
  27. package/artifacts/RandomBeacon.json +2 -2
  28. package/artifacts/RandomBeaconChaosnet.json +2 -2
  29. package/artifacts/RandomBeaconGovernance.json +2 -2
  30. package/artifacts/Redemption.json +2 -2
  31. package/artifacts/ReimbursementPool.json +2 -2
  32. package/artifacts/T.json +2 -2
  33. package/artifacts/TBTC.json +10 -10
  34. package/artifacts/TBTCToken.json +10 -10
  35. package/artifacts/TBTCVault.json +24 -24
  36. package/artifacts/TokenStaking.json +1 -1
  37. package/artifacts/TokenholderGovernor.json +9 -9
  38. package/artifacts/TokenholderTimelock.json +8 -8
  39. package/artifacts/VendingMachine.json +11 -11
  40. package/artifacts/VendingMachineKeep.json +1 -1
  41. package/artifacts/VendingMachineNuCypher.json +1 -1
  42. package/artifacts/VendingMachineV2.json +4 -4
  43. package/artifacts/VendingMachineV3.json +4 -4
  44. package/artifacts/WalletRegistry.json +5 -5
  45. package/artifacts/WalletRegistryGovernance.json +2 -2
  46. package/artifacts/Wallets.json +2 -2
  47. package/artifacts/solcInputs/{b0025f1f7efe4824592ac0c9793776c3.json → 8445e3932e9b9683df0e9fb9258d7b11.json} +9 -0
  48. package/build/contracts/GovernanceUtils.sol/GovernanceUtils.dbg.json +1 -1
  49. package/build/contracts/bank/Bank.sol/Bank.dbg.json +1 -1
  50. package/build/contracts/bank/IReceiveBalanceApproval.sol/IReceiveBalanceApproval.dbg.json +1 -1
  51. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.dbg.json +1 -1
  52. package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +1 -1
  53. package/build/contracts/bridge/BridgeGovernanceParameters.sol/BridgeGovernanceParameters.dbg.json +1 -1
  54. package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +1 -1
  55. package/build/contracts/bridge/Deposit.sol/Deposit.dbg.json +1 -1
  56. package/build/contracts/bridge/DepositSweep.sol/DepositSweep.dbg.json +1 -1
  57. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +1 -1
  58. package/build/contracts/bridge/Fraud.sol/Fraud.dbg.json +1 -1
  59. package/build/contracts/bridge/Heartbeat.sol/Heartbeat.dbg.json +1 -1
  60. package/build/contracts/bridge/IRelay.sol/IRelay.dbg.json +1 -1
  61. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.dbg.json +1 -1
  62. package/build/contracts/bridge/Redemption.sol/OutboundTx.dbg.json +1 -1
  63. package/build/contracts/bridge/Redemption.sol/Redemption.dbg.json +1 -1
  64. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
  65. package/build/contracts/bridge/VendingMachineV2.sol/VendingMachineV2.dbg.json +1 -1
  66. package/build/contracts/bridge/VendingMachineV3.sol/VendingMachineV3.dbg.json +1 -1
  67. package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +1 -1
  68. package/build/contracts/l2/L2TBTC.sol/L2TBTC.dbg.json +1 -1
  69. package/build/contracts/l2/L2WormholeGateway.sol/IWormholeTokenBridge.dbg.json +4 -0
  70. package/build/contracts/l2/L2WormholeGateway.sol/IWormholeTokenBridge.json +179 -0
  71. package/build/contracts/l2/L2WormholeGateway.sol/L2WormholeGateway.dbg.json +4 -0
  72. package/build/contracts/l2/L2WormholeGateway.sol/L2WormholeGateway.json +430 -0
  73. package/build/contracts/maintainer/MaintainerProxy.sol/MaintainerProxy.dbg.json +1 -1
  74. package/build/contracts/relay/LightRelay.sol/ILightRelay.dbg.json +1 -1
  75. package/build/contracts/relay/LightRelay.sol/LightRelay.dbg.json +1 -1
  76. package/build/contracts/relay/LightRelay.sol/RelayUtils.dbg.json +1 -1
  77. package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
  78. package/build/contracts/vault/DonationVault.sol/DonationVault.dbg.json +1 -1
  79. package/build/contracts/vault/IVault.sol/IVault.dbg.json +1 -1
  80. package/build/contracts/vault/TBTCOptimisticMinting.sol/TBTCOptimisticMinting.dbg.json +1 -1
  81. package/build/contracts/vault/TBTCVault.sol/TBTCVault.dbg.json +1 -1
  82. package/contracts/l2/L2WormholeGateway.sol +389 -0
  83. package/export/artifacts/@keep-network/bitcoin-spv-sol/contracts/BTCUtils.sol/BTCUtils.json +20 -20
  84. package/export/artifacts/@keep-network/ecdsa/contracts/EcdsaDkgValidator.sol/EcdsaDkgValidator.json +1996 -1996
  85. package/export/artifacts/@keep-network/ecdsa/contracts/libraries/EcdsaDkg.sol/EcdsaDkg.json +20 -20
  86. package/export/artifacts/@keep-network/ecdsa/contracts/libraries/EcdsaInactivity.sol/EcdsaInactivity.json +1846 -1846
  87. package/export/artifacts/@keep-network/random-beacon/contracts/ReimbursementPool.sol/ReimbursementPool.json +571 -571
  88. package/export/artifacts/@keep-network/sortition-pools/contracts/Chaosnet.sol/Chaosnet.json +506 -506
  89. package/export/artifacts/@keep-network/sortition-pools/contracts/Rewards.sol/Rewards.json +23 -23
  90. package/export/artifacts/@keep-network/sortition-pools/contracts/SortitionPool.sol/SortitionPool.json +2481 -2481
  91. package/export/artifacts/@keep-network/sortition-pools/contracts/SortitionTree.sol/SortitionTree.json +465 -465
  92. package/export/artifacts/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol/ERC1967Proxy.json +614 -614
  93. package/export/artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json +640 -640
  94. package/export/artifacts/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json +1079 -1079
  95. package/export/artifacts/@openzeppelin/contracts/token/ERC721/ERC721.sol/ERC721.json +1945 -1945
  96. package/export/artifacts/@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol/ERC20Upgradeable.json +696 -696
  97. package/export/artifacts/@thesis/solidity-contracts/contracts/token/ERC20WithPermit.sol/ERC20WithPermit.json +2613 -2613
  98. package/export/artifacts/@thesis/solidity-contracts/contracts/token/MisfundRecovery.sol/MisfundRecovery.json +779 -779
  99. package/export/artifacts/contracts/bank/Bank.sol/Bank.json +1949 -1949
  100. package/export/artifacts/contracts/bridge/Bridge.sol/Bridge.json +7365 -7365
  101. package/export/artifacts/contracts/bridge/VendingMachine.sol/VendingMachine.json +1359 -1359
  102. package/export/artifacts/contracts/bridge/VendingMachineV2.sol/VendingMachineV2.json +1029 -1029
  103. package/export/artifacts/contracts/bridge/VendingMachineV3.sol/VendingMachineV3.json +1181 -1181
  104. package/export/artifacts/contracts/l2/L2TBTC.sol/L2TBTC.json +3122 -3122
  105. package/export/artifacts/contracts/l2/L2WormholeGateway.sol/L2WormholeGateway.json +15104 -0
  106. package/export/artifacts/contracts/maintainer/MaintainerProxy.sol/MaintainerProxy.json +2442 -2442
  107. package/export/artifacts/contracts/relay/LightRelay.sol/LightRelay.json +1941 -1941
  108. package/export/artifacts/contracts/test/BankStub.sol/BankStub.json +1951 -1951
  109. package/export/artifacts/contracts/test/BridgeStub.sol/BridgeStub.json +8406 -8406
  110. package/export/artifacts/contracts/test/GoerliLightRelay.sol/GoerliLightRelay.json +1941 -1941
  111. package/export/artifacts/contracts/test/HeartbeatStub.sol/HeartbeatStub.json +132 -132
  112. package/export/artifacts/contracts/test/LightRelayStub.sol/LightRelayStub.json +2066 -2066
  113. package/export/artifacts/contracts/test/ReceiveApprovalStub.sol/ReceiveApprovalStub.json +354 -354
  114. package/export/artifacts/contracts/test/SystemTestRelay.sol/SystemTestRelay.json +568 -568
  115. package/export/artifacts/contracts/test/TestERC20.sol/TestERC20.json +2370 -2370
  116. package/export/artifacts/contracts/test/TestERC721.sol/TestERC721.json +1768 -1768
  117. package/export/artifacts/contracts/test/TestEcdsaLib.sol/TestEcdsaLib.json +191 -191
  118. package/export/artifacts/contracts/test/WormholeBridgeStub.sol/WormholeBridgeStub.json +8665 -0
  119. package/export/artifacts/contracts/token/TBTC.sol/TBTC.json +2949 -2949
  120. package/export/artifacts/contracts/vault/DonationVault.sol/DonationVault.json +866 -866
  121. package/export/artifacts/contracts/vault/TBTCVault.sol/TBTCVault.json +3525 -3525
  122. package/export/typechain/IWormholeTokenBridge.js +2 -0
  123. package/export/typechain/L2WormholeGateway.js +2 -0
  124. package/export/typechain/ReentrancyGuardUpgradeable.js +2 -0
  125. package/export/typechain/WormholeBridgeStub.js +2 -0
  126. package/export/typechain/factories/IWormholeTokenBridge__factory.js +190 -0
  127. package/export/typechain/factories/L2WormholeGateway__factory.js +509 -0
  128. package/export/typechain/factories/ReentrancyGuardUpgradeable__factory.js +35 -0
  129. package/export/typechain/factories/WormholeBridgeStub__factory.js +451 -0
  130. package/export/typechain/index.js +10 -2
  131. package/package.json +1 -1
@@ -0,0 +1,389 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+
3
+ // ██████████████ ▐████▌ ██████████████
4
+ // ██████████████ ▐████▌ ██████████████
5
+ // ▐████▌ ▐████▌
6
+ // ▐████▌ ▐████▌
7
+ // ██████████████ ▐████▌ ██████████████
8
+ // ██████████████ ▐████▌ ██████████████
9
+ // ▐████▌ ▐████▌
10
+ // ▐████▌ ▐████▌
11
+ // ▐████▌ ▐████▌
12
+ // ▐████▌ ▐████▌
13
+ // ▐████▌ ▐████▌
14
+ // ▐████▌ ▐████▌
15
+
16
+ pragma solidity ^0.8.17;
17
+
18
+ import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
19
+ import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
20
+ import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
21
+ import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
22
+
23
+ import "./L2TBTC.sol";
24
+
25
+ /// @title IWormholeTokenBridge
26
+ /// @notice Wormhole Token Bridge interface. Contains only selected functions
27
+ /// used by L2WormholeGateway.
28
+ interface IWormholeTokenBridge {
29
+ function completeTransferWithPayload(bytes memory encodedVm)
30
+ external
31
+ returns (bytes memory);
32
+
33
+ function parseTransferWithPayload(bytes memory encoded)
34
+ external
35
+ pure
36
+ returns (TransferWithPayload memory transfer);
37
+
38
+ function transferTokens(
39
+ address token,
40
+ uint256 amount,
41
+ uint16 recipientChain,
42
+ bytes32 recipient,
43
+ uint256 arbiterFee,
44
+ uint32 nonce
45
+ ) external payable returns (uint64 sequence);
46
+
47
+ function transferTokensWithPayload(
48
+ address token,
49
+ uint256 amount,
50
+ uint16 recipientChain,
51
+ bytes32 recipient,
52
+ uint32 nonce,
53
+ bytes memory payload
54
+ ) external payable returns (uint64 sequence);
55
+
56
+ struct TransferWithPayload {
57
+ uint8 payloadID;
58
+ uint256 amount;
59
+ bytes32 tokenAddress;
60
+ uint16 tokenChain;
61
+ bytes32 to;
62
+ uint16 toChain;
63
+ bytes32 fromAddress;
64
+ bytes payload;
65
+ }
66
+ }
67
+
68
+ /// @title L2WormholeGateway
69
+ /// @notice Selected cross-ecosystem bridges are given the minting authority for
70
+ /// tBTC token on L2 and sidechains. This contract gives a minting
71
+ /// authority to the Wormhole Bridge.
72
+ ///
73
+ /// The process of bridging from L1 to L2 (or sidechain) looks as
74
+ /// follows:
75
+ /// 1. There is a tBTC holder on L1. The holder goes to the Wormhole
76
+ /// Portal and selects the chain they want to bridge to.
77
+ /// 2. The holder submits one transaction to L1 locking their tBTC
78
+ /// tokens in the bridge’s smart contract. After the transaction is
79
+ /// mined, they wait about 15 minutes for the Ethereum block
80
+ /// finality.
81
+ /// 3. The holder submits one transaction to L2 that is minting tokens.
82
+ /// After that transaction is mined, they have their tBTC on L2.
83
+ ///
84
+ /// The process of bridging from L2 (or sidechain) to L1 looks as
85
+ /// follows:
86
+ /// 1. There is a tBTC holder on L2. That holder goes to the Wormhole
87
+ /// Portal and selects one of the L2 chains they want to bridge from.
88
+ /// 2. The holder submits one transaction to L2 that is burning the
89
+ /// token. After the transaction is mined, they wait about 15 minutes
90
+ /// for the L2 block finality.
91
+ /// 3. The holder submits one transaction to L1 unlocking their tBTC
92
+ /// tokens from the bridge’s smart contract. After that transaction
93
+ /// is mined, they have their tBTC on L1.
94
+ ///
95
+ /// This smart contract is integrated with step 3 of L1->L2 bridging and
96
+ /// step 1 of L2->L1 or L2->L2 bridging. When the user redeems token on
97
+ /// L2, this contract receives the Wormhole tBTC representation and
98
+ /// mints the canonical tBTC in an equal amount. When user sends their
99
+ /// token from L1, this contract burns the canonical tBTC and sends
100
+ /// Wormhole tBTC representation through the bridge in an equal amount.
101
+ /// @dev This contract is supposed to be deployed behind a transparent
102
+ /// upgradeable proxy.
103
+ contract L2WormholeGateway is
104
+ Initializable,
105
+ OwnableUpgradeable,
106
+ ReentrancyGuardUpgradeable
107
+ {
108
+ using SafeERC20Upgradeable for IERC20Upgradeable;
109
+
110
+ /// @notice Reference to the Wormhole Token Bridge contract.
111
+ IWormholeTokenBridge public bridge;
112
+
113
+ /// @notice Wormhole tBTC token representation.
114
+ IERC20Upgradeable public bridgeToken;
115
+
116
+ /// @notice Canonical tBTC token.
117
+ L2TBTC public tbtc;
118
+
119
+ /// @notice Maps Wormhole chain ID to the Wormhole tBTC gateway address on
120
+ /// that chain. For example, this chain's ID should be mapped to
121
+ /// this contract's address. If there is no Wormhole tBTC gateway
122
+ /// address on the given chain, there is no entry in this mapping.
123
+ /// The mapping holds addresses in a Wormhole-specific format, where
124
+ /// Ethereum address is left-padded with zeros.
125
+ mapping(uint16 => bytes32) public gateways;
126
+
127
+ /// @notice Minting limit for this gateway. Useful for early days of testing
128
+ /// the system. The gateway can not mint more canonical tBTC than
129
+ /// this limit.
130
+ uint256 public mintingLimit;
131
+
132
+ /// @notice The amount of tBTC minted by this contract. tBTC burned by this
133
+ /// contract decreases this amount.
134
+ uint256 public mintedAmount;
135
+
136
+ event WormholeTbtcReceived(address receiver, uint256 amount);
137
+
138
+ event WormholeTbtcSent(
139
+ uint256 amount,
140
+ uint16 recipientChain,
141
+ bytes32 gateway,
142
+ bytes32 recipient,
143
+ uint256 arbiterFee,
144
+ uint32 nonce
145
+ );
146
+
147
+ event WormholeTbtcDeposited(address depositor, uint256 amount);
148
+
149
+ event GatewayAddressUpdated(uint16 chainId, bytes32 gateway);
150
+
151
+ event MintingLimitUpdated(uint256 mintingLimit);
152
+
153
+ function initialize(
154
+ IWormholeTokenBridge _bridge,
155
+ IERC20Upgradeable _bridgeToken,
156
+ L2TBTC _tbtc
157
+ ) external initializer {
158
+ __Ownable_init();
159
+ __ReentrancyGuard_init();
160
+
161
+ require(
162
+ address(_bridge) != address(0),
163
+ "Wormhole bridge address must not be 0x0"
164
+ );
165
+ require(
166
+ address(_bridgeToken) != address(0),
167
+ "Bridge token address must not be 0x0"
168
+ );
169
+ require(
170
+ address(_tbtc) != address(0),
171
+ "L2TBTC token address must not be 0x0"
172
+ );
173
+
174
+ bridge = _bridge;
175
+ bridgeToken = _bridgeToken;
176
+ tbtc = _tbtc;
177
+ mintingLimit = type(uint256).max;
178
+ }
179
+
180
+ /// @notice This function is called when the user sends their token from L2.
181
+ /// The contract burns the canonical tBTC from the user and sends
182
+ /// wormhole tBTC representation over the bridge.
183
+ /// Keep in mind that when multiple bridges receive a minting
184
+ /// authority on the canonical tBTC, this function may not be able
185
+ /// to send all amounts of tBTC through the Wormhole bridge. The
186
+ /// capability of Wormhole Bridge to send tBTC from the chain is
187
+ /// limited to the amount of tBTC bridged through Wormhole to that
188
+ /// chain.
189
+ /// @dev Requirements:
190
+ /// - The sender must have at least `amount` of the canonical tBTC and
191
+ /// it has to be approved for L2WormholeGateway.
192
+ /// - The L2WormholeGateway must have at least `amount` of the wormhole
193
+ /// tBTC.
194
+ /// - The recipient must not be 0x0.
195
+ /// - The amount to transfer must not be 0.
196
+ /// Depending if Wormhole tBTC gateway is registered on the target
197
+ /// chain, this function uses transfer or transfer with payload over
198
+ /// the Wormhole bridge.
199
+ /// @param amount The amount of tBTC to be sent.
200
+ /// @param recipientChain The Wormhole recipient chain ID.
201
+ /// @param recipient The address of the recipient in the Wormhole format.
202
+ /// @param arbiterFee The Wormhole arbiter fee. Ignored if sending
203
+ /// tBTC to chain with Wormhole tBTC gateway.
204
+ /// @param nonce The Wormhole nonce used to batch messages together.
205
+ /// @return The Wormhole sequence number.
206
+ function sendTbtc(
207
+ uint256 amount,
208
+ uint16 recipientChain,
209
+ bytes32 recipient,
210
+ uint256 arbiterFee,
211
+ uint32 nonce
212
+ ) external payable nonReentrant returns (uint64) {
213
+ require(
214
+ bridgeToken.balanceOf(address(this)) >= amount,
215
+ "Not enough wormhole tBTC in the gateway to bridge"
216
+ );
217
+
218
+ require(recipient != bytes32(0), "0x0 recipient not allowed");
219
+ require(amount != 0, "Amount must not be 0");
220
+
221
+ bytes32 gateway = gateways[recipientChain];
222
+
223
+ emit WormholeTbtcSent(
224
+ amount,
225
+ recipientChain,
226
+ gateway,
227
+ recipient,
228
+ arbiterFee,
229
+ nonce
230
+ );
231
+
232
+ mintedAmount -= amount;
233
+ tbtc.burnFrom(msg.sender, amount);
234
+ bridgeToken.safeApprove(address(bridge), amount);
235
+
236
+ if (gateway == bytes32(0)) {
237
+ // No Wormhole tBTC gateway on the target chain. The token minted
238
+ // by Wormhole should be considered canonical.
239
+ return
240
+ bridge.transferTokens{value: msg.value}(
241
+ address(bridgeToken),
242
+ amount,
243
+ recipientChain,
244
+ recipient,
245
+ arbiterFee,
246
+ nonce
247
+ );
248
+ } else {
249
+ // There is a Wormhole tBTC gateway on the target chain.
250
+ // The gateway needs to mint canonical tBTC for the recipient
251
+ // encoded in the payload.
252
+ return
253
+ bridge.transferTokensWithPayload{value: msg.value}(
254
+ address(bridgeToken),
255
+ amount,
256
+ recipientChain,
257
+ gateway,
258
+ nonce,
259
+ abi.encode(recipient)
260
+ );
261
+ }
262
+ }
263
+
264
+ /// @notice This function is called when the user redeems their token on L2.
265
+ /// The contract receives Wormhole tBTC representation and mints the
266
+ /// canonical tBTC for the user.
267
+ /// If the tBTC minting limit has been reached by this contract,
268
+ /// instead of minting tBTC the receiver address receives Wormhole
269
+ /// tBTC representation.
270
+ /// @dev Requirements:
271
+ /// - The receiver of Wormhole tBTC should be the L2WormholeGateway
272
+ /// contract.
273
+ /// - The receiver of the canonical tBTC should be abi-encoded in the
274
+ /// payload.
275
+ /// - The receiver of the canonical tBTC must not be the zero address.
276
+ /// The Wormhole Token Bridge contract has protection against redeeming
277
+ /// the same VAA again. When a Token Bridge VAA is redeemed, its
278
+ /// message body hash is stored in a map. This map is used to check
279
+ /// whether the hash has already been set in this map. For this reason,
280
+ /// this function does not have to be nonReentrant.
281
+ /// @param encodedVm A byte array containing a Wormhole VAA signed by the
282
+ /// guardians.
283
+ function receiveTbtc(bytes calldata encodedVm) external {
284
+ // ITokenBridge.completeTransferWithPayload completes a contract-controlled
285
+ // transfer of an ERC20 token. Calling this function is not enough to
286
+ // ensure L2WormholeGateway received Wormhole tBTC representation.
287
+ // Instead of going too deep into the ITokenBridge implementation,
288
+ // asserting who is the receiver of the token, and which token it is,
289
+ // we check the balance before the ITokenBridge call and the balance
290
+ // after ITokenBridge call. This way, we are sure this contract received
291
+ // Wormhole tBTC token in the given amount. This is transparent to
292
+ // all potential upgrades of ITokenBridge implementation and no other
293
+ // validations are needed.
294
+ uint256 balanceBefore = bridgeToken.balanceOf(address(this));
295
+ bytes memory encoded = bridge.completeTransferWithPayload(encodedVm);
296
+ uint256 balanceAfter = bridgeToken.balanceOf(address(this));
297
+
298
+ uint256 amount = balanceAfter - balanceBefore;
299
+ // Protect against the custody of irrelevant tokens.
300
+ require(amount > 0, "No tBTC transferred");
301
+
302
+ address receiver = fromWormholeAddress(
303
+ bytes32(bridge.parseTransferWithPayload(encoded).payload)
304
+ );
305
+ require(receiver != address(0), "0x0 receiver not allowed");
306
+
307
+ // We send wormhole tBTC OR mint canonical tBTC. We do not want to send
308
+ // dust. Sending wormhole tBTC is an exceptional situation and we want
309
+ // to keep it simple.
310
+ if (mintedAmount + amount > mintingLimit) {
311
+ bridgeToken.safeTransfer(receiver, amount);
312
+ } else {
313
+ // The function is non-reentrant given bridge.completeTransferWithPayload
314
+ // call that does not allow to use the same VAA again.
315
+ // slither-disable-next-line reentrancy-benign
316
+ mintedAmount += amount;
317
+ tbtc.mint(receiver, amount);
318
+ }
319
+
320
+ // The function is non-reentrant given bridge.completeTransferWithPayload
321
+ // call that does not allow to use the same VAA again.
322
+ // slither-disable-next-line reentrancy-events
323
+ emit WormholeTbtcReceived(receiver, amount);
324
+ }
325
+
326
+ /// @notice Allows to deposit Wormhole tBTC token in exchange for canonical
327
+ /// tBTC. Useful in a situation when user received wormhole tBTC
328
+ /// instead of canonical tBTC. One example of such situation is
329
+ /// when the minting limit was exceeded but the user minted anyway.
330
+ /// @dev Requirements:
331
+ /// - The sender must have at least `amount` of the Wormhole tBTC and
332
+ /// it has to be approved for L2WormholeGateway.
333
+ /// - The minting limit must allow for minting the given amount.
334
+ /// @param amount The amount of Wormhole tBTC to deposit.
335
+ function depositWormholeTbtc(uint256 amount) external {
336
+ require(
337
+ mintedAmount + amount <= mintingLimit,
338
+ "Minting limit exceeded"
339
+ );
340
+
341
+ emit WormholeTbtcDeposited(msg.sender, amount);
342
+ mintedAmount += amount;
343
+ bridgeToken.safeTransferFrom(msg.sender, address(this), amount);
344
+ tbtc.mint(msg.sender, amount);
345
+ }
346
+
347
+ /// @notice Lets the governance to update the tBTC gateway address on the
348
+ /// chain with the given Wormhole ID.
349
+ /// @dev Use toWormholeAddress function to convert between Ethereum and
350
+ /// Wormhole address formats.
351
+ /// @param chainId Wormhole ID of the chain.
352
+ /// @param gateway Address of tBTC gateway on the given chain in a Wormhole
353
+ /// format.
354
+ function updateGatewayAddress(uint16 chainId, bytes32 gateway)
355
+ external
356
+ onlyOwner
357
+ {
358
+ gateways[chainId] = gateway;
359
+ emit GatewayAddressUpdated(chainId, gateway);
360
+ }
361
+
362
+ /// @notice Lets the governance to update the tBTC minting limit for this
363
+ /// contract.
364
+ /// @param _mintingLimit The new minting limit.
365
+ function updateMintingLimit(uint256 _mintingLimit) external onlyOwner {
366
+ mintingLimit = _mintingLimit;
367
+ emit MintingLimitUpdated(_mintingLimit);
368
+ }
369
+
370
+ /// @notice Converts Ethereum address into Wormhole format.
371
+ /// @param _address The address to convert.
372
+ function toWormholeAddress(address _address)
373
+ external
374
+ pure
375
+ returns (bytes32)
376
+ {
377
+ return bytes32(uint256(uint160(_address)));
378
+ }
379
+
380
+ /// @notice Converts Wormhole address into Ethereum format.
381
+ /// @param _address The address to convert.
382
+ function fromWormholeAddress(bytes32 _address)
383
+ public
384
+ pure
385
+ returns (address)
386
+ {
387
+ return address(uint160(uint256(_address)));
388
+ }
389
+ }
@@ -109,32 +109,32 @@
109
109
  {
110
110
  "ast": {
111
111
  "nodeType": "YulBlock",
112
- "src": "0:201:120",
112
+ "src": "0:201:123",
113
113
  "statements": [
114
114
  {
115
115
  "nodeType": "YulBlock",
116
- "src": "6:3:120",
116
+ "src": "6:3:123",
117
117
  "statements": []
118
118
  },
119
119
  {
120
120
  "body": {
121
121
  "nodeType": "YulBlock",
122
- "src": "123:76:120",
122
+ "src": "123:76:123",
123
123
  "statements": [
124
124
  {
125
125
  "nodeType": "YulAssignment",
126
- "src": "133:26:120",
126
+ "src": "133:26:123",
127
127
  "value": {
128
128
  "arguments": [
129
129
  {
130
130
  "name": "headStart",
131
131
  "nodeType": "YulIdentifier",
132
- "src": "145:9:120"
132
+ "src": "145:9:123"
133
133
  },
134
134
  {
135
135
  "kind": "number",
136
136
  "nodeType": "YulLiteral",
137
- "src": "156:2:120",
137
+ "src": "156:2:123",
138
138
  "type": "",
139
139
  "value": "32"
140
140
  }
@@ -142,16 +142,16 @@
142
142
  "functionName": {
143
143
  "name": "add",
144
144
  "nodeType": "YulIdentifier",
145
- "src": "141:3:120"
145
+ "src": "141:3:123"
146
146
  },
147
147
  "nodeType": "YulFunctionCall",
148
- "src": "141:18:120"
148
+ "src": "141:18:123"
149
149
  },
150
150
  "variableNames": [
151
151
  {
152
152
  "name": "tail",
153
153
  "nodeType": "YulIdentifier",
154
- "src": "133:4:120"
154
+ "src": "133:4:123"
155
155
  }
156
156
  ]
157
157
  },
@@ -161,24 +161,24 @@
161
161
  {
162
162
  "name": "headStart",
163
163
  "nodeType": "YulIdentifier",
164
- "src": "175:9:120"
164
+ "src": "175:9:123"
165
165
  },
166
166
  {
167
167
  "name": "value0",
168
168
  "nodeType": "YulIdentifier",
169
- "src": "186:6:120"
169
+ "src": "186:6:123"
170
170
  }
171
171
  ],
172
172
  "functionName": {
173
173
  "name": "mstore",
174
174
  "nodeType": "YulIdentifier",
175
- "src": "168:6:120"
175
+ "src": "168:6:123"
176
176
  },
177
177
  "nodeType": "YulFunctionCall",
178
- "src": "168:25:120"
178
+ "src": "168:25:123"
179
179
  },
180
180
  "nodeType": "YulExpressionStatement",
181
- "src": "168:25:120"
181
+ "src": "168:25:123"
182
182
  }
183
183
  ]
184
184
  },
@@ -188,13 +188,13 @@
188
188
  {
189
189
  "name": "headStart",
190
190
  "nodeType": "YulTypedName",
191
- "src": "92:9:120",
191
+ "src": "92:9:123",
192
192
  "type": ""
193
193
  },
194
194
  {
195
195
  "name": "value0",
196
196
  "nodeType": "YulTypedName",
197
- "src": "103:6:120",
197
+ "src": "103:6:123",
198
198
  "type": ""
199
199
  }
200
200
  ],
@@ -202,16 +202,16 @@
202
202
  {
203
203
  "name": "tail",
204
204
  "nodeType": "YulTypedName",
205
- "src": "114:4:120",
205
+ "src": "114:4:123",
206
206
  "type": ""
207
207
  }
208
208
  ],
209
- "src": "14:185:120"
209
+ "src": "14:185:123"
210
210
  }
211
211
  ]
212
212
  },
213
213
  "contents": "{\n { }\n function abi_encode_tuple_t_uint256__to_t_uint256__fromStack_library_reversed(headStart, value0) -> tail\n {\n tail := add(headStart, 32)\n mstore(headStart, value0)\n }\n}",
214
- "id": 120,
214
+ "id": 123,
215
215
  "language": "Yul",
216
216
  "name": "#utility.yul"
217
217
  }
@@ -219,7 +219,7 @@
219
219
  "immutableReferences": {},
220
220
  "linkReferences": {},
221
221
  "opcodes": "PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x51 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x56E04EC EQ PUSH1 0x56 JUMPI DUP1 PUSH4 0x8CC71569 EQ PUSH1 0x71 JUMPI DUP1 PUSH4 0x8DB69E60 EQ PUSH1 0x79 JUMPI DUP1 PUSH4 0xD4258CA7 EQ PUSH1 0x81 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x5F PUSH3 0x127500 DUP2 JUMP JUMPDEST PUSH1 0x40 MLOAD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x5F PUSH2 0x7E0 DUP2 JUMP JUMPDEST PUSH1 0x5F PUSH1 0x0 NOT DUP2 JUMP JUMPDEST PUSH1 0x5F PUSH28 0xFFFF0000000000000000000000000000000000000000000000000000 DUP2 JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0x21 0xD8 0x5F GT 0xF6 0x4E 0xD4 0x4F 0xFB 0xA5 SWAP12 0xFC PUSH12 0x4A327F00D51E8E91CA784A04 DUP14 CALLDATACOPY 0x29 0xDB ADD 0xB3 PUSH32 0x64736F6C63430008110033000000000000000000000000000000000000000000 ",
222
- "sourceMap": "175:38691:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;443:62;;485:20;443:62;;;;;168:25:120;;;156:2;141:18;443:62:0;;;;;;;534:53;;583:4;534:53;;616:104;;-1:-1:-1;;616:104:0;;339:97;;378:58;339:97;"
222
+ "sourceMap": "175:38691:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;443:62;;485:20;443:62;;;;;168:25:123;;;156:2;141:18;443:62:0;;;;;;;534:53;;583:4;534:53;;616:104;;-1:-1:-1;;616:104:0;;339:97;;378:58;339:97;"
223
223
  },
224
224
  "gasEstimates": {
225
225
  "creation": {