文件 1 的 4:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 2 的 4:PSPStakingMigratorV1.sol
pragma solidity 0.8.6;
import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
import "./utils/Utils.sol";
error IndexOutOfRange(uint8 index);
interface I_sPSP is IERC20 {
function leave(uint256 _stakedAmount) external;
function withdraw(int256 id) external;
function userVsNextID(address owner) external returns (int256);
}
interface I_stkPSPBpt is IERC20 {
function redeem(address to, uint256 amount) external;
function cooldown() external;
}
interface I_sePSP is IERC20 {
function deposit(uint256 amount) external;
}
interface I_sePSP2 is I_sePSP {
function depositPSPAndEth(
uint256 pspAmount,
uint256 minBptOut,
bytes memory pspPermit
) external payable;
function depositPSPAndWeth(
uint256 pspAmount,
uint256 wethAmount,
uint256 minBptOut,
bytes memory pspPermit
) external;
}
contract PSPStakingMigratorV1 {
IERC20 public immutable PSP;
IERC20 public immutable WETH;
I_sePSP public immutable sePSP;
I_sePSP2 public immutable sePSP2;
I_stkPSPBpt public immutable stkPSPBpt;
IERC20 public immutable BPT;
I_sPSP[] public SPSPs;
struct RequestSPSP {
uint8 index;
uint256 amount;
bytes permitData;
}
constructor(
IERC20 _PSP,
IERC20 _WETH,
IERC20 _bpt,
I_sePSP _sePSP,
I_sePSP2 _sePSP2,
I_stkPSPBpt _stkPSPBpt,
I_sPSP[] memory _SPSPs
) {
PSP = _PSP;
WETH = _WETH;
BPT = _bpt;
sePSP = _sePSP;
sePSP2 = _sePSP2;
stkPSPBpt = _stkPSPBpt;
SPSPs = _SPSPs;
}
function depositSPSPsForSePSP(RequestSPSP[] calldata reqs) external {
_unstakeSPSPsAndGetPSP(reqs);
uint256 pspBalance = PSP.balanceOf(address(this));
PSP.approve(address(sePSP), pspBalance);
sePSP.deposit(pspBalance);
sePSP.transfer(msg.sender, pspBalance);
}
function depositStkPSPBptForSePSP2(uint256 bptAmount, bytes calldata stkPSPBptPermit) external {
Utils.permit(stkPSPBpt, stkPSPBptPermit);
stkPSPBpt.transferFrom(msg.sender, address(this), bptAmount);
stkPSPBpt.cooldown();
stkPSPBpt.redeem(address(this), bptAmount);
BPT.approve(address(sePSP2), bptAmount);
sePSP2.deposit(bptAmount);
sePSP2.transfer(msg.sender, bptAmount);
}
function depositSPSPsAndETHForSePSP2(RequestSPSP[] calldata reqs, uint256 minBptOut) external payable {
_unstakeSPSPsAndGetPSP(reqs);
uint256 pspAmount = PSP.balanceOf(address(this));
PSP.approve(address(sePSP2), pspAmount);
sePSP2.depositPSPAndEth{ value: msg.value }(pspAmount, minBptOut, "");
uint256 sePSP2Balance = sePSP2.balanceOf(address(this));
sePSP2.transfer(msg.sender, sePSP2Balance);
}
function depositSPSPsAndWETHForSePSP2(
RequestSPSP[] calldata reqs,
uint256 wethAmount,
uint256 minBptOut
) external {
_unstakeSPSPsAndGetPSP(reqs);
WETH.transferFrom(msg.sender, address(this), wethAmount);
uint256 pspAmount = PSP.balanceOf(address(this));
PSP.approve(address(sePSP2), pspAmount);
WETH.approve(address(sePSP2), wethAmount);
sePSP2.depositPSPAndWeth(pspAmount, wethAmount, minBptOut, "");
uint256 sePSP2Balance = sePSP2.balanceOf(address(this));
sePSP2.transfer(msg.sender, sePSP2Balance);
}
function _unstakeSPSPsAndGetPSP(RequestSPSP[] calldata reqs) internal {
for (uint8 i; i < reqs.length; i++) {
RequestSPSP memory req = reqs[i];
if (req.index >= SPSPs.length) {
revert IndexOutOfRange(req.index);
}
I_sPSP sPSP = SPSPs[req.index];
Utils.permit(sPSP, req.permitData);
sPSP.transferFrom(msg.sender, address(this), req.amount);
int256 id = sPSP.userVsNextID(address(this));
sPSP.leave(req.amount);
sPSP.withdraw(id);
}
}
}
文件 3 的 4:Utils.sol
pragma solidity 0.8.6;
import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
error PermitFailed();
error TransferEthFailed();
library Utils {
function permit(IERC20 token, bytes memory permit) internal {
if (permit.length == 32 * 7) {
(bool success, ) = address(token).call(abi.encodePacked(IERC20Permit.permit.selector, permit));
if (!success) {
revert PermitFailed();
}
}
}
function transferETH(address payable destination, uint256 amount) internal {
if (amount > 0) {
(bool result, ) = destination.call{ value: amount }("");
if (!result) {
revert TransferEthFailed();
}
}
}
}
文件 4 的 4:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
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);
}
{
"compilationTarget": {
"contracts/2.0/PSPStakingMigratorV1.sol": "PSPStakingMigratorV1"
},
"evmVersion": "berlin",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 100000
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IERC20","name":"_PSP","type":"address"},{"internalType":"contract IERC20","name":"_WETH","type":"address"},{"internalType":"contract IERC20","name":"_bpt","type":"address"},{"internalType":"contract I_sePSP","name":"_sePSP","type":"address"},{"internalType":"contract I_sePSP2","name":"_sePSP2","type":"address"},{"internalType":"contract I_stkPSPBpt","name":"_stkPSPBpt","type":"address"},{"internalType":"contract I_sPSP[]","name":"_SPSPs","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"IndexOutOfRange","type":"error"},{"inputs":[],"name":"PermitFailed","type":"error"},{"inputs":[],"name":"BPT","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PSP","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"SPSPs","outputs":[{"internalType":"contract I_sPSP","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"index","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"permitData","type":"bytes"}],"internalType":"struct PSPStakingMigratorV1.RequestSPSP[]","name":"reqs","type":"tuple[]"},{"internalType":"uint256","name":"minBptOut","type":"uint256"}],"name":"depositSPSPsAndETHForSePSP2","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"index","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"permitData","type":"bytes"}],"internalType":"struct PSPStakingMigratorV1.RequestSPSP[]","name":"reqs","type":"tuple[]"},{"internalType":"uint256","name":"wethAmount","type":"uint256"},{"internalType":"uint256","name":"minBptOut","type":"uint256"}],"name":"depositSPSPsAndWETHForSePSP2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"index","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"permitData","type":"bytes"}],"internalType":"struct PSPStakingMigratorV1.RequestSPSP[]","name":"reqs","type":"tuple[]"}],"name":"depositSPSPsForSePSP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bptAmount","type":"uint256"},{"internalType":"bytes","name":"stkPSPBptPermit","type":"bytes"}],"name":"depositStkPSPBptForSePSP2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sePSP","outputs":[{"internalType":"contract I_sePSP","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sePSP2","outputs":[{"internalType":"contract I_sePSP2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stkPSPBpt","outputs":[{"internalType":"contract I_stkPSPBpt","name":"","type":"address"}],"stateMutability":"view","type":"function"}]