Source Code
Latest 25 from a total of 104,494 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Start | 364629465 | 183 days ago | IN | 0.00009 ETH | 0.00000672 | ||||
| Start | 360111170 | 196 days ago | IN | 0.000085 ETH | 0.00000268 | ||||
| Receive Message ... | 360099974 | 196 days ago | IN | 0 ETH | 0.00000595 | ||||
| Start | 360085170 | 196 days ago | IN | 0.0018 ETH | 0.00001019 | ||||
| Receive Message ... | 360057927 | 196 days ago | IN | 0 ETH | 0.00005974 | ||||
| Receive Message ... | 360041740 | 196 days ago | IN | 0 ETH | 0.00000753 | ||||
| Receive Message ... | 359990162 | 196 days ago | IN | 0 ETH | 0.00000468 | ||||
| Receive Message ... | 359953269 | 196 days ago | IN | 0 ETH | 0.00000461 | ||||
| Start | 359946429 | 196 days ago | IN | 0.0005 ETH | 0.0000037 | ||||
| Start | 359885271 | 196 days ago | IN | 0 ETH | 0.0000025 | ||||
| Receive Message ... | 359868745 | 196 days ago | IN | 0 ETH | 0.00000454 | ||||
| Receive Message ... | 359813250 | 197 days ago | IN | 0 ETH | 0.00000474 | ||||
| Start | 359805221 | 197 days ago | IN | 0.001 ETH | 0.00000259 | ||||
| Receive Message ... | 359797951 | 197 days ago | IN | 0 ETH | 0.00000631 | ||||
| Start | 359763940 | 197 days ago | IN | 0.00055 ETH | 0.00000647 | ||||
| Receive Message ... | 359755353 | 197 days ago | IN | 0 ETH | 0.00001767 | ||||
| Start | 359719231 | 197 days ago | IN | 0.00005959 ETH | 0.00000267 | ||||
| Receive Message ... | 359627091 | 197 days ago | IN | 0 ETH | 0.00000475 | ||||
| Start | 359582103 | 197 days ago | IN | 0.0001 ETH | 0.0000025 | ||||
| Receive Message ... | 359553299 | 197 days ago | IN | 0 ETH | 0.0000045 | ||||
| Start | 359444607 | 198 days ago | IN | 0.00030838 ETH | 0.0000043 | ||||
| Start | 359412353 | 198 days ago | IN | 0.00032 ETH | 0.00000252 | ||||
| Start | 359406357 | 198 days ago | IN | 0.0006 ETH | 0.00000259 | ||||
| Receive Message ... | 359364234 | 198 days ago | IN | 0 ETH | 0.00000519 | ||||
| Start | 359350617 | 198 days ago | IN | 0.0004054 ETH | 0.00000279 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 364629465 | 183 days ago | 0.00009 ETH | ||||
| 360111170 | 196 days ago | 0.000085 ETH | ||||
| 360099974 | 196 days ago | 0.00000892 ETH | ||||
| 360099974 | 196 days ago | 0.0099881 ETH | ||||
| 360099974 | 196 days ago | 0.00999702 ETH | ||||
| 360085170 | 196 days ago | 0.0018 ETH | ||||
| 360057927 | 196 days ago | 0.00002225 ETH | ||||
| 360057927 | 196 days ago | 0.00008241 ETH | ||||
| 360057927 | 196 days ago | 0.00010466 ETH | ||||
| 360041740 | 196 days ago | 0.00000905 ETH | ||||
| 360041740 | 196 days ago | 0.1399492 ETH | ||||
| 360041740 | 196 days ago | 0.13995825 ETH | ||||
| 359990162 | 196 days ago | 0.00000634 ETH | ||||
| 359990162 | 196 days ago | 0.00003964 ETH | ||||
| 359990162 | 196 days ago | 0.00004598 ETH | ||||
| 359953269 | 196 days ago | 0.00000632 ETH | ||||
| 359953269 | 196 days ago | 0.00004366 ETH | ||||
| 359953269 | 196 days ago | 0.00004999 ETH | ||||
| 359946429 | 196 days ago | 0.0005 ETH | ||||
| 359868745 | 196 days ago | 0.00000648 ETH | ||||
| 359868745 | 196 days ago | 0.00001548 ETH | ||||
| 359868745 | 196 days ago | 0.00002196 ETH | ||||
| 359813250 | 197 days ago | 0.00000606 ETH | ||||
| 359813250 | 197 days ago | 0.00009791 ETH | ||||
| 359813250 | 197 days ago | 0.00010397 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Portico
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSE
pragma solidity ^0.8.9;
import "./PorticoStructs.sol";
import "./ITokenBridge.sol";
import "./IWormhole.sol";
import "./IERC20.sol";
import "./IWETH.sol";
//uniswap
import "./uniswap/ISwapRouter02.sol";
//oz
import "./oz/Ownable.sol";
import "./oz/ReentrancyGuard.sol";
import "./oz/SafeERC20.sol";
contract PorticoBase is Ownable, ReentrancyGuard {
using SafeERC20 for IERC20;
ISwapRouter02 public immutable ROUTERV3;
ITokenBridge public immutable TOKENBRIDGE;
IWETH public immutable WETH;
IWormhole public immutable wormhole;
uint16 public immutable wormholeChainId;
address public FEE_RECIPIENT;
constructor(ISwapRouter02 _routerV3, ITokenBridge _bridge, IWETH _weth, address _feeRecipient) Ownable(_msgSender()) {
ROUTERV3 = _routerV3;
TOKENBRIDGE = _bridge;
wormhole = _bridge.wormhole();
WETH = _weth;
wormholeChainId = wormhole.chainId();
FEE_RECIPIENT = _feeRecipient;
}
function version() external pure returns (uint32) {
return 1;
}
///@notice config recipient for relayer fees
function setFeeRecipient(address newFeeRecipient) external onlyOwner {
FEE_RECIPIENT = newFeeRecipient;
}
///@notice if current approval is insufficient, approve max
///@notice oz safeIncreaseAllowance controls for tokens that require allowance to be reset to 0 before increasing again
function updateApproval(address spender, IERC20 token, uint256 amount) internal {
// get current allowance
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < amount) {
// amount is a delta, so need to pass max - current to avoid overflow
token.safeIncreaseAllowance(spender, type(uint256).max - (currentAllowance + 1));
}
}
}
abstract contract PorticoStart is PorticoBase {
using PorticoFlagSetAccess for PorticoFlagSet;
using SafeERC20 for IERC20;
function _start_v3swap(PorticoStructs.TradeParameters memory params, uint256 actualAmount) internal returns (uint256 amount) {
updateApproval(address(ROUTERV3), params.startTokenAddress, actualAmount);
ROUTERV3.exactInputSingle(
ISwapRouter02.ExactInputSingleParams(
address(params.startTokenAddress), //tokenIn
address(params.canonAssetAddress), //tokenOut
params.flags.feeTierStart(), //fee
address(this), //recipient
actualAmount, //amountIn
params.minAmountStart, //minAmountReceived
0
)
);
amount = params.canonAssetAddress.balanceOf(address(this));
}
event PorticoSwapStart(uint64 indexed sequence, uint16 indexed chainId);
function start(
PorticoStructs.TradeParameters memory params
) external payable nonReentrant returns (address emitterAddress, uint16 chainId, uint64 sequence) {
uint256 amount;
uint256 whMessageFee = wormhole.messageFee();
uint256 value = msg.value;
// always check for native wrapping logic
if (address(params.startTokenAddress) == address(WETH) && params.flags.shouldWrapNative()) {
// if wrapping, msg.value should be exactly amountSpecified + wormhole message fee
require(value == params.amountSpecified + whMessageFee, "msg.value incorrect");
// if we are wrapping a token, we call WETH.deposit for the user, assuming we have been sent what we need.
WETH.deposit{ value: params.amountSpecified }();
// because wormhole rounds to 1e8, some dust may exist from previous txs
// we use balanceOf to lump this in with future txs
amount = WETH.balanceOf(address(this));
} else {
// ensure no eth needs to be refunded
require(value == whMessageFee, "msg.value incorrect");
// otherwise, just get the token we need to do the swap (if we are swapping, or just the token itself)
params.startTokenAddress.safeTransferFrom(_msgSender(), address(this), params.amountSpecified);
// Because wormhole rounds to 1e8, some dust may exist from previous txs
// we use balanceOf to lump this in with future txs
amount = params.startTokenAddress.balanceOf(address(this));
}
// sanity check amount received
require(amount >= params.amountSpecified, "transfer insufficient");
// if the start token is the canon token, we don't need to swap
if (params.startTokenAddress != params.canonAssetAddress) {
// do the swap, and amount is now the amount that we received from the swap
amount = _start_v3swap(params, amount);
}
// allow the token bridge to do its token bridge things
updateApproval(address(TOKENBRIDGE), params.canonAssetAddress, amount);
// now we need to produce the payload we are sending
PorticoStructs.DecodedVAA memory decodedVAA = PorticoStructs.DecodedVAA(
params.flags,
params.finalTokenAddress,
params.recipientAddress,
amount,
params.minAmountFinish,
params.relayerFee
);
// send the actual transfer tx, and get the sequence
sequence = TOKENBRIDGE.transferTokensWithPayload{ value: whMessageFee }(
address(params.canonAssetAddress),
amount,
params.flags.recipientChain(),
padAddress(params.recipientPorticoAddress),
params.flags.bridgeNonce(),
abi.encode(decodedVAA)
);
// local chain id
chainId = wormholeChainId;
// emitter is the local tokenbridge
emitterAddress = address(TOKENBRIDGE);
// emit event
emit PorticoSwapStart(sequence, chainId);
}
///@notice @return addr in bytes32 format, as required by Wormhole
function padAddress(address addr) internal pure returns (bytes32) {
return bytes32(uint256(uint160(addr)));
}
}
abstract contract PorticoFinish is PorticoBase {
using PorticoFlagSetAccess for PorticoFlagSet;
using SafeERC20 for IERC20;
event PorticoSwapFinish(bool swapCompleted, uint256 finaluserAmount, uint256 relayerFeeAmount, PorticoStructs.DecodedVAA data);
// receiveMessageAndSwap is the entrypoint for finishing the swap
function receiveMessageAndSwap(bytes calldata encodedTransferMessage) external nonReentrant {
// start by calling _completeTransfer, submitting the VAA to the token bridge
(PorticoStructs.DecodedVAA memory message, PorticoStructs.BridgeInfo memory bridgeInfo) = _completeTransfer(encodedTransferMessage);
// we modify the message to set the relayerFee to 0 if the msgSender is the fee recipient
// this allows users to self-relay and not pay the fee, even if the fee was set to non-zero at tx origin
bridgeInfo.relayerFeeAmount = (_msgSender() == message.recipientAddress) ? 0 : message.relayerFee;
//now process
(bool swapCompleted, uint256 finalUserAmount) = finish(message, bridgeInfo);
// simply emit the raw data bytes. it should be trivial to parse.
emit PorticoSwapFinish(swapCompleted, finalUserAmount, bridgeInfo.relayerFeeAmount, message);
}
// _completeTransfer takes the vaa for a payload3 token transfer, redeems it with the token bridge, and returns the decoded vaa payload
function _completeTransfer(
bytes calldata encodedTransferMessage
) internal returns (PorticoStructs.DecodedVAA memory message, PorticoStructs.BridgeInfo memory bridgeInfo) {
/**
* Call `completeTransferWithPayload` on the token bridge. This
* method acts as a reentrancy protection since it does not allow
* transfers to be redeemed more than once.
*/
bytes memory transferPayload = TOKENBRIDGE.completeTransferWithPayload(encodedTransferMessage);
// parse the wormhole message payload into the `TransferWithPayload` struct, a payload3 token transfer
ITokenBridge.TransferWithPayload memory transfer = TOKENBRIDGE.parseTransferWithPayload(transferPayload);
// ensure that the to address is this address
require(unpadAddress(transfer.to) == address(this) && transfer.toChain == wormholeChainId, "Token not sent to this address");
// decode the payload3 we originally sent into the decodedVAA struct.
message = abi.decode(transfer.payload, (PorticoStructs.DecodedVAA));
// get the address for the token on this address.
bridgeInfo.tokenReceived = IERC20(
transfer.tokenChain == wormholeChainId
? unpadAddress(transfer.tokenAddress)
: TOKENBRIDGE.wrappedAsset(transfer.tokenChain, transfer.tokenAddress)
);
// put the transfer amount into amountReceived, knowing we may need to change it in a sec
bridgeInfo.amountReceived = transfer.amount;
// if there are more than 8 decimals, we need to denormalize. wormhole token bridge truncates tokens of more than 8 decimals to 8 decimals.
uint8 decimals = bridgeInfo.tokenReceived.decimals();
if (decimals > 8) {
bridgeInfo.amountReceived *= uint256(10) ** (decimals - 8);
}
}
///@notice determines we need to swap and/or unwrap, does those things if needed, and sends tokens to user & pays relayer fee
function finish(
PorticoStructs.DecodedVAA memory params,
PorticoStructs.BridgeInfo memory bridgeInfo
) internal returns (bool swapCompleted, uint256 finalUserAmount) {
// see if the unwrap flag is set, and that the finalTokenAddress is the address we have set on deploy as our native weth9 address
bool shouldUnwrap = params.flags.shouldUnwrapNative() && address(params.finalTokenAddress) == address(WETH);
if ((params.finalTokenAddress) == bridgeInfo.tokenReceived) {
// this means that we don't need to do a swap, aka, we received the canon asset.
finalUserAmount = payOut(shouldUnwrap, params.finalTokenAddress, params.recipientAddress, bridgeInfo.relayerFeeAmount);
return (false, finalUserAmount);
}
// if we are here, if means we need to do the swap, resulting aset from the swap is sent to this contract
swapCompleted = _finish_v3swap(params, bridgeInfo);
// if the swap fails, we just transfer the amount we received from the token bridge to the recipientAddress.
if (!swapCompleted) {
bridgeInfo.tokenReceived.transfer(params.recipientAddress, bridgeInfo.amountReceived);
// we also mark swapCompleted to be false for PorticoSwapFinish event
return (swapCompleted, bridgeInfo.amountReceived);
}
// we must call payout if the swap was completed
finalUserAmount = payOut(shouldUnwrap, params.finalTokenAddress, params.recipientAddress, bridgeInfo.relayerFeeAmount);
}
/**
* @notice perform the swap via Uniswap V3 Router
* if swap fails, we don't pay fees to the relayer
* the reason is because that typically, the swap fails because of bad market conditions
* in this case, it is in the best interest of the mev/relayer to NOT relay this message until conditions are good
* the user of course, who if they self relay, does not pay a fee, does not have this problem, so they can force this if they wish
* swap failed - return canon asset to recipient
* it will return true if the swap was completed, indicating that funds need to be sent from this contract to the recipient
*/
function _finish_v3swap(
PorticoStructs.DecodedVAA memory params,
PorticoStructs.BridgeInfo memory bridgeInfo
) internal returns (bool swapCompleted) {
// set swap options with params decoded from the payload
ISwapRouter02.ExactInputSingleParams memory swapParams = ISwapRouter02.ExactInputSingleParams({
tokenIn: address(bridgeInfo.tokenReceived),
tokenOut: address(params.finalTokenAddress),
fee: params.flags.feeTierFinish(),
recipient: address(this), // we need to receive the token in order to correctly split the fee. tragic.
amountIn: bridgeInfo.amountReceived,
amountOutMinimum: params.minAmountFinish,
sqrtPriceLimitX96: 0 //sqrtPriceLimit is not used
});
// update approval
updateApproval(address(ROUTERV3), bridgeInfo.tokenReceived, bridgeInfo.amountReceived);
// try the swap
try ROUTERV3.exactInputSingle(swapParams) {
swapCompleted = true;
} catch {}
}
///@notice pay out to user and relayer
///@notice this should always be called UNLESS swap fails, in which case payouts happen there
// NOTE if relayerFeeAmount is incorrectly scaled, then the end user may receive nothing, and all proceeds go to relayer
// it is incumbent upon the cross chain tx origin to ensure the relayerFeeAmount is passed correctly
function payOut(bool unwrap, IERC20 finalToken, address recipient, uint256 relayerFeeAmount) internal returns (uint256 finalUserAmount) {
uint256 totalBalance = finalToken.balanceOf(address(this));
// square up balances with what we actually have, don't trust reporting from the bridge
if (relayerFeeAmount > totalBalance) {
// control for underflow
finalUserAmount = 0;
relayerFeeAmount = totalBalance;
} else {
// user gets total - relayer fee
finalUserAmount = totalBalance - relayerFeeAmount;
}
// if feeRecipient is not set, then send fees to msg.sender
address feeRecipient = FEE_RECIPIENT == address(0x0) ? _msgSender() : FEE_RECIPIENT;
if (unwrap) {
WETH.withdraw(WETH.balanceOf(address(this)));
if (finalUserAmount > 0) {
// send to user
sendEther(recipient, finalUserAmount);
}
if (relayerFeeAmount > 0) {
// pay relayer fee
sendEther(feeRecipient, relayerFeeAmount);
}
} else {
// send to user
if (finalUserAmount > 0) {
finalToken.safeTransfer(recipient, finalUserAmount);
}
if (relayerFeeAmount > 0) {
// pay relayer fee
finalToken.safeTransfer(feeRecipient, relayerFeeAmount);
}
}
}
receive() external payable {}
///@dev https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/Utils.sol#L10-L15
function unpadAddress(bytes32 whFormatAddress) internal pure returns (address) {
if (uint256(whFormatAddress) >> 160 != 0) {
revert("Not EVM Addr");
}
return address(uint160(uint256(whFormatAddress)));
}
///@notice send ether without exposing to gas griefing attacks via returned bytes
function sendEther(address to, uint256 value) internal {
bool sent;
assembly {
sent := call(gas(), to, value, 0, 0, 0, 0)
}
if (!sent) {
revert("failed to send ether");
}
}
}
contract Portico is PorticoFinish, PorticoStart {
constructor(
ISwapRouter02 _routerV3,
ITokenBridge _bridge,
IWETH _weth,
address _feeRecipient
) PorticoBase(_routerV3, _bridge, _weth, _feeRecipient) {}
}// SPDX-License-Identifier: UNLICENSE
pragma solidity ^0.8.9;
interface IERC20 {
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool success);
function balanceOf(address account) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool success);
function decimals() external view returns (uint8);
function allowance(address owner, address spender) external view returns (uint256);
}// SPDX-License-Identifier: UNLICENSE
pragma solidity ^0.8.9;
import "./IWETH.sol";
import "./IWormhole.sol";
interface ITokenBridge {
struct Transfer {
uint8 payloadID;
uint256 amount;
bytes32 tokenAddress;
uint16 tokenChain;
bytes32 to;
uint16 toChain;
uint256 fee;
}
struct TransferWithPayload {
uint8 payloadID;
uint256 amount;
bytes32 tokenAddress;
uint16 tokenChain;
bytes32 to;
uint16 toChain;
bytes32 fromAddress;
bytes payload;
}
struct AssetMeta {
uint8 payloadID;
bytes32 tokenAddress;
uint16 tokenChain;
uint8 decimals;
bytes32 symbol;
bytes32 name;
}
struct RegisterChain {
bytes32 module;
uint8 action;
uint16 chainId;
uint16 emitterChainID;
bytes32 emitterAddress;
}
struct UpgradeContract {
bytes32 module;
uint8 action;
uint16 chainId;
bytes32 newContract;
}
struct RecoverChainId {
bytes32 module;
uint8 action;
uint256 evmChainId;
uint16 newChainId;
}
event ContractUpgraded(address indexed oldContract, address indexed newContract);
event TransferRedeemed(uint16 indexed emitterChainId, bytes32 indexed emitterAddress, uint64 indexed sequence);
function _parseTransferCommon(bytes memory encoded) external pure returns (Transfer memory transfer);
function attestToken(address tokenAddress, uint32 nonce) external payable returns (uint64 sequence);
function wrapAndTransferETH(uint16 recipientChain, bytes32 recipient, uint256 arbiterFee, uint32 nonce) external payable returns (uint64 sequence);
function wrapAndTransferETHWithPayload(uint16 recipientChain, bytes32 recipient, uint32 nonce, bytes memory payload) external payable returns (uint64 sequence);
function transferTokens(address token, uint256 amount, uint16 recipientChain, bytes32 recipient, uint256 arbiterFee, uint32 nonce) external payable returns (uint64 sequence);
function transferTokensWithPayload(address token, uint256 amount, uint16 recipientChain, bytes32 recipient, uint32 nonce, bytes memory payload) external payable returns (uint64 sequence);
function updateWrapped(bytes memory encodedVm) external returns (address token);
function createWrapped(bytes memory encodedVm) external returns (address token);
function completeTransferWithPayload(bytes memory encodedVm) external returns (bytes memory);
function completeTransferAndUnwrapETHWithPayload(bytes memory encodedVm) external returns (bytes memory);
function completeTransfer(bytes memory encodedVm) external;
function completeTransferAndUnwrapETH(bytes memory encodedVm) external;
function encodeAssetMeta(AssetMeta memory meta) external pure returns (bytes memory encoded);
function encodeTransfer(Transfer memory transfer) external pure returns (bytes memory encoded);
function encodeTransferWithPayload(TransferWithPayload memory transfer) external pure returns (bytes memory encoded);
function parsePayloadID(bytes memory encoded) external pure returns (uint8 payloadID);
function parseAssetMeta(bytes memory encoded) external pure returns (AssetMeta memory meta);
function parseTransfer(bytes memory encoded) external pure returns (Transfer memory transfer);
function parseTransferWithPayload(bytes memory encoded) external pure returns (TransferWithPayload memory transfer);
function governanceActionIsConsumed(bytes32 hash) external view returns (bool);
function isInitialized(address impl) external view returns (bool);
function isTransferCompleted(bytes32 hash) external view returns (bool);
function wormhole() external view returns (IWormhole);
function chainId() external view returns (uint16);
function evmChainId() external view returns (uint256);
function isFork() external view returns (bool);
function governanceChainId() external view returns (uint16);
function governanceContract() external view returns (bytes32);
function wrappedAsset(uint16 tokenChainId, bytes32 tokenAddress) external view returns (address);
function bridgeContracts(uint16 chainId_) external view returns (bytes32);
function tokenImplementation() external view returns (address);
function WETH() external view returns (IWETH);
function outstandingBridged(address token) external view returns (uint256);
function isWrappedAsset(address token) external view returns (bool);
function finality() external view returns (uint8);
function implementation() external view returns (address);
function initialize() external;
function registerChain(bytes memory encodedVM) external;
function upgrade(bytes memory encodedVM) external;
function submitRecoverChainId(bytes memory encodedVM) external;
function parseRegisterChain(bytes memory encoded) external pure returns (RegisterChain memory chain);
function parseUpgrade(bytes memory encoded) external pure returns (UpgradeContract memory chain);
function parseRecoverChainId(bytes memory encodedRecoverChainId) external pure returns (RecoverChainId memory rci);
}// SPDX-License-Identifier: UNLICENSE
pragma solidity ^0.8.9;
import "./IERC20.sol";
interface IWETH is IERC20{
function deposit() external payable;
function transfer(address to, uint value) external returns (bool);
function withdraw(uint) external;
}// SPDX-License-Identifier: UNLICENSE
pragma solidity ^0.8.9;
interface IWormhole {
struct GuardianSet {
address[] keys;
uint32 expirationTime;
}
struct Signature {
bytes32 r;
bytes32 s;
uint8 v;
uint8 guardianIndex;
}
/**
struct Signature {
uint8 index;
bytes signature;
string name;
}
*/
struct VM {
uint8 version;
uint32 timestamp;
uint32 nonce;
uint16 emitterChainId;
bytes32 emitterAddress;
uint64 sequence;
uint8 consistencyLevel;
bytes payload;
uint32 guardianSetIndex;
Signature[] signatures;
bytes32 hash;
}
struct ContractUpgrade {
bytes32 module;
uint8 action;
uint16 chain;
address newContract;
}
struct GuardianSetUpgrade {
bytes32 module;
uint8 action;
uint16 chain;
GuardianSet newGuardianSet;
uint32 newGuardianSetIndex;
}
struct SetMessageFee {
bytes32 module;
uint8 action;
uint16 chain;
uint256 messageFee;
}
struct TransferFees {
bytes32 module;
uint8 action;
uint16 chain;
uint256 amount;
bytes32 recipient;
}
struct RecoverChainId {
bytes32 module;
uint8 action;
uint256 evmChainId;
uint16 newChainId;
}
event LogMessagePublished(address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel);
event ContractUpgraded(address indexed oldContract, address indexed newContract);
event GuardianSetAdded(uint32 indexed index);
function publishMessage(uint32 nonce, bytes memory payload, uint8 consistencyLevel) external payable returns (uint64 sequence);
function testSigs() external returns (Signature[] memory signatures);
function test8() external returns (uint8 test);
function testBytes() external returns (bytes memory payload);
function testBigKahuna() external returns (VM memory vm);
function initialize() external;
function parseAndVerifyVM(bytes calldata encodedVM) external view returns (VM memory vm, bool valid, string memory reason);
function verifyVM(VM memory vm) external view returns (bool valid, string memory reason);
function verifySignatures(
bytes32 hash,
Signature[] memory signatures,
GuardianSet memory guardianSet
) external pure returns (bool valid, string memory reason);
function parseVM(bytes memory encodedVM) external pure returns (VM memory vm);
function quorum(uint numGuardians) external pure returns (uint numSignaturesRequiredForQuorum);
function getGuardianSet(uint32 index) external view returns (GuardianSet memory);
function getCurrentGuardianSetIndex() external view returns (uint32);
function getGuardianSetExpiry() external view returns (uint32);
function governanceActionIsConsumed(bytes32 hash) external view returns (bool);
function isInitialized(address impl) external view returns (bool);
function chainId() external view returns (uint16);
function isFork() external view returns (bool);
function governanceChainId() external view returns (uint16);
function governanceContract() external view returns (bytes32);
function messageFee() external view returns (uint256);
function evmChainId() external view returns (uint256);
function nextSequence(address emitter) external view returns (uint64);
function parseContractUpgrade(bytes memory encodedUpgrade) external pure returns (ContractUpgrade memory cu);
function parseGuardianSetUpgrade(bytes memory encodedUpgrade) external pure returns (GuardianSetUpgrade memory gsu);
function parseSetMessageFee(bytes memory encodedSetMessageFee) external pure returns (SetMessageFee memory smf);
function parseTransferFees(bytes memory encodedTransferFees) external pure returns (TransferFees memory tf);
function parseRecoverChainId(bytes memory encodedRecoverChainId) external pure returns (RecoverChainId memory rci);
function submitContractUpgrade(bytes memory _vm) external;
function submitSetMessageFee(bytes memory _vm) external;
function submitNewGuardianSet(bytes memory _vm) external;
function submitTransferFees(bytes memory _vm) external;
function submitRecoverChainId(bytes memory _vm) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC-20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "./Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "./IERC20Permit.sol";
import {Address} from "./Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: UNLICENSE
pragma solidity ^0.8.9;
import "./IERC20.sol";
type PorticoFlagSet is bytes32;
library PorticoFlagSetAccess {
// the portico uses one word (32 bytes) to represent a large amount of variables
// bytes 0-1 is the recipient chain
function recipientChain(PorticoFlagSet flagset) internal pure returns (uint16 ans) {
assembly {
ans := add(byte(0, flagset), shl(8, byte(1, flagset)))
}
}
// bytes 2-5 is the bridge nonce
function bridgeNonce(PorticoFlagSet flagset) internal pure returns (uint32 ans) {
assembly {
ans := add(add(add(byte(2, flagset), shl(8, byte(3, flagset))), shl(16, byte(4, flagset))), shl(24, byte(5, flagset)))
}
}
// bytes 6,7,8 is the fee tier for start path
function feeTierStart(PorticoFlagSet flagset) internal pure returns (uint24 ans) {
assembly {
ans := add(add(byte(6, flagset), shl(8, byte(7, flagset))), shl(16, byte(8, flagset)))
}
}
// bytes 9,10,11 is the fee tier for finish path
function feeTierFinish(PorticoFlagSet flagset) internal pure returns (uint24 ans) {
assembly {
ans := add(add(byte(9, flagset), shl(8, byte(10, flagset))), shl(16, byte(11, flagset)))
}
}
// shouldWrapNative is the first bit of the byte 31
function shouldWrapNative(PorticoFlagSet flagset) internal pure returns (bool) {
bytes32 fs = PorticoFlagSet.unwrap(flagset);
return uint8(fs[31]) & (1 << 0) > 0;
}
// shouldUnwrapNative is the second bit of byte 31
function shouldUnwrapNative(PorticoFlagSet flagset) internal pure returns (bool) {
bytes32 fs = PorticoFlagSet.unwrap(flagset);
return uint8(fs[31]) & (1 << 1) > 0;
}
}
library PorticoStructs {
//https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayerSDK.sol#L177
//https://docs.wormhole.com/wormhole/quick-start/tutorials/hello-token#receiving-a-token
struct TokenReceived {
bytes32 tokenHomeAddress;
uint16 tokenHomeChain;
IERC20 tokenAddress;
uint256 amount;
}
//268,090 - to beat
struct TradeParameters {
PorticoFlagSet flags;
IERC20 startTokenAddress;
IERC20 canonAssetAddress;
IERC20 finalTokenAddress;
// address of the recipient on the recipientChain
address recipientAddress;
// address of the portico on the recipient chain
address recipientPorticoAddress;
// the amount of the token that the person wishes to transfer
uint256 amountSpecified;
uint256 minAmountStart;
uint256 minAmountFinish;
uint256 relayerFee; // the amount of tokens of the recipient to give to the relayer
}
//268,041 158,788
struct DecodedVAA {
PorticoFlagSet flags;
IERC20 finalTokenAddress;
// the person to receive the token
address recipientAddress;
// the x asset amount expected to be received
uint256 canonAssetAmount;
uint256 minAmountFinish;
uint256 relayerFee;
}
struct BridgeInfo {
IERC20 tokenReceived;
uint256 amountReceived;
uint256 relayerFeeAmount;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;
/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter02 {
function factory() external view returns (address);
//frusturatingly, there is no deadline in this set of params
//used on SwapRouter02 on Base chain
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another token
/// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance,
/// and swap the entire amount, enabling contracts to send tokens before calling this function.
/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
}{
"optimizer": {
"enabled": true,
"runs": 200,
"details": {
"orderLiterals": true,
"deduplicate": true,
"cse": true,
"yul": true
}
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract ISwapRouter02","name":"_routerV3","type":"address"},{"internalType":"contract ITokenBridge","name":"_bridge","type":"address"},{"internalType":"contract IWETH","name":"_weth","type":"address"},{"internalType":"address","name":"_feeRecipient","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"swapCompleted","type":"bool"},{"indexed":false,"internalType":"uint256","name":"finaluserAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"relayerFeeAmount","type":"uint256"},{"components":[{"internalType":"PorticoFlagSet","name":"flags","type":"bytes32"},{"internalType":"contract IERC20","name":"finalTokenAddress","type":"address"},{"internalType":"address","name":"recipientAddress","type":"address"},{"internalType":"uint256","name":"canonAssetAmount","type":"uint256"},{"internalType":"uint256","name":"minAmountFinish","type":"uint256"},{"internalType":"uint256","name":"relayerFee","type":"uint256"}],"indexed":false,"internalType":"struct PorticoStructs.DecodedVAA","name":"data","type":"tuple"}],"name":"PorticoSwapFinish","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"sequence","type":"uint64"},{"indexed":true,"internalType":"uint16","name":"chainId","type":"uint16"}],"name":"PorticoSwapStart","type":"event"},{"inputs":[],"name":"FEE_RECIPIENT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROUTERV3","outputs":[{"internalType":"contract ISwapRouter02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKENBRIDGE","outputs":[{"internalType":"contract ITokenBridge","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTransferMessage","type":"bytes"}],"name":"receiveMessageAndSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFeeRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"PorticoFlagSet","name":"flags","type":"bytes32"},{"internalType":"contract IERC20","name":"startTokenAddress","type":"address"},{"internalType":"contract IERC20","name":"canonAssetAddress","type":"address"},{"internalType":"contract IERC20","name":"finalTokenAddress","type":"address"},{"internalType":"address","name":"recipientAddress","type":"address"},{"internalType":"address","name":"recipientPorticoAddress","type":"address"},{"internalType":"uint256","name":"amountSpecified","type":"uint256"},{"internalType":"uint256","name":"minAmountStart","type":"uint256"},{"internalType":"uint256","name":"minAmountFinish","type":"uint256"},{"internalType":"uint256","name":"relayerFee","type":"uint256"}],"internalType":"struct PorticoStructs.TradeParameters","name":"params","type":"tuple"}],"name":"start","outputs":[{"internalType":"address","name":"emitterAddress","type":"address"},{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"uint64","name":"sequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"wormhole","outputs":[{"internalType":"contract IWormhole","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wormholeChainId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
6101206040523480156200001257600080fd5b50604051620025b6380380620025b68339810160408190526200003591620001fe565b8383838333806200006057604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200006b8162000195565b50600180556001600160a01b03808516608052831660a0819052604080516384acd1bb60e01b815290516384acd1bb916004808201926020929091908290030181865afa158015620000c1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000e7919062000266565b6001600160a01b0390811660e081905290831660c05260408051634d4502c960e11b81529051639a8a0592916004808201926020929091908290030181865afa15801562000139573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200015f91906200028d565b61ffff1661010052600280546001600160a01b0319166001600160a01b039290921691909117905550620002b395505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0381168114620001fb57600080fd5b50565b600080600080608085870312156200021557600080fd5b84516200022281620001e5565b60208601519094506200023581620001e5565b60408601519093506200024881620001e5565b60608601519092506200025b81620001e5565b939692955090935050565b6000602082840312156200027957600080fd5b81516200028681620001e5565b9392505050565b600060208284031215620002a057600080fd5b815161ffff811681146200028657600080fd5b60805160a05160c05160e0516101005161223a6200037c600039600081816101bc0152818161090901528181610bd00152610c6601526000818161020301526103f301526000818161029a0152818161047c01528181610522015281816105aa01528181610e1a01526113cc01526000818160e40152818161077d015281816108020152818161092c01528181610a9101528181610b150152610cc00152600081816101730152818161104c015281816110780152818161159601526115db015261223a6000f3fe6080604052600436106100c65760003560e01c806384acd1bb1161007f578063ad5c464811610059578063ad5c464814610288578063e74b981b146102bc578063ebd09054146102dc578063f2fde38b146102fc57600080fd5b806384acd1bb146101f15780638da5cb5b146102255780639a4896fe1461024357600080fd5b806315a3d8f5146100d25780633d528f351461012357806354fd4d50146101455780635e3caf6914610161578063715018a614610195578063793e64e3146101aa57600080fd5b366100cd57005b600080fd5b3480156100de57600080fd5b506101067f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561012f57600080fd5b5061014361013e366004611a40565b61031c565b005b34801561015157600080fd5b506040516001815260200161011a565b34801561016d57600080fd5b506101067f000000000000000000000000000000000000000000000000000000000000000081565b3480156101a157600080fd5b506101436103cd565b3480156101b657600080fd5b506101de7f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff909116815260200161011a565b3480156101fd57600080fd5b506101067f000000000000000000000000000000000000000000000000000000000000000081565b34801561023157600080fd5b506000546001600160a01b0316610106565b610256610251366004611b3b565b6103e1565b604080516001600160a01b03909416845261ffff909216602084015267ffffffffffffffff169082015260600161011a565b34801561029457600080fd5b506101067f000000000000000000000000000000000000000000000000000000000000000081565b3480156102c857600080fd5b506101436102d7366004611be2565b61099d565b3480156102e857600080fd5b50600254610106906001600160a01b031681565b34801561030857600080fd5b50610143610317366004611be2565b6109c7565b610324610a05565b6000806103318484610a2f565b9150915081604001516001600160a01b031661034a3390565b6001600160a01b031614610362578160a00151610365565b60005b60408201526000806103778484610dfc565b915091507fc2addcb063016f6dc1647fc8cd7206c3436cc4293c4acffe4feac288459ca7fc82828560400151876040516103b49493929190611c47565b60405180910390a1505050506103c960018055565b5050565b6103d5610f5b565b6103df6000610f88565b565b60008060006103ee610a05565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631a90a2196040518163ffffffff1660e01b8152600401602060405180830381865afa15801561044f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104739190611c6c565b905060003490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687602001516001600160a01b03161480156104c25750865160011615155b1561062857818760c001516104d79190611c9b565b81146105205760405162461bcd60e51b81526020600482015260136024820152721b5cd9cb9d985b1d59481a5b98dbdc9c9958dd606a1b60448201526064015b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db08860c001516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561057f57600080fd5b505af1158015610593573d6000803e3d6000fd5b50506040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031693506370a0823192506024019050602060405180830381865afa1580156105fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106219190611c6c565b92506106fe565b81811461066d5760405162461bcd60e51b81526020600482015260136024820152721b5cd9cb9d985b1d59481a5b98dbdc9c9958dd606a1b6044820152606401610517565b61068d3360c089015160208a01516001600160a01b031691903090610fd8565b60208701516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156106d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106fb9190611c6c565b92505b8660c0015183101561074a5760405162461bcd60e51b81526020600482015260156024820152741d1c985b9cd9995c881a5b9cdd59999a58da595b9d605a1b6044820152606401610517565b86604001516001600160a01b031687602001516001600160a01b031614610778576107758784611045565b92505b6107a77f0000000000000000000000000000000000000000000000000000000000000000886040015185611207565b60006040518060c001604052808960000151815260200189606001516001600160a01b0316815260200189608001516001600160a01b03168152602001858152602001896101000151815260200189610120015181525090507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c5a5ebda848a60400151876108508d60000151600081901a60019190911a60081b0190565b60a08e01516001600160a01b03168e51600281901a600382901a60081b01600482901a60101b0160059190911a60181b01886040516020016108929190611cae565b6040516020818303038152906040526040518863ffffffff1660e01b81526004016108c296959493929190611d0c565b60206040518083038185885af11580156108e0573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906109059190611d5b565b94507f000000000000000000000000000000000000000000000000000000000000000095507f000000000000000000000000000000000000000000000000000000000000000096508561ffff168567ffffffffffffffff167f29bbdeaf59aab4b88cf0ec8a729f885d1b957311a49de002e7db6620e390467060405160405180910390a35050505061099660018055565b9193909250565b6109a5610f5b565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6109cf610f5b565b6001600160a01b0381166109f957604051631e4fbdf760e01b815260006004820152602401610517565b610a0281610f88565b50565b600260015403610a2857604051633ee5aeb560e01b815260040160405180910390fd5b6002600155565b6040805160c0810182526000808252602080830182905282840182905260608084018390526080840183905260a0840183905284519081018552828152908101829052928301529060405163c3f511c160e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c3f511c190610ac89088908890600401611d85565b6000604051808303816000875af1158015610ae7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b0f9190810190611e32565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ea63738d836040518263ffffffff1660e01b8152600401610b5f9190611e6f565b600060405180830381865afa158015610b7c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ba49190810190611ea5565b9050306001600160a01b0316610bbd82608001516112b1565b6001600160a01b0316148015610bfe57507f000000000000000000000000000000000000000000000000000000000000000061ffff168160a0015161ffff16145b610c4a5760405162461bcd60e51b815260206004820152601e60248201527f546f6b656e206e6f742073656e7420746f2074686973206164647265737300006044820152606401610517565b8060e00151806020019051810190610c629190611f6e565b93507f000000000000000000000000000000000000000000000000000000000000000061ffff16816060015161ffff1614610d385760608101516040808301519051630ff8f14360e11b815261ffff909216600483015260248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631ff1e28690604401602060405180830381865afa158015610d0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d339190611ffa565b610d45565b610d4581604001516112b1565b6001600160a01b0316808452602080830151818601526040805163313ce56760e01b815290516000939263313ce56792600480820193918290030181865afa158015610d95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db99190612017565b905060088160ff161115610df257610dd2600882612032565b610ddd90600a61212f565b84602001818151610dee919061213e565b9052505b5050509250929050565b6000806000610e118560000151600216151590565b8015610e5257507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031685602001516001600160a01b0316145b905083600001516001600160a01b031685602001516001600160a01b031603610e9957610e8d818660200151876040015187604001516112f8565b91506000925050610f54565b610ea385856114fd565b925082610f385783516040868101516020870151915163a9059cbb60e01b81526001600160a01b03918216600482015260248101929092529091169063a9059cbb906044016020604051808303816000875af1158015610f07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2b9190612155565b5050506020820151610f54565b610f50818660200151876040015187604001516112f8565b9150505b9250929050565b6000546001600160a01b031633146103df5760405163118cdaa760e01b8152336004820152602401610517565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040516001600160a01b03848116602483015283811660448301526064820183905261103f9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505061165d565b50505050565b60006110767f0000000000000000000000000000000000000000000000000000000000000000846020015184611207565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166304e45aaf6040518060e0016040528086602001516001600160a01b0316815260200186604001516001600160a01b031681526020016110fb876000015160008160081a60101b8260071a60081b8360061a01019050919050565b62ffffff168152602001306001600160a01b031681526020018581526020018660e00151815260200160006001600160a01b03168152506040518263ffffffff1660e01b815260040161114e9190612177565b6020604051808303816000875af115801561116d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111919190611c6c565b5060408084015190516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156111dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112009190611c6c565b9392505050565b604051636eb1769f60e11b81523060048201526001600160a01b0384811660248301526000919084169063dd62ed3e90604401602060405180830381865afa158015611257573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127b9190611c6c565b90508181101561103f5761103f84611294836001611c9b565b6112a0906000196121d5565b6001600160a01b03861691906116c5565b600060a082901c156112f45760405162461bcd60e51b815260206004820152600c60248201526b2737ba1022ab269020b2323960a11b6044820152606401610517565b5090565b6040516370a0823160e01b815230600482015260009081906001600160a01b038616906370a0823190602401602060405180830381865afa158015611341573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113659190611c6c565b90508083111561137b5760009150809250611388565b61138583826121d5565b91505b6002546000906001600160a01b0316156113ad576002546001600160a01b03166113af565b335b905086156114bf576040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d9082906370a0823190602401602060405180830381865afa158015611423573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114479190611c6c565b6040518263ffffffff1660e01b815260040161146591815260200190565b600060405180830381600087803b15801561147f57600080fd5b505af1158015611493573d6000803e3d6000fd5b5050505060008311156114aa576114aa858461174f565b83156114ba576114ba818561174f565b6114f3565b82156114d9576114d96001600160a01b03871686856117a1565b83156114f3576114f36001600160a01b03871682866117a1565b5050949350505050565b6000806040518060e0016040528084600001516001600160a01b0316815260200185602001516001600160a01b031681526020016115548660000151600981901a600a82901a60081b01600b9190911a60101b0190565b62ffffff168152602001306001600160a01b03168152602001846020015181526020018560800151815260200160006001600160a01b031681525090506115c47f000000000000000000000000000000000000000000000000000000000000000084600001518560200151611207565b6040516304e45aaf60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906304e45aaf90611610908490600401612177565b6020604051808303816000875af192505050801561164b575060408051601f3d908101601f1916820190925261164891810190611c6c565b60015b156116565750600191505b5092915050565b60006116726001600160a01b038416836117d2565b905080516000141580156116975750808060200190518101906116959190612155565b155b156116c057604051635274afe760e01b81526001600160a01b0384166004820152602401610517565b505050565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015611715573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117399190611c6c565b905061103f848461174a8585611c9b565b6117e6565b600080600080600085875af19050806116c05760405162461bcd60e51b81526020600482015260146024820152733330b4b632b2103a379039b2b7321032ba3432b960611b6044820152606401610517565b6040516001600160a01b038381166024830152604482018390526116c091859182169063a9059cbb9060640161100d565b606061120083836000611876565b92915050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526118378482611913565b61103f576040516001600160a01b0384811660248301526000604483015261186c91869182169063095ea7b39060640161100d565b61103f848261165d565b60608147101561189b5760405163cd78605960e01b8152306004820152602401610517565b600080856001600160a01b031684866040516118b791906121e8565b60006040518083038185875af1925050503d80600081146118f4576040519150601f19603f3d011682016040523d82523d6000602084013e6118f9565b606091505b50915091506119098683836119bb565b9695505050505050565b6000806000846001600160a01b03168460405161193091906121e8565b6000604051808303816000865af19150503d806000811461196d576040519150601f19603f3d011682016040523d82523d6000602084013e611972565b606091505b509150915081801561199c57508051158061199c57508080602001905181019061199c9190612155565b80156119b257506000856001600160a01b03163b115b95945050505050565b6060826119d0576119cb82611a17565b611200565b81511580156119e757506001600160a01b0384163b155b15611a1057604051639996b31560e01b81526001600160a01b0385166004820152602401610517565b5080611200565b805115611a275780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60008060208385031215611a5357600080fd5b823567ffffffffffffffff80821115611a6b57600080fd5b818501915085601f830112611a7f57600080fd5b813581811115611a8e57600080fd5b866020828501011115611aa057600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052604160045260246000fd5b604051610140810167ffffffffffffffff81118282101715611aec57611aec611ab2565b60405290565b604051610100810167ffffffffffffffff81118282101715611aec57611aec611ab2565b6001600160a01b0381168114610a0257600080fd5b8035611b3681611b16565b919050565b60006101408284031215611b4e57600080fd5b611b56611ac8565b82358152611b6660208401611b2b565b6020820152611b7760408401611b2b565b6040820152611b8860608401611b2b565b6060820152611b9960808401611b2b565b6080820152611baa60a08401611b2b565b60a082015260c0838101359082015260e080840135908201526101008084013590820152610120928301359281019290925250919050565b600060208284031215611bf457600080fd5b813561120081611b16565b80518252602081015160018060a01b0380821660208501528060408401511660408501525050606081015160608301526080810151608083015260a081015160a08301525050565b8415158152602081018490526040810183905261012081016119b26060830184611bff565b600060208284031215611c7e57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156117e0576117e0611c85565b60c081016117e08284611bff565b60005b83811015611cd7578181015183820152602001611cbf565b50506000910152565b60008151808452611cf8816020860160208601611cbc565b601f01601f19169290920160200192915050565b60018060a01b038716815285602082015261ffff8516604082015283606082015263ffffffff8316608082015260c060a08201526000611d4f60c0830184611ce0565b98975050505050505050565b600060208284031215611d6d57600080fd5b815167ffffffffffffffff8116811461120057600080fd5b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b600082601f830112611dc557600080fd5b815167ffffffffffffffff80821115611de057611de0611ab2565b604051601f8301601f19908116603f01168101908282118183101715611e0857611e08611ab2565b81604052838152866020858801011115611e2157600080fd5b611909846020830160208901611cbc565b600060208284031215611e4457600080fd5b815167ffffffffffffffff811115611e5b57600080fd5b611e6784828501611db4565b949350505050565b6020815260006112006020830184611ce0565b805160ff81168114611b3657600080fd5b805161ffff81168114611b3657600080fd5b600060208284031215611eb757600080fd5b815167ffffffffffffffff80821115611ecf57600080fd5b908301906101008286031215611ee457600080fd5b611eec611af2565b611ef583611e82565b81526020830151602082015260408301516040820152611f1760608401611e93565b606082015260808301516080820152611f3260a08401611e93565b60a082015260c083015160c082015260e083015182811115611f5357600080fd5b611f5f87828601611db4565b60e08301525095945050505050565b600060c08284031215611f8057600080fd5b60405160c0810181811067ffffffffffffffff82111715611fa357611fa3611ab2565b604052825181526020830151611fb881611b16565b60208201526040830151611fcb81611b16565b80604083015250606083015160608201526080830151608082015260a083015160a08201528091505092915050565b60006020828403121561200c57600080fd5b815161120081611b16565b60006020828403121561202957600080fd5b61120082611e82565b60ff82811682821603908111156117e0576117e0611c85565b600181815b8085111561208657816000190482111561206c5761206c611c85565b8085161561207957918102915b93841c9390800290612050565b509250929050565b60008261209d575060016117e0565b816120aa575060006117e0565b81600181146120c057600281146120ca576120e6565b60019150506117e0565b60ff8411156120db576120db611c85565b50506001821b6117e0565b5060208310610133831016604e8410600b8410161715612109575081810a6117e0565b612113838361204b565b806000190482111561212757612127611c85565b029392505050565b600061120060ff84168361208e565b80820281158282048414176117e0576117e0611c85565b60006020828403121561216757600080fd5b8151801515811461120057600080fd5b81516001600160a01b03908116825260208084015182169083015260408084015162ffffff16908301526060808401518216908301526080808401519083015260a0838101519083015260c092830151169181019190915260e00190565b818103818111156117e0576117e0611c85565b600082516121fa818460208701611cbc565b919091019291505056fea2646970667358221220f3bd59e6cb6a3eb18a2cdad6abde82fa285014e470f0d2d7b8ccbad0f6fba6c664736f6c6343000814003300000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc450000000000000000000000000b2402144bb366a632d14b83f244d2e0e21bd39c00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab10000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106100c65760003560e01c806384acd1bb1161007f578063ad5c464811610059578063ad5c464814610288578063e74b981b146102bc578063ebd09054146102dc578063f2fde38b146102fc57600080fd5b806384acd1bb146101f15780638da5cb5b146102255780639a4896fe1461024357600080fd5b806315a3d8f5146100d25780633d528f351461012357806354fd4d50146101455780635e3caf6914610161578063715018a614610195578063793e64e3146101aa57600080fd5b366100cd57005b600080fd5b3480156100de57600080fd5b506101067f0000000000000000000000000b2402144bb366a632d14b83f244d2e0e21bd39c81565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561012f57600080fd5b5061014361013e366004611a40565b61031c565b005b34801561015157600080fd5b506040516001815260200161011a565b34801561016d57600080fd5b506101067f00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc4581565b3480156101a157600080fd5b506101436103cd565b3480156101b657600080fd5b506101de7f000000000000000000000000000000000000000000000000000000000000001781565b60405161ffff909116815260200161011a565b3480156101fd57600080fd5b506101067f000000000000000000000000a5f208e072434bc67592e4c49c1b991ba79bca4681565b34801561023157600080fd5b506000546001600160a01b0316610106565b610256610251366004611b3b565b6103e1565b604080516001600160a01b03909416845261ffff909216602084015267ffffffffffffffff169082015260600161011a565b34801561029457600080fd5b506101067f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab181565b3480156102c857600080fd5b506101436102d7366004611be2565b61099d565b3480156102e857600080fd5b50600254610106906001600160a01b031681565b34801561030857600080fd5b50610143610317366004611be2565b6109c7565b610324610a05565b6000806103318484610a2f565b9150915081604001516001600160a01b031661034a3390565b6001600160a01b031614610362578160a00151610365565b60005b60408201526000806103778484610dfc565b915091507fc2addcb063016f6dc1647fc8cd7206c3436cc4293c4acffe4feac288459ca7fc82828560400151876040516103b49493929190611c47565b60405180910390a1505050506103c960018055565b5050565b6103d5610f5b565b6103df6000610f88565b565b60008060006103ee610a05565b6000807f000000000000000000000000a5f208e072434bc67592e4c49c1b991ba79bca466001600160a01b0316631a90a2196040518163ffffffff1660e01b8152600401602060405180830381865afa15801561044f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104739190611c6c565b905060003490507f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b031687602001516001600160a01b03161480156104c25750865160011615155b1561062857818760c001516104d79190611c9b565b81146105205760405162461bcd60e51b81526020600482015260136024820152721b5cd9cb9d985b1d59481a5b98dbdc9c9958dd606a1b60448201526064015b60405180910390fd5b7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b031663d0e30db08860c001516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561057f57600080fd5b505af1158015610593573d6000803e3d6000fd5b50506040516370a0823160e01b81523060048201527f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b031693506370a0823192506024019050602060405180830381865afa1580156105fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106219190611c6c565b92506106fe565b81811461066d5760405162461bcd60e51b81526020600482015260136024820152721b5cd9cb9d985b1d59481a5b98dbdc9c9958dd606a1b6044820152606401610517565b61068d3360c089015160208a01516001600160a01b031691903090610fd8565b60208701516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156106d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106fb9190611c6c565b92505b8660c0015183101561074a5760405162461bcd60e51b81526020600482015260156024820152741d1c985b9cd9995c881a5b9cdd59999a58da595b9d605a1b6044820152606401610517565b86604001516001600160a01b031687602001516001600160a01b031614610778576107758784611045565b92505b6107a77f0000000000000000000000000b2402144bb366a632d14b83f244d2e0e21bd39c886040015185611207565b60006040518060c001604052808960000151815260200189606001516001600160a01b0316815260200189608001516001600160a01b03168152602001858152602001896101000151815260200189610120015181525090507f0000000000000000000000000b2402144bb366a632d14b83f244d2e0e21bd39c6001600160a01b031663c5a5ebda848a60400151876108508d60000151600081901a60019190911a60081b0190565b60a08e01516001600160a01b03168e51600281901a600382901a60081b01600482901a60101b0160059190911a60181b01886040516020016108929190611cae565b6040516020818303038152906040526040518863ffffffff1660e01b81526004016108c296959493929190611d0c565b60206040518083038185885af11580156108e0573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906109059190611d5b565b94507f000000000000000000000000000000000000000000000000000000000000001795507f0000000000000000000000000b2402144bb366a632d14b83f244d2e0e21bd39c96508561ffff168567ffffffffffffffff167f29bbdeaf59aab4b88cf0ec8a729f885d1b957311a49de002e7db6620e390467060405160405180910390a35050505061099660018055565b9193909250565b6109a5610f5b565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6109cf610f5b565b6001600160a01b0381166109f957604051631e4fbdf760e01b815260006004820152602401610517565b610a0281610f88565b50565b600260015403610a2857604051633ee5aeb560e01b815260040160405180910390fd5b6002600155565b6040805160c0810182526000808252602080830182905282840182905260608084018390526080840183905260a0840183905284519081018552828152908101829052928301529060405163c3f511c160e01b81526000906001600160a01b037f0000000000000000000000000b2402144bb366a632d14b83f244d2e0e21bd39c169063c3f511c190610ac89088908890600401611d85565b6000604051808303816000875af1158015610ae7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b0f9190810190611e32565b905060007f0000000000000000000000000b2402144bb366a632d14b83f244d2e0e21bd39c6001600160a01b031663ea63738d836040518263ffffffff1660e01b8152600401610b5f9190611e6f565b600060405180830381865afa158015610b7c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ba49190810190611ea5565b9050306001600160a01b0316610bbd82608001516112b1565b6001600160a01b0316148015610bfe57507f000000000000000000000000000000000000000000000000000000000000001761ffff168160a0015161ffff16145b610c4a5760405162461bcd60e51b815260206004820152601e60248201527f546f6b656e206e6f742073656e7420746f2074686973206164647265737300006044820152606401610517565b8060e00151806020019051810190610c629190611f6e565b93507f000000000000000000000000000000000000000000000000000000000000001761ffff16816060015161ffff1614610d385760608101516040808301519051630ff8f14360e11b815261ffff909216600483015260248201527f0000000000000000000000000b2402144bb366a632d14b83f244d2e0e21bd39c6001600160a01b031690631ff1e28690604401602060405180830381865afa158015610d0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d339190611ffa565b610d45565b610d4581604001516112b1565b6001600160a01b0316808452602080830151818601526040805163313ce56760e01b815290516000939263313ce56792600480820193918290030181865afa158015610d95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db99190612017565b905060088160ff161115610df257610dd2600882612032565b610ddd90600a61212f565b84602001818151610dee919061213e565b9052505b5050509250929050565b6000806000610e118560000151600216151590565b8015610e5257507f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b031685602001516001600160a01b0316145b905083600001516001600160a01b031685602001516001600160a01b031603610e9957610e8d818660200151876040015187604001516112f8565b91506000925050610f54565b610ea385856114fd565b925082610f385783516040868101516020870151915163a9059cbb60e01b81526001600160a01b03918216600482015260248101929092529091169063a9059cbb906044016020604051808303816000875af1158015610f07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2b9190612155565b5050506020820151610f54565b610f50818660200151876040015187604001516112f8565b9150505b9250929050565b6000546001600160a01b031633146103df5760405163118cdaa760e01b8152336004820152602401610517565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040516001600160a01b03848116602483015283811660448301526064820183905261103f9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505061165d565b50505050565b60006110767f00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45846020015184611207565b7f00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc456001600160a01b03166304e45aaf6040518060e0016040528086602001516001600160a01b0316815260200186604001516001600160a01b031681526020016110fb876000015160008160081a60101b8260071a60081b8360061a01019050919050565b62ffffff168152602001306001600160a01b031681526020018581526020018660e00151815260200160006001600160a01b03168152506040518263ffffffff1660e01b815260040161114e9190612177565b6020604051808303816000875af115801561116d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111919190611c6c565b5060408084015190516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156111dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112009190611c6c565b9392505050565b604051636eb1769f60e11b81523060048201526001600160a01b0384811660248301526000919084169063dd62ed3e90604401602060405180830381865afa158015611257573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127b9190611c6c565b90508181101561103f5761103f84611294836001611c9b565b6112a0906000196121d5565b6001600160a01b03861691906116c5565b600060a082901c156112f45760405162461bcd60e51b815260206004820152600c60248201526b2737ba1022ab269020b2323960a11b6044820152606401610517565b5090565b6040516370a0823160e01b815230600482015260009081906001600160a01b038616906370a0823190602401602060405180830381865afa158015611341573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113659190611c6c565b90508083111561137b5760009150809250611388565b61138583826121d5565b91505b6002546000906001600160a01b0316156113ad576002546001600160a01b03166113af565b335b905086156114bf576040516370a0823160e01b81523060048201527f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b031690632e1a7d4d9082906370a0823190602401602060405180830381865afa158015611423573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114479190611c6c565b6040518263ffffffff1660e01b815260040161146591815260200190565b600060405180830381600087803b15801561147f57600080fd5b505af1158015611493573d6000803e3d6000fd5b5050505060008311156114aa576114aa858461174f565b83156114ba576114ba818561174f565b6114f3565b82156114d9576114d96001600160a01b03871686856117a1565b83156114f3576114f36001600160a01b03871682866117a1565b5050949350505050565b6000806040518060e0016040528084600001516001600160a01b0316815260200185602001516001600160a01b031681526020016115548660000151600981901a600a82901a60081b01600b9190911a60101b0190565b62ffffff168152602001306001600160a01b03168152602001846020015181526020018560800151815260200160006001600160a01b031681525090506115c47f00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc4584600001518560200151611207565b6040516304e45aaf60e01b81526001600160a01b037f00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc4516906304e45aaf90611610908490600401612177565b6020604051808303816000875af192505050801561164b575060408051601f3d908101601f1916820190925261164891810190611c6c565b60015b156116565750600191505b5092915050565b60006116726001600160a01b038416836117d2565b905080516000141580156116975750808060200190518101906116959190612155565b155b156116c057604051635274afe760e01b81526001600160a01b0384166004820152602401610517565b505050565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015611715573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117399190611c6c565b905061103f848461174a8585611c9b565b6117e6565b600080600080600085875af19050806116c05760405162461bcd60e51b81526020600482015260146024820152733330b4b632b2103a379039b2b7321032ba3432b960611b6044820152606401610517565b6040516001600160a01b038381166024830152604482018390526116c091859182169063a9059cbb9060640161100d565b606061120083836000611876565b92915050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526118378482611913565b61103f576040516001600160a01b0384811660248301526000604483015261186c91869182169063095ea7b39060640161100d565b61103f848261165d565b60608147101561189b5760405163cd78605960e01b8152306004820152602401610517565b600080856001600160a01b031684866040516118b791906121e8565b60006040518083038185875af1925050503d80600081146118f4576040519150601f19603f3d011682016040523d82523d6000602084013e6118f9565b606091505b50915091506119098683836119bb565b9695505050505050565b6000806000846001600160a01b03168460405161193091906121e8565b6000604051808303816000865af19150503d806000811461196d576040519150601f19603f3d011682016040523d82523d6000602084013e611972565b606091505b509150915081801561199c57508051158061199c57508080602001905181019061199c9190612155565b80156119b257506000856001600160a01b03163b115b95945050505050565b6060826119d0576119cb82611a17565b611200565b81511580156119e757506001600160a01b0384163b155b15611a1057604051639996b31560e01b81526001600160a01b0385166004820152602401610517565b5080611200565b805115611a275780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60008060208385031215611a5357600080fd5b823567ffffffffffffffff80821115611a6b57600080fd5b818501915085601f830112611a7f57600080fd5b813581811115611a8e57600080fd5b866020828501011115611aa057600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052604160045260246000fd5b604051610140810167ffffffffffffffff81118282101715611aec57611aec611ab2565b60405290565b604051610100810167ffffffffffffffff81118282101715611aec57611aec611ab2565b6001600160a01b0381168114610a0257600080fd5b8035611b3681611b16565b919050565b60006101408284031215611b4e57600080fd5b611b56611ac8565b82358152611b6660208401611b2b565b6020820152611b7760408401611b2b565b6040820152611b8860608401611b2b565b6060820152611b9960808401611b2b565b6080820152611baa60a08401611b2b565b60a082015260c0838101359082015260e080840135908201526101008084013590820152610120928301359281019290925250919050565b600060208284031215611bf457600080fd5b813561120081611b16565b80518252602081015160018060a01b0380821660208501528060408401511660408501525050606081015160608301526080810151608083015260a081015160a08301525050565b8415158152602081018490526040810183905261012081016119b26060830184611bff565b600060208284031215611c7e57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156117e0576117e0611c85565b60c081016117e08284611bff565b60005b83811015611cd7578181015183820152602001611cbf565b50506000910152565b60008151808452611cf8816020860160208601611cbc565b601f01601f19169290920160200192915050565b60018060a01b038716815285602082015261ffff8516604082015283606082015263ffffffff8316608082015260c060a08201526000611d4f60c0830184611ce0565b98975050505050505050565b600060208284031215611d6d57600080fd5b815167ffffffffffffffff8116811461120057600080fd5b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b600082601f830112611dc557600080fd5b815167ffffffffffffffff80821115611de057611de0611ab2565b604051601f8301601f19908116603f01168101908282118183101715611e0857611e08611ab2565b81604052838152866020858801011115611e2157600080fd5b611909846020830160208901611cbc565b600060208284031215611e4457600080fd5b815167ffffffffffffffff811115611e5b57600080fd5b611e6784828501611db4565b949350505050565b6020815260006112006020830184611ce0565b805160ff81168114611b3657600080fd5b805161ffff81168114611b3657600080fd5b600060208284031215611eb757600080fd5b815167ffffffffffffffff80821115611ecf57600080fd5b908301906101008286031215611ee457600080fd5b611eec611af2565b611ef583611e82565b81526020830151602082015260408301516040820152611f1760608401611e93565b606082015260808301516080820152611f3260a08401611e93565b60a082015260c083015160c082015260e083015182811115611f5357600080fd5b611f5f87828601611db4565b60e08301525095945050505050565b600060c08284031215611f8057600080fd5b60405160c0810181811067ffffffffffffffff82111715611fa357611fa3611ab2565b604052825181526020830151611fb881611b16565b60208201526040830151611fcb81611b16565b80604083015250606083015160608201526080830151608082015260a083015160a08201528091505092915050565b60006020828403121561200c57600080fd5b815161120081611b16565b60006020828403121561202957600080fd5b61120082611e82565b60ff82811682821603908111156117e0576117e0611c85565b600181815b8085111561208657816000190482111561206c5761206c611c85565b8085161561207957918102915b93841c9390800290612050565b509250929050565b60008261209d575060016117e0565b816120aa575060006117e0565b81600181146120c057600281146120ca576120e6565b60019150506117e0565b60ff8411156120db576120db611c85565b50506001821b6117e0565b5060208310610133831016604e8410600b8410161715612109575081810a6117e0565b612113838361204b565b806000190482111561212757612127611c85565b029392505050565b600061120060ff84168361208e565b80820281158282048414176117e0576117e0611c85565b60006020828403121561216757600080fd5b8151801515811461120057600080fd5b81516001600160a01b03908116825260208084015182169083015260408084015162ffffff16908301526060808401518216908301526080808401519083015260a0838101519083015260c092830151169181019190915260e00190565b818103818111156117e0576117e0611c85565b600082516121fa818460208701611cbc565b919091019291505056fea2646970667358221220f3bd59e6cb6a3eb18a2cdad6abde82fa285014e470f0d2d7b8ccbad0f6fba6c664736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc450000000000000000000000000b2402144bb366a632d14b83f244d2e0e21bd39c00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab10000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _routerV3 (address): 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45
Arg [1] : _bridge (address): 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c
Arg [2] : _weth (address): 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1
Arg [3] : _feeRecipient (address): 0x0000000000000000000000000000000000000000
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45
Arg [1] : 0000000000000000000000000b2402144bb366a632d14b83f244d2e0e21bd39c
Arg [2] : 00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$136.47
Net Worth in ETH
0.058081
Token Allocations
ETH
88.32%
BNB
11.64%
POL
0.03%
Others
0.01%
Multichain Portfolio | 35 Chains
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.