@across-protocol/contracts 5.0.9 → 5.0.10-alpha.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.
- package/contracts/interfaces/SponsoredCCTPInterface.sol +19 -0
- package/contracts/interfaces/SponsoredOFTInterface.sol +21 -2
- package/contracts/periphery/mintburn/BaseModuleHandler.sol +1 -0
- package/contracts/periphery/mintburn/HyperCoreFlowRoles.sol +1 -0
- package/contracts/periphery/mintburn/sponsored-cctp/SponsoredCCTPDstPeriphery.sol +24 -2
- package/contracts/periphery/mintburn/sponsored-cctp/SponsoredCCTPSrcPeriphery.sol +64 -37
- package/contracts/periphery/mintburn/sponsored-oft/DstOFTHandler.sol +28 -2
- package/contracts/periphery/mintburn/sponsored-oft/SponsoredOFTSrcPeriphery.sol +66 -33
- package/dist/broadcast/deployed-addresses.json +34 -24
- package/dist/evm/artifacts/BaseModuleHandler.sol/BaseModuleHandler.json +1 -1
- package/dist/evm/artifacts/CounterfactualDepositCCTP.sol/CounterfactualDepositCCTP.json +1 -1
- package/dist/evm/artifacts/CounterfactualDepositOFT.sol/CounterfactualDepositOFT.json +1 -1
- package/dist/evm/artifacts/DstOFTHandler.sol/DstOFTHandler.json +1 -1
- package/dist/evm/artifacts/HyperCoreFlowExecutor.sol/HyperCoreFlowExecutor.json +1 -1
- package/dist/evm/artifacts/HyperCoreFlowRoles.sol/HyperCoreFlowRoles.json +1 -1
- package/dist/evm/artifacts/SponsoredCCTPDstPeriphery.sol/SponsoredCCTPDstPeriphery.json +1 -1
- package/dist/evm/artifacts/SponsoredCCTPInterface.sol/SponsoredCCTPInterface.json +1 -1
- package/dist/evm/artifacts/SponsoredCCTPSrcPeriphery.sol/SponsoredCCTPSrcPeriphery.json +1 -1
- package/dist/evm/artifacts/SponsoredOFTInterface.sol/SponsoredOFTInterface.json +1 -1
- package/dist/evm/artifacts/SponsoredOFTSrcPeriphery.sol/SponsoredOFTSrcPeriphery.json +1 -1
- package/package.json +1 -1
|
@@ -24,6 +24,12 @@ interface SponsoredCCTPInterface is SponsoredExecutionModeInterface {
|
|
|
24
24
|
// Error thrown when the CCTP message transmitter receive message fails.
|
|
25
25
|
error CCTPMessageTransmitterFailed();
|
|
26
26
|
|
|
27
|
+
// Error thrown when direct flow destination handler is not a contract.
|
|
28
|
+
error InvalidDirectHandler();
|
|
29
|
+
|
|
30
|
+
// Error thrown when the burn token is invalid.
|
|
31
|
+
error InvalidBurnToken();
|
|
32
|
+
|
|
27
33
|
event SponsoredDepositForBurn(
|
|
28
34
|
bytes32 indexed quoteNonce,
|
|
29
35
|
address indexed originSender,
|
|
@@ -37,6 +43,19 @@ interface SponsoredCCTPInterface is SponsoredExecutionModeInterface {
|
|
|
37
43
|
bytes signature
|
|
38
44
|
);
|
|
39
45
|
|
|
46
|
+
event SponsoredCCTPDirectExecution(
|
|
47
|
+
bytes32 indexed quoteNonce,
|
|
48
|
+
address indexed originSender,
|
|
49
|
+
bytes32 indexed finalRecipient,
|
|
50
|
+
uint256 quoteDeadline,
|
|
51
|
+
uint256 maxBpsToSponsor,
|
|
52
|
+
uint256 maxUserSlippageBps,
|
|
53
|
+
bytes32 finalToken,
|
|
54
|
+
uint32 destinationDex,
|
|
55
|
+
uint8 accountCreationMode,
|
|
56
|
+
bytes signature
|
|
57
|
+
);
|
|
58
|
+
|
|
40
59
|
// Event when emergency receive is called
|
|
41
60
|
event EmergencyReceiveMessage(bytes32 nonce, address finalRecipent, address finalToken, uint256 amount);
|
|
42
61
|
|
|
@@ -60,6 +60,21 @@ interface SponsoredOFTInterface is SponsoredExecutionModeInterface {
|
|
|
60
60
|
bytes sig
|
|
61
61
|
);
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* @notice Event emitted when quote is executed locally without OFT bridging.
|
|
65
|
+
*/
|
|
66
|
+
event SponsoredOFTDirectExecution(
|
|
67
|
+
bytes32 indexed quoteNonce,
|
|
68
|
+
address indexed originSender,
|
|
69
|
+
bytes32 indexed finalRecipient,
|
|
70
|
+
bytes32 destinationHandler,
|
|
71
|
+
uint256 quoteDeadline,
|
|
72
|
+
uint256 maxBpsToSponsor,
|
|
73
|
+
uint256 maxUserSlippageBps,
|
|
74
|
+
bytes32 finalToken,
|
|
75
|
+
bytes sig
|
|
76
|
+
);
|
|
77
|
+
|
|
63
78
|
/// @notice Thrown when the source eid of the ioft messenger does not match the src eid supplied.
|
|
64
79
|
error IncorrectSrcEid();
|
|
65
80
|
/// @notice Thrown when the supplied token does not match the supplied ioft messenger.
|
|
@@ -70,12 +85,16 @@ interface SponsoredOFTInterface is SponsoredExecutionModeInterface {
|
|
|
70
85
|
error QuoteExpired();
|
|
71
86
|
/// @notice Thrown if Quote nonce was already used.
|
|
72
87
|
error NonceAlreadyUsed();
|
|
73
|
-
/// @notice Thrown when
|
|
74
|
-
error
|
|
88
|
+
/// @notice Thrown when msg.value does not match the expected native fee.
|
|
89
|
+
error InvalidNativeFee();
|
|
75
90
|
/// @notice Thrown when array lengths do not match.
|
|
76
91
|
error ArrayLengthMismatch();
|
|
77
92
|
/// @notice Thrown when maxOftFeeBps is greater than 10000.
|
|
78
93
|
error InvalidMaxOftFeeBps();
|
|
94
|
+
/// @notice Thrown when direct flow quote does not target current source eid.
|
|
95
|
+
error InvalidDirectDstEid();
|
|
96
|
+
/// @notice Thrown when destination handler is not a contract.
|
|
97
|
+
error InvalidDirectHandler();
|
|
79
98
|
|
|
80
99
|
/**
|
|
81
100
|
* @notice Returns the signer address that is used to validate the signatures of the quotes.
|
|
@@ -27,6 +27,7 @@ abstract contract BaseModuleHandler is
|
|
|
27
27
|
|
|
28
28
|
_setRoleAdmin(PERMISSIONED_BOT_ROLE, _roleAdmin);
|
|
29
29
|
_setRoleAdmin(FUNDS_SWEEPER_ROLE, _roleAdmin);
|
|
30
|
+
_setRoleAdmin(DIRECT_CALLER_ROLE, _roleAdmin);
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
/// @notice Fallback function to proxy all calls to the HyperCore module via delegatecall
|
|
@@ -4,4 +4,5 @@ pragma solidity ^0.8.0;
|
|
|
4
4
|
abstract contract HyperCoreFlowRoles {
|
|
5
5
|
bytes32 public constant PERMISSIONED_BOT_ROLE = keccak256("PERMISSIONED_BOT_ROLE");
|
|
6
6
|
bytes32 public constant FUNDS_SWEEPER_ROLE = keccak256("FUNDS_SWEEPER_ROLE");
|
|
7
|
+
bytes32 public constant DIRECT_CALLER_ROLE = keccak256("DIRECT_CALLER_ROLE");
|
|
7
8
|
}
|
|
@@ -192,16 +192,38 @@ contract SponsoredCCTPDstPeriphery is BaseModuleHandler, SponsoredCCTPInterface,
|
|
|
192
192
|
// where an attacker provides correct message/attestation but invalid signature.
|
|
193
193
|
_validateQuoteOrRevert(quote, signature);
|
|
194
194
|
|
|
195
|
+
_executeQuote(quote, feeExecuted);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @notice Direct execution entrypoint for same-chain flows that bypass CCTP transport.
|
|
200
|
+
* @dev Caller must hold DIRECT_CALLER_ROLE and transfer baseToken funds to this contract before invoking.
|
|
201
|
+
* @param quote The quote that contains the data for the deposit.
|
|
202
|
+
*/
|
|
203
|
+
function directReceiveMessage(
|
|
204
|
+
SponsoredCCTPInterface.SponsoredCCTPQuote memory quote
|
|
205
|
+
) external nonReentrant authorizeFundedFlow onlyRole(DIRECT_CALLER_ROLE) {
|
|
206
|
+
if (quote.burnToken.toAddress() != baseToken) revert InvalidBurnToken();
|
|
207
|
+
MainStorage storage $ = _getMainStorage();
|
|
208
|
+
if ($.usedNonces[quote.nonce]) revert InvalidNonce();
|
|
209
|
+
$.usedNonces[quote.nonce] = true;
|
|
210
|
+
_executeQuote(quote, 0);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* @notice Shared execution logic for both CCTP-bridged and direct flows.
|
|
215
|
+
* @param quote The validated quote.
|
|
216
|
+
* @param feeExecuted The CCTP fee deducted (0 for direct flows).
|
|
217
|
+
*/
|
|
218
|
+
function _executeQuote(SponsoredCCTPInterface.SponsoredCCTPQuote memory quote, uint256 feeExecuted) internal {
|
|
195
219
|
uint256 amountAfterFees = quote.amount - feeExecuted;
|
|
196
220
|
|
|
197
221
|
CommonFlowParams memory commonParams = CommonFlowParams({
|
|
198
222
|
amountInEVM: amountAfterFees,
|
|
199
223
|
quoteNonce: quote.nonce,
|
|
200
224
|
finalRecipient: quote.finalRecipient.toAddress(),
|
|
201
|
-
// If the quote is invalid we don't want to swap, so we use the base token as the final token
|
|
202
225
|
finalToken: quote.finalToken.toAddress(),
|
|
203
226
|
destinationDex: quote.destinationDex,
|
|
204
|
-
// If the quote is invalid we don't sponsor the flow or the extra fees
|
|
205
227
|
maxBpsToSponsor: quote.maxBpsToSponsor,
|
|
206
228
|
extraFeesIncurred: feeExecuted,
|
|
207
229
|
accountCreationMode: StructsAccountCreationMode(quote.accountCreationMode)
|
|
@@ -4,10 +4,13 @@ pragma solidity ^0.8.0;
|
|
|
4
4
|
import { Ownable } from "@openzeppelin/contracts-v4/access/Ownable.sol";
|
|
5
5
|
import { IERC20 } from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol";
|
|
6
6
|
import { SafeERC20 } from "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20.sol";
|
|
7
|
+
import { Address } from "@openzeppelin/contracts-v4/utils/Address.sol";
|
|
7
8
|
import { ITokenMessengerV2 } from "../../../external/interfaces/CCTPInterfaces.sol";
|
|
8
9
|
|
|
9
10
|
import { SponsoredCCTPQuoteLib } from "../../../libraries/SponsoredCCTPQuoteLib.sol";
|
|
10
11
|
import { SponsoredCCTPInterface } from "../../../interfaces/SponsoredCCTPInterface.sol";
|
|
12
|
+
import { SponsoredCCTPDstPeriphery } from "./SponsoredCCTPDstPeriphery.sol";
|
|
13
|
+
import { Bytes32ToAddress } from "../../../libraries/AddressConverters.sol";
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
16
|
* @title SponsoredCCTPSrcPeriphery
|
|
@@ -16,6 +19,8 @@ import { SponsoredCCTPInterface } from "../../../interfaces/SponsoredCCTPInterfa
|
|
|
16
19
|
*/
|
|
17
20
|
contract SponsoredCCTPSrcPeriphery is SponsoredCCTPInterface, Ownable {
|
|
18
21
|
using SafeERC20 for IERC20;
|
|
22
|
+
using Bytes32ToAddress for bytes32;
|
|
23
|
+
using Address for address;
|
|
19
24
|
|
|
20
25
|
/// @notice The CCTP token messenger contract.
|
|
21
26
|
ITokenMessengerV2 public immutable cctpTokenMessenger;
|
|
@@ -81,45 +86,67 @@ contract SponsoredCCTPSrcPeriphery is SponsoredCCTPInterface, Ownable {
|
|
|
81
86
|
if (quote.deadline < block.timestamp) revert InvalidDeadline();
|
|
82
87
|
if (quote.sourceDomain != sourceDomain) revert InvalidSourceDomain();
|
|
83
88
|
|
|
84
|
-
(
|
|
85
|
-
uint256 amount,
|
|
86
|
-
uint32 destinationDomain,
|
|
87
|
-
bytes32 mintRecipient,
|
|
88
|
-
address burnToken,
|
|
89
|
-
bytes32 destinationCaller,
|
|
90
|
-
uint256 maxFee,
|
|
91
|
-
uint32 minFinalityThreshold,
|
|
92
|
-
bytes memory hookData
|
|
93
|
-
) = SponsoredCCTPQuoteLib.getDepositForBurnData(quote);
|
|
94
|
-
|
|
95
89
|
$.usedNonces[quote.nonce] = true;
|
|
96
90
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
91
|
+
if (quote.destinationDomain == sourceDomain) {
|
|
92
|
+
address destinationHandler = quote.mintRecipient.toAddress();
|
|
93
|
+
if (!destinationHandler.isContract()) revert InvalidDirectHandler();
|
|
94
|
+
|
|
95
|
+
address burnToken = quote.burnToken.toAddress();
|
|
96
|
+
IERC20(burnToken).safeTransferFrom(msg.sender, destinationHandler, quote.amount);
|
|
97
|
+
SponsoredCCTPDstPeriphery(payable(destinationHandler)).directReceiveMessage(quote);
|
|
98
|
+
|
|
99
|
+
emit SponsoredCCTPDirectExecution(
|
|
100
|
+
quote.nonce,
|
|
101
|
+
msg.sender,
|
|
102
|
+
quote.finalRecipient,
|
|
103
|
+
quote.deadline,
|
|
104
|
+
quote.maxBpsToSponsor,
|
|
105
|
+
quote.maxUserSlippageBps,
|
|
106
|
+
quote.finalToken,
|
|
107
|
+
quote.destinationDex,
|
|
108
|
+
quote.accountCreationMode,
|
|
109
|
+
signature
|
|
110
|
+
);
|
|
111
|
+
} else {
|
|
112
|
+
(
|
|
113
|
+
uint256 amount,
|
|
114
|
+
uint32 destinationDomain,
|
|
115
|
+
bytes32 mintRecipient,
|
|
116
|
+
address burnToken,
|
|
117
|
+
bytes32 destinationCaller,
|
|
118
|
+
uint256 maxFee,
|
|
119
|
+
uint32 minFinalityThreshold,
|
|
120
|
+
bytes memory hookData
|
|
121
|
+
) = SponsoredCCTPQuoteLib.getDepositForBurnData(quote);
|
|
122
|
+
|
|
123
|
+
IERC20(burnToken).safeTransferFrom(msg.sender, address(this), amount);
|
|
124
|
+
IERC20(burnToken).forceApprove(address(cctpTokenMessenger), amount);
|
|
125
|
+
|
|
126
|
+
cctpTokenMessenger.depositForBurnWithHook(
|
|
127
|
+
amount,
|
|
128
|
+
destinationDomain,
|
|
129
|
+
mintRecipient,
|
|
130
|
+
burnToken,
|
|
131
|
+
destinationCaller,
|
|
132
|
+
maxFee,
|
|
133
|
+
minFinalityThreshold,
|
|
134
|
+
hookData
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
emit SponsoredDepositForBurn(
|
|
138
|
+
quote.nonce,
|
|
139
|
+
msg.sender,
|
|
140
|
+
quote.finalRecipient,
|
|
141
|
+
quote.deadline,
|
|
142
|
+
quote.maxBpsToSponsor,
|
|
143
|
+
quote.maxUserSlippageBps,
|
|
144
|
+
quote.finalToken,
|
|
145
|
+
quote.destinationDex,
|
|
146
|
+
quote.accountCreationMode,
|
|
147
|
+
signature
|
|
148
|
+
);
|
|
149
|
+
}
|
|
123
150
|
}
|
|
124
151
|
|
|
125
152
|
/**
|
|
@@ -78,6 +78,8 @@ contract DstOFTHandler is BaseModuleHandler, OFTCoreMath, ILayerZeroComposer, Ar
|
|
|
78
78
|
error UnauthorizedEndpoint();
|
|
79
79
|
/// @notice Thrown when supplied _composeMsg format is unexpected
|
|
80
80
|
error InvalidComposeMsgFormat();
|
|
81
|
+
/// @notice Thrown when direct execution is attempted with unsupported token.
|
|
82
|
+
error InvalidDirectToken();
|
|
81
83
|
|
|
82
84
|
constructor(
|
|
83
85
|
address _oftEndpoint,
|
|
@@ -166,9 +168,33 @@ contract DstOFTHandler is BaseModuleHandler, OFTCoreMath, ILayerZeroComposer, Ar
|
|
|
166
168
|
|
|
167
169
|
// Amount received from `lzReceive` on destination. May be different from the amount the user originally sent (if the OFT takes a fee in the bridged token)
|
|
168
170
|
uint256 amountLD = OFTComposeMsgCodec.amountLD(_message);
|
|
171
|
+
_executeFromComposeMsg(composeMsg, amountLD);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* @notice Direct execution entrypoint for same-chain flows that bypass OFT transport.
|
|
176
|
+
* @dev Caller must hold DIRECT_CALLER_ROLE and transfer baseToken funds to this contract before invoking.
|
|
177
|
+
*/
|
|
178
|
+
function executeDirect(
|
|
179
|
+
address tokenSent,
|
|
180
|
+
uint256 amountLD,
|
|
181
|
+
bytes calldata composeMsg
|
|
182
|
+
) external nonReentrant authorizeFundedFlow onlyRole(DIRECT_CALLER_ROLE) {
|
|
183
|
+
if (tokenSent != baseToken) revert InvalidDirectToken();
|
|
184
|
+
if (!composeMsg._isValidComposeMsgBytelength()) revert InvalidComposeMsgFormat();
|
|
169
185
|
|
|
170
|
-
|
|
171
|
-
|
|
186
|
+
bytes32 quoteNonce = composeMsg._getNonce();
|
|
187
|
+
MainStorage storage $ = _getMainStorage();
|
|
188
|
+
if ($.usedNonces[quoteNonce]) revert NonceAlreadyUsed();
|
|
189
|
+
$.usedNonces[quoteNonce] = true;
|
|
190
|
+
|
|
191
|
+
_executeFromComposeMsg(composeMsg, amountLD);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function _executeFromComposeMsg(bytes memory composeMsg, uint256 amountLD) internal {
|
|
195
|
+
bytes32 quoteNonce = composeMsg._getNonce();
|
|
196
|
+
// We trust src side to encode the correct amountSD. It pulls amountLD from the user, using IOFT's sharedDecimals()
|
|
197
|
+
// for conversion to SD. For direct path, amountLD is supplied by trusted direct caller.
|
|
172
198
|
uint256 amountSentSD = composeMsg._getAmountSD();
|
|
173
199
|
uint256 amountSentLD = _toLD(uint64(amountSentSD));
|
|
174
200
|
|
|
@@ -4,9 +4,10 @@ pragma solidity ^0.8.23;
|
|
|
4
4
|
import { SponsoredOFTInterface } from "../../../interfaces/SponsoredOFTInterface.sol";
|
|
5
5
|
import { QuoteSignLib } from "./QuoteSignLib.sol";
|
|
6
6
|
import { ComposeMsgCodec } from "./ComposeMsgCodec.sol";
|
|
7
|
+
import { DstOFTHandler } from "./DstOFTHandler.sol";
|
|
7
8
|
|
|
8
9
|
import { IOFT, IOAppCore, SendParam, MessagingFee } from "../../../interfaces/IOFT.sol";
|
|
9
|
-
import { AddressToBytes32 } from "../../../libraries/AddressConverters.sol";
|
|
10
|
+
import { AddressToBytes32, Bytes32ToAddress } from "../../../libraries/AddressConverters.sol";
|
|
10
11
|
import { MinimalLZOptions } from "../../../external/libraries/MinimalLZOptions.sol";
|
|
11
12
|
import { OFTCoreMath } from "../../../external/libraries/OFTCoreMath.sol";
|
|
12
13
|
|
|
@@ -14,6 +15,7 @@ import { Ownable } from "@openzeppelin/contracts-v4/access/Ownable.sol";
|
|
|
14
15
|
import { IERC20 } from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol";
|
|
15
16
|
import { IERC20Metadata } from "@openzeppelin/contracts-v4/token/ERC20/extensions/IERC20Metadata.sol";
|
|
16
17
|
import { SafeERC20 } from "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20.sol";
|
|
18
|
+
import { Address } from "@openzeppelin/contracts-v4/utils/Address.sol";
|
|
17
19
|
|
|
18
20
|
/// @notice Source chain periphery contract for users to interact with to start a sponsored or a non-sponsored flow
|
|
19
21
|
/// that allows custom Across-supported flows on destination chain. Uses LayerZero's OFT as an underlying bridge
|
|
@@ -21,6 +23,8 @@ contract SponsoredOFTSrcPeriphery is Ownable, OFTCoreMath, SponsoredOFTInterface
|
|
|
21
23
|
using AddressToBytes32 for address;
|
|
22
24
|
using MinimalLZOptions for bytes;
|
|
23
25
|
using SafeERC20 for IERC20;
|
|
26
|
+
using Bytes32ToAddress for bytes32;
|
|
27
|
+
using Address for address;
|
|
24
28
|
|
|
25
29
|
bytes public constant EMPTY_OFT_COMMAND = new bytes(0);
|
|
26
30
|
|
|
@@ -90,42 +94,71 @@ contract SponsoredOFTSrcPeriphery is Ownable, OFTCoreMath, SponsoredOFTInterface
|
|
|
90
94
|
* @param signature The signature authorizing the quote
|
|
91
95
|
*/
|
|
92
96
|
function deposit(Quote calldata quote, bytes calldata signature) external payable {
|
|
93
|
-
// Step 1: validate quote and mark quote nonce used
|
|
94
97
|
_validateQuote(quote, signature);
|
|
95
98
|
_getMainStorage().quoteNonces[quote.signedParams.nonce] = true;
|
|
96
99
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
100
|
+
if (quote.signedParams.dstEid == SRC_EID) {
|
|
101
|
+
if (msg.value > 0) revert InvalidNativeFee();
|
|
102
|
+
address destinationHandler = quote.signedParams.destinationHandler.toAddress();
|
|
103
|
+
if (!destinationHandler.isContract()) revert InvalidDirectHandler();
|
|
104
|
+
|
|
105
|
+
bytes memory composeMsg = ComposeMsgCodec._encode(
|
|
106
|
+
quote.signedParams.nonce,
|
|
107
|
+
uint256(_toSD(quote.signedParams.amountLD)),
|
|
108
|
+
quote.signedParams.maxBpsToSponsor,
|
|
109
|
+
quote.signedParams.maxUserSlippageBps,
|
|
110
|
+
quote.signedParams.finalRecipient,
|
|
111
|
+
quote.signedParams.finalToken,
|
|
112
|
+
quote.signedParams.destinationDex,
|
|
113
|
+
quote.signedParams.accountCreationMode,
|
|
114
|
+
quote.signedParams.executionMode,
|
|
115
|
+
quote.signedParams.actionData
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
IERC20(TOKEN).safeTransferFrom(msg.sender, destinationHandler, quote.signedParams.amountLD);
|
|
119
|
+
DstOFTHandler(payable(destinationHandler)).executeDirect(TOKEN, quote.signedParams.amountLD, composeMsg);
|
|
120
|
+
|
|
121
|
+
emit SponsoredOFTDirectExecution(
|
|
122
|
+
quote.signedParams.nonce,
|
|
123
|
+
msg.sender,
|
|
124
|
+
quote.signedParams.finalRecipient,
|
|
125
|
+
quote.signedParams.destinationHandler,
|
|
126
|
+
quote.signedParams.deadline,
|
|
127
|
+
quote.signedParams.maxBpsToSponsor,
|
|
128
|
+
quote.signedParams.maxUserSlippageBps,
|
|
129
|
+
quote.signedParams.finalToken,
|
|
130
|
+
signature
|
|
131
|
+
);
|
|
132
|
+
} else {
|
|
133
|
+
(SendParam memory sendParam, MessagingFee memory fee, address refundAddress) = _buildOftTransfer(quote);
|
|
134
|
+
|
|
135
|
+
if (fee.nativeFee > msg.value) {
|
|
136
|
+
revert InvalidNativeFee();
|
|
137
|
+
}
|
|
138
|
+
// OFT doesn't refund the unused native fee portion. Instead, it expects precise fee.nativeFee to be transferred
|
|
139
|
+
// as msg.value, so we refund the user ourselves
|
|
140
|
+
uint256 nativeFeeRefund = msg.value - fee.nativeFee;
|
|
141
|
+
if (nativeFeeRefund > 0) {
|
|
142
|
+
(bool success, ) = payable(refundAddress).call{ value: nativeFeeRefund }("");
|
|
143
|
+
require(success, "Unable to send value, recipient may have reverted");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
IERC20(TOKEN).safeTransferFrom(msg.sender, address(this), quote.signedParams.amountLD);
|
|
147
|
+
IERC20(TOKEN).forceApprove(address(OFT_MESSENGER), quote.signedParams.amountLD);
|
|
148
|
+
|
|
149
|
+
IOFT(OFT_MESSENGER).send{ value: fee.nativeFee }(sendParam, fee, refundAddress);
|
|
150
|
+
emit SponsoredOFTSend(
|
|
151
|
+
quote.signedParams.nonce,
|
|
152
|
+
msg.sender,
|
|
153
|
+
quote.signedParams.finalRecipient,
|
|
154
|
+
quote.signedParams.destinationHandler,
|
|
155
|
+
quote.signedParams.deadline,
|
|
156
|
+
quote.signedParams.maxBpsToSponsor,
|
|
157
|
+
quote.signedParams.maxUserSlippageBps,
|
|
158
|
+
quote.signedParams.finalToken,
|
|
159
|
+
signature
|
|
160
|
+
);
|
|
110
161
|
}
|
|
111
|
-
|
|
112
|
-
// Step 3: pull tokens from user and apporove OFT messenger
|
|
113
|
-
IERC20(TOKEN).safeTransferFrom(msg.sender, address(this), quote.signedParams.amountLD);
|
|
114
|
-
IERC20(TOKEN).forceApprove(address(OFT_MESSENGER), quote.signedParams.amountLD);
|
|
115
|
-
|
|
116
|
-
// Step 4: send oft transfer and emit event with auxiliary data
|
|
117
|
-
IOFT(OFT_MESSENGER).send{ value: fee.nativeFee }(sendParam, fee, refundAddress);
|
|
118
|
-
emit SponsoredOFTSend(
|
|
119
|
-
quote.signedParams.nonce,
|
|
120
|
-
msg.sender,
|
|
121
|
-
quote.signedParams.finalRecipient,
|
|
122
|
-
quote.signedParams.destinationHandler,
|
|
123
|
-
quote.signedParams.deadline,
|
|
124
|
-
quote.signedParams.maxBpsToSponsor,
|
|
125
|
-
quote.signedParams.maxUserSlippageBps,
|
|
126
|
-
quote.signedParams.finalToken,
|
|
127
|
-
signature
|
|
128
|
-
);
|
|
129
162
|
}
|
|
130
163
|
|
|
131
164
|
function _buildOftTransfer(
|
|
@@ -211,19 +211,19 @@
|
|
|
211
211
|
"transaction_hash": "0xa2a7b2c6812fb8ae34539fb04cd5f2a9112da1c7f6ffce0ddcf1fee7e43acf48"
|
|
212
212
|
},
|
|
213
213
|
"PermissionedMulticallHandler": {
|
|
214
|
-
"address": "
|
|
215
|
-
"block_number":
|
|
216
|
-
"transaction_hash": "
|
|
214
|
+
"address": "0xD9D9Fd5A693dCD8FEf97A1d58d1d38aeeE771dF4",
|
|
215
|
+
"block_number": 24923036,
|
|
216
|
+
"transaction_hash": "0xdf6e007fee3ff93b47e6b135cb0ba9457fafea8f38350025e7c8c84d46ef0905"
|
|
217
217
|
},
|
|
218
218
|
"DonationBox_CCTP": {
|
|
219
|
-
"address": "
|
|
220
|
-
"block_number":
|
|
221
|
-
"transaction_hash": "
|
|
219
|
+
"address": "0xE694EbDFfCAD44ffb2025E2341027743fFDEAe3f",
|
|
220
|
+
"block_number": 24923037,
|
|
221
|
+
"transaction_hash": "0xa718319386ecd03007db65595e2905385658c329a7beb626e3403eb0bd594ea4"
|
|
222
222
|
},
|
|
223
223
|
"SponsoredCCTPDstPeriphery": {
|
|
224
|
-
"address": "
|
|
225
|
-
"block_number":
|
|
226
|
-
"transaction_hash": "
|
|
224
|
+
"address": "0x545cd9145A7B783328e9f0B9f489c962464F82e0",
|
|
225
|
+
"block_number": 24923038,
|
|
226
|
+
"transaction_hash": "0xd96182e721a33c860d4296d20d86e439bf423026841c8433e3d1ce5fe0321f82"
|
|
227
227
|
},
|
|
228
228
|
"SponsoredCCTPSrcPeriphery": {
|
|
229
229
|
"address": "0x6769155b16F25D317819eFef011E0A50A48e83c5",
|
|
@@ -869,20 +869,25 @@
|
|
|
869
869
|
"block_number": 32382094,
|
|
870
870
|
"transaction_hash": "0x188d49f786ebe99a6dbeb7c845d525064431a1eb615d0bea275d8da8a32953b1"
|
|
871
871
|
},
|
|
872
|
+
"PermissionedMulticallHandler": {
|
|
873
|
+
"address": "0xD7B719ed2b02Bfa0247600EDd6bd8Fb3957e95c8",
|
|
874
|
+
"block_number": 33686717,
|
|
875
|
+
"transaction_hash": "0x51bc99dd5ba78198246e16eee7b2f94dbe123720f05bffd1dd0862d5da8e2fb5"
|
|
876
|
+
},
|
|
872
877
|
"DonationBox_CCTP": {
|
|
873
|
-
"address": "
|
|
874
|
-
"block_number":
|
|
875
|
-
"transaction_hash": "
|
|
878
|
+
"address": "0xe3D0D1B6d3571EDC9657dB5076AC1Be5f0bBfE60",
|
|
879
|
+
"block_number": 33686717,
|
|
880
|
+
"transaction_hash": "0x38305e431db9c74a6f9fa2f6209c2086cc4b79f10ca3bfae773e4313914eaf28"
|
|
876
881
|
},
|
|
877
882
|
"SponsoredCCTPDstPeriphery": {
|
|
878
|
-
"address": "
|
|
879
|
-
"block_number":
|
|
880
|
-
"transaction_hash": "
|
|
883
|
+
"address": "0x1CFE31eD57c2d2b4CB69c0298A1b586965b882d5",
|
|
884
|
+
"block_number": 33686717,
|
|
885
|
+
"transaction_hash": "0x5730f65ea3507b2daea9a0a143b3da717d7f2194e428993fb04fddfb714eb66e"
|
|
881
886
|
},
|
|
882
887
|
"SponsoredCCTPSrcPeriphery": {
|
|
883
|
-
"address": "
|
|
884
|
-
"block_number":
|
|
885
|
-
"transaction_hash": "
|
|
888
|
+
"address": "0xF4E32c4aC479f0B007BC005Ec0F481A2C78Ba1B4",
|
|
889
|
+
"block_number": 33685558,
|
|
890
|
+
"transaction_hash": "0xef3bcc6d1bb0adc5a2b88c6dbe64a2492f72ac7d27a4aa6e42e5ace34df1f531"
|
|
886
891
|
},
|
|
887
892
|
"TransferProxy": {
|
|
888
893
|
"address": "0x8b2C0BFaBD6DaD8cc700dde3F168D3c81CF0eEfF",
|
|
@@ -1192,15 +1197,20 @@
|
|
|
1192
1197
|
"block_number": 43894633,
|
|
1193
1198
|
"transaction_hash": "0x28b429aae286cfb5f09ce924514384b64203a62def3fbb61296a93e1bb3636eb"
|
|
1194
1199
|
},
|
|
1200
|
+
"PermissionedMulticallHandler": {
|
|
1201
|
+
"address": "0xB6CAAfD8Ecf18385fFc7c020327E111a1D40A2D4",
|
|
1202
|
+
"block_number": 44959757,
|
|
1203
|
+
"transaction_hash": "0x0e3e581e4970cb3b9a193f8fddf7a63cbcc4c4f7b980139a6f685fbbfec1d459"
|
|
1204
|
+
},
|
|
1195
1205
|
"DonationBox_CCTP": {
|
|
1196
|
-
"address": "
|
|
1197
|
-
"block_number":
|
|
1198
|
-
"transaction_hash": "
|
|
1206
|
+
"address": "0x3ff139d8d5519555aA13b0eBd357B0Ba810f06Df",
|
|
1207
|
+
"block_number": 44959758,
|
|
1208
|
+
"transaction_hash": "0x019b8a736e60768ec4410e4e38c8ae4385e23e72c0cdcc9f305269d1208948c5"
|
|
1199
1209
|
},
|
|
1200
1210
|
"SponsoredCCTPDstPeriphery": {
|
|
1201
|
-
"address": "
|
|
1202
|
-
"block_number":
|
|
1203
|
-
"transaction_hash": "
|
|
1211
|
+
"address": "0x8dEDA155E446F5d90579C3DCe560e5b00e93F773",
|
|
1212
|
+
"block_number": 44959760,
|
|
1213
|
+
"transaction_hash": "0x052db9819150099889e890e641781eedcb3f7e016f87d72bea2984ce6554d350"
|
|
1204
1214
|
},
|
|
1205
1215
|
"SponsoredCCTPSrcPeriphery": {
|
|
1206
1216
|
"address": "0xa30968D3468316D957B9115EAad3C1c8E450116d",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"abi":[{"type":"fallback","stateMutability":"nonpayable"},{"type":"function","name":"AUTHORIZED_FUNDED_FLOW_SLOT","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"DEFAULT_ADMIN_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"FUNDS_SWEEPER_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"PERMISSIONED_BOT_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"getRoleAdmin","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"grantRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"hasRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"hyperCoreModule","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"renounceRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"callerConfirmation","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"revokeRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"event","name":"Initialized","inputs":[{"name":"version","type":"uint64","indexed":false,"internalType":"uint64"}],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"previousAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"newAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"neededRole","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"FundedFlowNotAuthorized","inputs":[]},{"type":"error","name":"InvalidInitialization","inputs":[]},{"type":"error","name":"NotInitializing","inputs":[]}],"bytecode":"0x"}
|
|
1
|
+
{"abi":[{"type":"fallback","stateMutability":"nonpayable"},{"type":"function","name":"AUTHORIZED_FUNDED_FLOW_SLOT","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"DEFAULT_ADMIN_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"DIRECT_CALLER_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"FUNDS_SWEEPER_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"PERMISSIONED_BOT_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"getRoleAdmin","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"grantRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"hasRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"hyperCoreModule","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"renounceRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"callerConfirmation","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"revokeRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"event","name":"Initialized","inputs":[{"name":"version","type":"uint64","indexed":false,"internalType":"uint64"}],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"previousAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"newAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"neededRole","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"FundedFlowNotAuthorized","inputs":[]},{"type":"error","name":"InvalidInitialization","inputs":[]},{"type":"error","name":"NotInitializing","inputs":[]}],"bytecode":"0x"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"abi":[{"type":"constructor","inputs":[{"name":"_srcPeriphery","type":"address","internalType":"address"},{"name":"_sourceDomain","type":"uint32","internalType":"uint32"}],"stateMutability":"nonpayable"},{"type":"function","name":"execute","inputs":[{"name":"params","type":"bytes","internalType":"bytes"},{"name":"submitterData","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"sourceDomain","inputs":[],"outputs":[{"name":"","type":"uint32","internalType":"uint32"}],"stateMutability":"view"},{"type":"function","name":"srcPeriphery","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"event","name":"CCTPDepositExecuted","inputs":[{"name":"amount","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"executionFeeRecipient","type":"address","indexed":true,"internalType":"address"},{"name":"nonce","type":"bytes32","indexed":false,"internalType":"bytes32"},{"name":"cctpDeadline","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"error","name":"SafeERC20FailedOperation","inputs":[{"name":"token","type":"address","internalType":"address"}]}],"bytecode":"
|
|
1
|
+
{"abi":[{"type":"constructor","inputs":[{"name":"_srcPeriphery","type":"address","internalType":"address"},{"name":"_sourceDomain","type":"uint32","internalType":"uint32"}],"stateMutability":"nonpayable"},{"type":"function","name":"execute","inputs":[{"name":"params","type":"bytes","internalType":"bytes"},{"name":"submitterData","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"sourceDomain","inputs":[],"outputs":[{"name":"","type":"uint32","internalType":"uint32"}],"stateMutability":"view"},{"type":"function","name":"srcPeriphery","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"event","name":"CCTPDepositExecuted","inputs":[{"name":"amount","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"executionFeeRecipient","type":"address","indexed":true,"internalType":"address"},{"name":"nonce","type":"bytes32","indexed":false,"internalType":"bytes32"},{"name":"cctpDeadline","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"error","name":"SafeERC20FailedOperation","inputs":[{"name":"token","type":"address","internalType":"address"}]}],"bytecode":"0x60c0346100b157601f610ab238819003918201601f19168301916001600160401b038311848410176100b55780849260409485528339810103126100b1578051906001600160a01b03821682036100b157602001519063ffffffff821682036100b15760805260a0526040516109e890816100ca8239608051818181605b0152818161032301528181610507015281816106820152818161076501526107c3015260a051818181609f01526104480152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe6101006040526004361015610012575f80fd5b5f5f3560e01c80631f6a1eb9146100c35780638ddb4a89146100825763d248e8951461003c575f80fd5b3461007f578060031936011261007f5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b80fd5b503461007f578060031936011261007f57602060405163ffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b5060403660031901126107225760043567ffffffffffffffff8111610722576100f09036906004016108c9565b60243567ffffffffffffffff8111610722576101109036906004016108c9565b91909260208183810103126107225780359067ffffffffffffffff8211610722576101e08282018483010312610722576102e0604052610151828201610919565b610100528082016020810135610120526040810135610140526060810135610160526080810135610180526101889060a001610919565b6101a05280820160c08101356101c05260e08101356101e05261010081013561020052610120810135610220526101c29061014001610919565b610240526101d58183016101600161092a565b610260526101e88183016101800161092a565b6102805267ffffffffffffffff8183016101a0013511610722576101c09261021b9082018383016101a081013501610938565b6102a0520101356102c0526020818301839003126107225781359167ffffffffffffffff83116107225760a08382018383010312610722576040519260a0840184811067ffffffffffffffff8211176107265760405281810180358552602001356001600160a01b038116900361072257818101602081810135908601526040808201359086015260608082013590860152608001359067ffffffffffffffff8211610722576102cf938301920101610938565b60808201526001600160a01b0360406101000151166101c0610100015180610868575b508151906101c0610100015160e0528160e05181031161073a5760405163095ea7b360e01b5f526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660045260e051830360245260205f60448180865af19060015f5114821615610859575b6040521561074e575b50610100516101205161014051610160516101805160e051939594929391928286038083029363ffffffff9092169290840414908614171561073a5763ffffffff60a0610100015116604088015160608901519160c061010001519360e06101000151956101008001519761012061010001519963ffffffff6101406101000151169b60ff6101606101000151169d60ff6101806101000151166080526101a0610100015160c05260405160a05261024060a051019560a051871067ffffffffffffffff881117610726576127109660405263ffffffff7f00000000000000000000000000000000000000000000000000000000000000001660a05152602060a0510152604060a051015260e0519003606060a0510152608060a051015260a0805101520460c060a051015260e060a051015261010060a051015261012060a051015261014060a051015261016060a051015261018060a05101526101a060a05101526101c060a05101526101e060a051015260805161020060a051015260c05161022060a051015260808101516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b15610722575f6106759160405180938192635c828f4360e11b83526040600484015263ffffffff60a0515116604484015263ffffffff602060a0510151166064840152604060a05101516084840152606060a051015160a4840152608060a051015160c484015260a08051015160e484015260c060a051015161010484015263ffffffff60e060a05101511661012484015261010060a051015161014484015261012060a051015161016484015261014060a051015161018484015261016060a05101516101a484015261018060a05101516101c48401526101a060a05101516101e484015263ffffffff6101c060a05101511661020484015260ff6101e060a05101511661022484015260ff61020060a05101511661024484015261066361022060a051015161024061026486015261028485019061098e565b8381036003190160248501529061098e565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1801561071757610702575b507f39c5f15e81023add0ebdd2b2e47d2c3f6301fac8b86a813fc927305f720ad27b606082516001600160a01b03602085015116938260408201519101519060405192835260208301526040820152a280f35b61070f9192505f906108f7565b5f905f6106af565b6040513d5f823e3d90fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b60405163095ea7b360e01b5f526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166004525f60245260205f60448180865af19060015f5114821615610841575b6040521561080e5760405163095ea7b360e01b5f526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660045260e051830360245260205f60448180865af19060015f5114821615610820575b60405261036f575b635274afe760e01b5f5260045260245ffd5b90600181151661083857823b15153d15161690610806565b503d5f823e3d90fd5b90600181151661083857823b15153d151616906107a4565b90823b15153d15161690610366565b6001600160a01b03602084015116906040519163a9059cbb60e01b5f5260045260245260205f60448180865af19060015f51148216156108b1575b6040521561080e575f6102f2565b90600181151661083857823b15153d151616906108a3565b9181601f840112156107225782359167ffffffffffffffff8311610722576020838186019501011161072257565b90601f8019910116810190811067ffffffffffffffff82111761072657604052565b359063ffffffff8216820361072257565b359060ff8216820361072257565b81601f820112156107225780359067ffffffffffffffff8211610726576040519261096d601f8401601f1916602001856108f7565b8284526020838301011161072257815f926020809301838601378301015290565b805180835260209291819084018484015e5f828201840152601f01601f191601019056fea2646970667358221220e76bd57dd6b82e94885402a7713923482705e4ed1af98215909fcbb3e25a935164736f6c634300081e0033"}
|