编译器
0.8.20+commit.a1b79de6
文件 1 的 13:Address.sol
pragma solidity ^0.8.20;
library Address {
error AddressInsufficientBalance(address account);
error AddressEmptyCode(address target);
error FailedInnerCall();
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();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
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);
}
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);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
文件 2 的 13:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 3 的 13:IERC20.sol
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);
}
文件 4 的 13:IERC20Permit.sol
pragma solidity ^0.8.20;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 5 的 13:ISwapRouter02.sol
pragma solidity >=0.7.5;
pragma abicoder v2;
interface ISwapRouter02 {
function factory() external view returns (address);
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
}
文件 6 的 13:ITokenBridge.sol
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);
}
文件 7 的 13:IWETH.sol
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;
}
文件 8 的 13:IWormhole.sol
pragma solidity ^0.8.9;
interface IWormhole {
struct GuardianSet {
address[] keys;
uint32 expirationTime;
}
struct Signature {
bytes32 r;
bytes32 s;
uint8 v;
uint8 guardianIndex;
}
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;
}
文件 9 的 13:Ownable.sol
pragma solidity ^0.8.20;
import {Context} from "./Context.sol";
abstract contract Ownable is Context {
address private _owner;
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 10 的 13:Portico.sol
pragma solidity ^0.8.9;
import "./PorticoStructs.sol";
import "./ITokenBridge.sol";
import "./IWormhole.sol";
import "./IERC20.sol";
import "./IWETH.sol";
import "./uniswap/ISwapRouter02.sol";
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;
}
function setFeeRecipient(address newFeeRecipient) external onlyOwner {
FEE_RECIPIENT = newFeeRecipient;
}
function updateApproval(address spender, IERC20 token, uint256 amount) internal {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < amount) {
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),
address(params.canonAssetAddress),
params.flags.feeTierStart(),
address(this),
actualAmount,
params.minAmountStart,
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;
if (address(params.startTokenAddress) == address(WETH) && params.flags.shouldWrapNative()) {
require(value == params.amountSpecified + whMessageFee, "msg.value incorrect");
WETH.deposit{ value: params.amountSpecified }();
amount = WETH.balanceOf(address(this));
} else {
require(value == whMessageFee, "msg.value incorrect");
params.startTokenAddress.safeTransferFrom(_msgSender(), address(this), params.amountSpecified);
amount = params.startTokenAddress.balanceOf(address(this));
}
require(amount >= params.amountSpecified, "transfer insufficient");
if (params.startTokenAddress != params.canonAssetAddress) {
amount = _start_v3swap(params, amount);
}
updateApproval(address(TOKENBRIDGE), params.canonAssetAddress, amount);
PorticoStructs.DecodedVAA memory decodedVAA = PorticoStructs.DecodedVAA(
params.flags,
params.finalTokenAddress,
params.recipientAddress,
amount,
params.minAmountFinish,
params.relayerFee
);
sequence = TOKENBRIDGE.transferTokensWithPayload{ value: whMessageFee }(
address(params.canonAssetAddress),
amount,
params.flags.recipientChain(),
padAddress(params.recipientPorticoAddress),
params.flags.bridgeNonce(),
abi.encode(decodedVAA)
);
chainId = wormholeChainId;
emitterAddress = address(TOKENBRIDGE);
emit PorticoSwapStart(sequence, chainId);
}
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);
function receiveMessageAndSwap(bytes calldata encodedTransferMessage) external nonReentrant {
(PorticoStructs.DecodedVAA memory message, PorticoStructs.BridgeInfo memory bridgeInfo) = _completeTransfer(encodedTransferMessage);
bridgeInfo.relayerFeeAmount = (_msgSender() == message.recipientAddress) ? 0 : message.relayerFee;
(bool swapCompleted, uint256 finalUserAmount) = finish(message, bridgeInfo);
emit PorticoSwapFinish(swapCompleted, finalUserAmount, bridgeInfo.relayerFeeAmount, message);
}
function _completeTransfer(
bytes calldata encodedTransferMessage
) internal returns (PorticoStructs.DecodedVAA memory message, PorticoStructs.BridgeInfo memory bridgeInfo) {
bytes memory transferPayload = TOKENBRIDGE.completeTransferWithPayload(encodedTransferMessage);
ITokenBridge.TransferWithPayload memory transfer = TOKENBRIDGE.parseTransferWithPayload(transferPayload);
require(unpadAddress(transfer.to) == address(this) && transfer.toChain == wormholeChainId, "Token not sent to this address");
message = abi.decode(transfer.payload, (PorticoStructs.DecodedVAA));
bridgeInfo.tokenReceived = IERC20(
transfer.tokenChain == wormholeChainId
? unpadAddress(transfer.tokenAddress)
: TOKENBRIDGE.wrappedAsset(transfer.tokenChain, transfer.tokenAddress)
);
bridgeInfo.amountReceived = transfer.amount;
uint8 decimals = bridgeInfo.tokenReceived.decimals();
if (decimals > 8) {
bridgeInfo.amountReceived *= uint256(10) ** (decimals - 8);
}
}
function finish(
PorticoStructs.DecodedVAA memory params,
PorticoStructs.BridgeInfo memory bridgeInfo
) internal returns (bool swapCompleted, uint256 finalUserAmount) {
bool shouldUnwrap = params.flags.shouldUnwrapNative() && address(params.finalTokenAddress) == address(WETH);
if ((params.finalTokenAddress) == bridgeInfo.tokenReceived) {
finalUserAmount = payOut(shouldUnwrap, params.finalTokenAddress, params.recipientAddress, bridgeInfo.relayerFeeAmount);
return (false, finalUserAmount);
}
swapCompleted = _finish_v3swap(params, bridgeInfo);
if (!swapCompleted) {
bridgeInfo.tokenReceived.transfer(params.recipientAddress, bridgeInfo.amountReceived);
return (swapCompleted, bridgeInfo.amountReceived);
}
finalUserAmount = payOut(shouldUnwrap, params.finalTokenAddress, params.recipientAddress, bridgeInfo.relayerFeeAmount);
}
function _finish_v3swap(
PorticoStructs.DecodedVAA memory params,
PorticoStructs.BridgeInfo memory bridgeInfo
) internal returns (bool swapCompleted) {
ISwapRouter02.ExactInputSingleParams memory swapParams = ISwapRouter02.ExactInputSingleParams({
tokenIn: address(bridgeInfo.tokenReceived),
tokenOut: address(params.finalTokenAddress),
fee: params.flags.feeTierFinish(),
recipient: address(this),
amountIn: bridgeInfo.amountReceived,
amountOutMinimum: params.minAmountFinish,
sqrtPriceLimitX96: 0
});
updateApproval(address(ROUTERV3), bridgeInfo.tokenReceived, bridgeInfo.amountReceived);
try ROUTERV3.exactInputSingle(swapParams) {
swapCompleted = true;
} catch {}
}
function payOut(bool unwrap, IERC20 finalToken, address recipient, uint256 relayerFeeAmount) internal returns (uint256 finalUserAmount) {
uint256 totalBalance = finalToken.balanceOf(address(this));
if (relayerFeeAmount > totalBalance) {
finalUserAmount = 0;
relayerFeeAmount = totalBalance;
} else {
finalUserAmount = totalBalance - relayerFeeAmount;
}
address feeRecipient = FEE_RECIPIENT == address(0x0) ? _msgSender() : FEE_RECIPIENT;
if (unwrap) {
WETH.withdraw(WETH.balanceOf(address(this)));
if (finalUserAmount > 0) {
sendEther(recipient, finalUserAmount);
}
if (relayerFeeAmount > 0) {
sendEther(feeRecipient, relayerFeeAmount);
}
} else {
if (finalUserAmount > 0) {
finalToken.safeTransfer(recipient, finalUserAmount);
}
if (relayerFeeAmount > 0) {
finalToken.safeTransfer(feeRecipient, relayerFeeAmount);
}
}
}
receive() external payable {}
function unpadAddress(bytes32 whFormatAddress) internal pure returns (address) {
if (uint256(whFormatAddress) >> 160 != 0) {
revert("Not EVM Addr");
}
return address(uint160(uint256(whFormatAddress)));
}
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) {}
}
文件 11 的 13:PorticoStructs.sol
pragma solidity ^0.8.9;
import "./IERC20.sol";
type PorticoFlagSet is bytes32;
library PorticoFlagSetAccess {
function recipientChain(PorticoFlagSet flagset) internal pure returns (uint16 ans) {
assembly {
ans := add(byte(0, flagset), shl(8, byte(1, flagset)))
}
}
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)))
}
}
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)))
}
}
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)))
}
}
function shouldWrapNative(PorticoFlagSet flagset) internal pure returns (bool) {
bytes32 fs = PorticoFlagSet.unwrap(flagset);
return uint8(fs[31]) & (1 << 0) > 0;
}
function shouldUnwrapNative(PorticoFlagSet flagset) internal pure returns (bool) {
bytes32 fs = PorticoFlagSet.unwrap(flagset);
return uint8(fs[31]) & (1 << 1) > 0;
}
}
library PorticoStructs {
struct TokenReceived {
bytes32 tokenHomeAddress;
uint16 tokenHomeChain;
IERC20 tokenAddress;
uint256 amount;
}
struct TradeParameters {
PorticoFlagSet flags;
IERC20 startTokenAddress;
IERC20 canonAssetAddress;
IERC20 finalTokenAddress;
address recipientAddress;
address recipientPorticoAddress;
uint256 amountSpecified;
uint256 minAmountStart;
uint256 minAmountFinish;
uint256 relayerFee;
}
struct DecodedVAA {
PorticoFlagSet flags;
IERC20 finalTokenAddress;
address recipientAddress;
uint256 canonAssetAmount;
uint256 minAmountFinish;
uint256 relayerFee;
}
struct BridgeInfo {
IERC20 tokenReceived;
uint256 amountReceived;
uint256 relayerFeeAmount;
}
}
文件 12 的 13:ReentrancyGuard.sol
pragma solidity ^0.8.20;
abstract contract ReentrancyGuard {
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
_status = ENTERED;
}
function _nonReentrantAfter() private {
_status = NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
文件 13 的 13:SafeERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "./IERC20Permit.sol";
import {Address} from "./Address.sol";
library SafeERC20 {
using Address for address;
error SafeERC20FailedOperation(address token);
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
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);
}
}
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);
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}
{
"compilationTarget": {
"contracts/Portico.sol": "Portico"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"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"}]