编译器
0.8.17+commit.8df45f5f
文件 1 的 7:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 2 的 7:EnumerableSet.sol
pragma solidity ^0.8.0;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping(bytes32 => uint256) _indexes;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
set._values[toDeleteIndex] = lastValue;
set._indexes[lastValue] = valueIndex;
}
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
assembly {
result := store
}
return result;
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}
文件 3 的 7:FjordLbpAbstractV1.sol
pragma solidity ^0.8.7;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {TransferHelper} from "@uniswap/lib/contracts/libraries/TransferHelper.sol";
enum LBPType {
NORMAL,
NFT,
REDEMPTION,
SWEEPER
}
enum SwapKind {
GIVEN_IN,
GIVEN_OUT
}
interface IAsset {
}
struct SingleSwap {
bytes32 poolId;
SwapKind kind;
IAsset assetIn;
IAsset assetOut;
uint256 amount;
bytes userData;
}
struct FundManagement {
address sender;
bool fromInternalBalance;
address payable recipient;
bool toInternalBalance;
}
interface LBPFactory {
function create(
string memory name,
string memory symbol,
address[] memory tokens,
uint256[] memory weights,
uint256 swapFeePercentage,
address owner,
bool swapEnabledOnStart
) external returns (address);
}
interface Vault {
struct JoinPoolRequest {
address[] assets;
uint256[] maxAmountsIn;
bytes userData;
bool fromInternalBalance;
}
struct ExitPoolRequest {
address[] assets;
uint256[] minAmountsOut;
bytes userData;
bool toInternalBalance;
}
function joinPool(bytes32 poolId, address sender, address recipient, JoinPoolRequest memory request) external;
function exitPool(bytes32 poolId, address sender, address recipient, ExitPoolRequest memory request) external;
function getPoolTokens(
bytes32 poolId
) external view returns (address[] memory tokens, uint256[] memory balances, uint256 lastChangeBlock);
function swap(
SingleSwap memory singleSwap,
FundManagement memory funds,
uint256 limit,
uint256 deadline
) external payable returns (uint256 amountCalculated);
}
interface LBP {
function updateWeightsGradually(uint256 startTime, uint256 endTime, uint256[] memory endWeights) external;
function setSwapEnabled(bool swapEnabled) external;
function getPoolId() external returns (bytes32 poolID);
}
interface WeightedPool {
function getPoolId() external returns (bytes32 poolID);
}
interface Blocklist {
function isNotBlocked(address _address) external view returns (bool);
}
enum ExitKind {
EXACT_BPT_IN_FOR_ONE_TOKEN_OUT,
EXACT_BPT_IN_FOR_TOKENS_OUT,
BPT_IN_FOR_EXACT_TOKENS_OUT
}
abstract contract FjordLbpAbstractV1 is Ownable {
using EnumerableSet for EnumerableSet.AddressSet;
address public blockListAddress;
EnumerableSet.AddressSet internal _pools;
EnumerableSet.AddressSet internal _recipientAddresses;
mapping(address => uint256) internal _feeRecipientsBPS;
uint256 internal constant _TEN_THOUSAND_BPS = 10_000;
LBPType public lbpType;
event Skimmed(address token, address to, uint256 balance);
event RecipientsUpdated(address[] recipients, uint256[] recipientShareBPS);
event TransferredFee(address indexed pool, address token, address feeRecipient, uint256 feeAmount);
event TransferredToken(address indexed pool, address token, address to, uint256 amount);
event JoinedPool(address indexed pool, address[] tokens, uint256[] amounts, bytes userData);
event GradualWeightUpdateScheduled(address indexed pool, uint256 startTime, uint256 endTime, uint256[] endWeights);
event SwapEnabledSet(address indexed pool, bool swapEnabled);
event TransferredPoolOwnership(address indexed pool, address previousOwner, address newOwner);
event PoolCreated(
address indexed pool,
bytes32 poolId,
string name,
string symbol,
address[] tokens,
uint256[] weights,
uint256 swapFeePercentage,
address owner,
bool swapEnabledOnStart,
LBPType lbpType
);
function isPool(address pool) external view returns (bool valid) {
return _pools.contains(pool);
}
function poolCount() external view returns (uint256 count) {
return _pools.length();
}
function getPoolAt(uint256 index) external view returns (address pool) {
return _pools.at(index);
}
function getPools() external view returns (address[] memory pools) {
return _pools.values();
}
function getBPTTokenBalance(address pool) external view returns (uint256 bptBalance) {
return IERC20(pool).balanceOf(address(this));
}
function getFeeRecipients() external view returns (address[] memory recipients) {
return _recipientAddresses.values();
}
function getRecipientShareBPS(address recipientAddress) external view returns (uint256 shareSize) {
if (_recipientAddresses.contains(recipientAddress)) {
return _feeRecipientsBPS[recipientAddress];
}
return uint256(0);
}
function _calcBPTokenToBurn(address pool, uint256 maxBPTTokenOut) internal view returns (uint256) {
uint256 bptBalance = IERC20(pool).balanceOf(address(this));
require(maxBPTTokenOut <= bptBalance, "Specifed BPT out amount out exceeds owner balance");
require(bptBalance > 0, "Pool owner BPT balance is less than zero");
return maxBPTTokenOut == 0 ? bptBalance : maxBPTTokenOut;
}
function _transferTokenToPoolOwner(address pool, address token, uint256 amount) internal {
TransferHelper.safeTransfer(token, msg.sender, amount);
emit TransferredToken(pool, token, msg.sender, amount);
}
function _distributeSafeFee(address pool, address fundToken, uint256 totalFeeAmount) internal {
TransferHelper.safeTransfer(fundToken, owner(), totalFeeAmount);
emit TransferredFee(pool, fundToken, owner(), totalFeeAmount);
}
function _resetRecipients() private {
uint256 recipientsLength = _recipientAddresses.length();
address[] memory recipientValues = _recipientAddresses.values();
for (uint256 i = 0; i < recipientsLength; i++) {
address recipientAddress = recipientValues[i];
delete _feeRecipientsBPS[recipientAddress];
_recipientAddresses.remove(recipientAddress);
}
}
function updateRecipients(address[] calldata recipients, uint256[] calldata recipientShareBPS) external onlyOwner {
require(recipients.length > 0, "recipients must have values");
require(recipientShareBPS.length > 0, "recipientShareBPS must have values");
require(
recipients.length == recipientShareBPS.length,
"'recipients' and 'recipientShareBPS' arrays must have the same length"
);
_resetRecipients();
require(blockListAddress != address(0), "no blocklist address set");
uint256 sumBPS = 0;
uint256 arraysLength = recipientShareBPS.length;
for (uint256 i = 0; i < arraysLength; i++) {
require(recipientShareBPS[i] > uint256(0), "Share BPS size must be greater than 0");
bool recipientIsNotBlocked = Blocklist(blockListAddress).isNotBlocked(recipients[i]);
require(recipientIsNotBlocked, "recipient is blocked");
sumBPS += recipientShareBPS[i];
_recipientAddresses.add(recipients[i]);
_feeRecipientsBPS[recipients[i]] = recipientShareBPS[i];
}
require(sumBPS == _TEN_THOUSAND_BPS, "Invalid recipients BPS sum");
require(_recipientAddresses.length() == recipientShareBPS.length, "Fee recipient address must be unique");
emit RecipientsUpdated(recipients, recipientShareBPS);
}
function _distributePlatformAccessFee(address pool, address fundToken, uint256 totalFeeAmount) internal {
uint256 recipientsLength = _recipientAddresses.length();
for (uint256 i = 0; i < recipientsLength; i++) {
address recipientAddress = _recipientAddresses.at(i);
uint256 proportionalAmount = (totalFeeAmount * _feeRecipientsBPS[recipientAddress]) / _TEN_THOUSAND_BPS;
TransferHelper.safeTransfer(fundToken, recipientAddress, proportionalAmount);
emit TransferredFee(pool, fundToken, recipientAddress, proportionalAmount);
}
}
function skim(address token, address recipient) external onlyOwner {
require(!_pools.contains(token), "can't skim BPT tokens");
uint256 balance = IERC20(token).balanceOf(address(this));
TransferHelper.safeTransfer(token, recipient, balance);
emit Skimmed(token, recipient, balance);
}
function updateBlocklistAddress(address contractAddress) external onlyOwner {
blockListAddress = contractAddress;
}
}
文件 4 的 7:FjordLbpProxyV6.sol
pragma solidity ^0.8.7;
import {TransferHelper} from "@uniswap/lib/contracts/libraries/TransferHelper.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "./FjordLbpAbstractV1.sol";
struct PoolConfig {
string name;
string symbol;
address[] tokens;
uint256[] amounts;
uint256[] weights;
uint256[] endWeights;
uint256 swapFeePercentage;
uint256 startTime;
uint256 endTime;
}
struct WeightedPoolConfig {
string name;
string symbol;
address[] tokens;
uint256[] amounts;
uint256[] weights;
uint256 swapFeePercentage;
}
struct PoolData {
address owner;
uint256 fundTokenInputAmount;
LBPType lbpType;
address weightedPoolAddress;
}
interface IRateProvider {
function getRate() external view returns (uint256);
}
interface WeightedPoolFactory {
function create(
string memory name,
string memory symbol,
IERC20[] memory tokens,
uint256[] memory normalizedWeights,
IRateProvider[] memory rateProviders,
uint256 swapFeePercentage,
address owner
) external returns (address);
}
contract FjordLbpProxyV6 is FjordLbpAbstractV1 {
address ZERO_ADDRESS = 0x0000000000000000000000000000000000000000;
using EnumerableSet for EnumerableSet.AddressSet;
EnumerableSet.AddressSet internal _weightedPools;
EnumerableSet.AddressSet internal _fundTokenAddresses;
mapping(address => PoolData) private _poolData;
address public immutable VaultAddress;
address public immutable LBPFactoryAddress;
address public immutable WeightedPoolFactoryAddress;
uint256 public immutable platformAccessFeeBPS;
event WeightedPoolCreated(
address indexed pool,
bytes32 poolId,
string name,
string symbol,
address[] tokens,
uint256[] weights,
uint256 swapFeePercentage,
address owner
);
event JoinedWeightedPool(address indexed pool, address[] tokens, uint256[] amounts, bytes userData);
constructor(
uint256 _platformAccessFeeBPS,
address _LBPFactoryAddress,
address _WeightedPoolFactoryAddress,
address _vaultAddress,
address[] memory fundTokenAddresses
) {
require(_platformAccessFeeBPS <= 10_000, "LBP Fee cannot be greater than 10.000 (100%)");
require(fundTokenAddresses.length > 0, "At least 1 fund needs to be used");
lbpType = LBPType.NORMAL;
platformAccessFeeBPS = _platformAccessFeeBPS;
LBPFactoryAddress = _LBPFactoryAddress;
WeightedPoolFactoryAddress = _WeightedPoolFactoryAddress;
VaultAddress = _vaultAddress;
_recipientAddresses.add(owner());
_feeRecipientsBPS[owner()] = _TEN_THOUSAND_BPS;
addFundTokenOptions(fundTokenAddresses);
}
modifier onlyLBPPoolOwner(address pool) {
require(msg.sender == _poolData[pool].owner, "!owner");
_;
}
function allowedFundTokens() external view returns (address[] memory fundTokens) {
return _fundTokenAddresses.values();
}
function isAllowedFund(address tokenAddress) external view returns (bool) {
return _fundTokenAddresses.contains(tokenAddress);
}
function isWeightedPool(address pool) external view returns (bool valid) {
return _weightedPools.contains(pool);
}
function getWeightedPools() external view returns (address[] memory pools) {
return _weightedPools.values();
}
function weightedPoolCount() external view returns (uint256 count) {
return _weightedPools.length();
}
function getPoolData(address pool) external view returns (PoolData memory poolData) {
return _poolData[pool];
}
function createLBP(PoolConfig memory poolConfig) external returns (address) {
require(poolConfig.tokens.length == 2, "Copper LBPs must have exactly two tokens");
require(poolConfig.tokens[0] != poolConfig.tokens[1], "LBP tokens must be unique");
require(poolConfig.startTime > block.timestamp, "LBP start time must be in the future");
require(poolConfig.endTime > poolConfig.startTime, "LBP end time must be greater than start time");
require(blockListAddress != address(0), "no blocklist address set");
bool msgSenderIsNotBlocked = Blocklist(blockListAddress).isNotBlocked(msg.sender);
require(msgSenderIsNotBlocked, "msg.sender is blocked");
int256 indexOfFundToken = _findIndexOfFund(poolConfig.tokens);
TransferHelper.safeTransferFrom(poolConfig.tokens[0], msg.sender, address(this), poolConfig.amounts[0]);
TransferHelper.safeTransferFrom(poolConfig.tokens[1], msg.sender, address(this), poolConfig.amounts[1]);
TransferHelper.safeApprove(poolConfig.tokens[0], VaultAddress, poolConfig.amounts[0]);
TransferHelper.safeApprove(poolConfig.tokens[1], VaultAddress, poolConfig.amounts[1]);
address pool = LBPFactory(LBPFactoryAddress).create(
poolConfig.name,
poolConfig.symbol,
poolConfig.tokens,
poolConfig.weights,
poolConfig.swapFeePercentage,
address(this),
false
);
bytes32 poolId = LBP(pool).getPoolId();
emit PoolCreated(
pool,
poolId,
poolConfig.name,
poolConfig.symbol,
poolConfig.tokens,
poolConfig.weights,
poolConfig.swapFeePercentage,
address(this),
false,
lbpType
);
_poolData[pool] = PoolData(msg.sender, poolConfig.amounts[uint256(indexOfFundToken)], lbpType, address(0));
require(_pools.add(pool), "exists already");
bytes memory userData = abi.encode(0, poolConfig.amounts);
Vault(VaultAddress).joinPool(
poolId,
address(this),
address(this),
Vault.JoinPoolRequest(poolConfig.tokens, poolConfig.amounts, userData, false)
);
emit JoinedPool(pool, poolConfig.tokens, poolConfig.amounts, userData);
LBP(pool).updateWeightsGradually(poolConfig.startTime, poolConfig.endTime, poolConfig.endWeights);
emit GradualWeightUpdateScheduled(pool, poolConfig.startTime, poolConfig.endTime, poolConfig.endWeights);
return pool;
}
function setSwapEnabled(address pool, bool swapEnabled) external onlyLBPPoolOwner(pool) {
LBP(pool).setSwapEnabled(swapEnabled);
emit SwapEnabledSet(pool, swapEnabled);
}
function transferPoolOwnership(address pool, address newOwner) external onlyLBPPoolOwner(pool) {
require(blockListAddress != address(0), "no blocklist address set");
bool newOwnerIsNotBlocked = Blocklist(blockListAddress).isNotBlocked(msg.sender);
require(newOwnerIsNotBlocked, "newOwner is blocked");
address previousOwner = _poolData[pool].owner;
_poolData[pool].owner = newOwner;
emit TransferredPoolOwnership(pool, previousOwner, newOwner);
}
function exitPool(address pool, uint256 maxBPTTokenOut, bool isStandardFee) external onlyLBPPoolOwner(pool) {
uint256[] memory minAmountsOut = new uint256[](2);
minAmountsOut[0] = uint256(0);
minAmountsOut[1] = uint256(0);
bytes32 poolId = LBP(pool).getPoolId();
(address[] memory poolTokens, uint256[] memory balances, ) = Vault(VaultAddress).getPoolTokens(poolId);
require(poolTokens.length == minAmountsOut.length, "invalid input length");
PoolData memory poolData = _poolData[pool];
uint256 bptToBurn = _calcBPTokenToBurn(pool, maxBPTTokenOut);
Vault(VaultAddress).exitPool(
poolId,
address(this),
payable(address(this)),
Vault.ExitPoolRequest(
poolTokens,
minAmountsOut,
abi.encode(ExitKind.EXACT_BPT_IN_FOR_TOKENS_OUT, bptToBurn),
false
)
);
(, uint256[] memory balancesAfterExit, ) = Vault(VaultAddress).getPoolTokens(poolId);
int256 indexOfFundToken = _findIndexOfFund(poolTokens);
_distributeTokens(
pool,
poolTokens,
poolData,
balances[uint256(indexOfFundToken)] - balancesAfterExit[uint256(indexOfFundToken)],
isStandardFee,
indexOfFundToken
);
}
function _distributeTokens(
address pool,
address[] memory poolTokens,
PoolData memory poolData,
uint256 fundTokenFromPool,
bool isStandardFee,
int256 indexOfFundToken
) private {
require(indexOfFundToken >= 0, "No valid collateral token found");
address mainToken = poolTokens[indexOfFundToken == 0 ? 1 : 0];
address fundToken = poolTokens[uint256(indexOfFundToken)];
uint256 mainTokenBalance = IERC20(mainToken).balanceOf(address(this));
uint256 remainingFundBalance = fundTokenFromPool;
if (fundTokenFromPool > poolData.fundTokenInputAmount) {
uint256 totalPlatformAccessFeeAmount = ((fundTokenFromPool - poolData.fundTokenInputAmount) *
platformAccessFeeBPS) / _TEN_THOUSAND_BPS;
remainingFundBalance = fundTokenFromPool - totalPlatformAccessFeeAmount;
if (isStandardFee == true) {
_distributePlatformAccessFee(pool, fundToken, totalPlatformAccessFeeAmount);
} else {
_distributeSafeFee(pool, fundToken, totalPlatformAccessFeeAmount);
}
}
_transferTokenToPoolOwner(pool, mainToken, mainTokenBalance);
_transferTokenToPoolOwner(pool, fundToken, remainingFundBalance);
}
function createWeightedPoolForLBP(
address lbpPool,
WeightedPoolConfig memory weightedPoolConfig
) external onlyLBPPoolOwner(lbpPool) returns (address) {
require(weightedPoolConfig.tokens.length == 2, "Weighted pool must have exactly two tokens");
require(weightedPoolConfig.tokens[0] != weightedPoolConfig.tokens[1], "Tokens must be unique");
require(blockListAddress != address(0), "no blocklist address set");
require(Blocklist(blockListAddress).isNotBlocked(msg.sender), "msg.sender is blocked");
require(_poolData[lbpPool].weightedPoolAddress == address(0), "Weighted pool already exists for this LBP");
TransferHelper.safeTransferFrom(
weightedPoolConfig.tokens[0],
msg.sender,
address(this),
weightedPoolConfig.amounts[0]
);
TransferHelper.safeTransferFrom(
weightedPoolConfig.tokens[1],
msg.sender,
address(this),
weightedPoolConfig.amounts[1]
);
TransferHelper.safeApprove(weightedPoolConfig.tokens[0], VaultAddress, weightedPoolConfig.amounts[0]);
TransferHelper.safeApprove(weightedPoolConfig.tokens[1], VaultAddress, weightedPoolConfig.amounts[1]);
IERC20[] memory tokens = new IERC20[](2);
tokens[0] = IERC20(weightedPoolConfig.tokens[0]);
tokens[1] = IERC20(weightedPoolConfig.tokens[1]);
IRateProvider[] memory rateProviders = new IRateProvider[](2);
rateProviders[0] = IRateProvider(ZERO_ADDRESS);
rateProviders[1] = IRateProvider(ZERO_ADDRESS);
address weightedPool = WeightedPoolFactory(WeightedPoolFactoryAddress).create(
weightedPoolConfig.name,
weightedPoolConfig.symbol,
tokens,
weightedPoolConfig.weights,
rateProviders,
weightedPoolConfig.swapFeePercentage,
msg.sender
);
bytes32 poolId = WeightedPool(weightedPool).getPoolId();
emit WeightedPoolCreated(
weightedPool,
poolId,
weightedPoolConfig.name,
weightedPoolConfig.symbol,
weightedPoolConfig.tokens,
weightedPoolConfig.weights,
weightedPoolConfig.swapFeePercentage,
msg.sender
);
_poolData[lbpPool].weightedPoolAddress = weightedPool;
require(_weightedPools.add(weightedPool), "exists already");
bytes memory userData = abi.encode(0, weightedPoolConfig.amounts);
Vault(VaultAddress).joinPool(
poolId,
address(this),
msg.sender,
Vault.JoinPoolRequest(weightedPoolConfig.tokens, weightedPoolConfig.amounts, userData, false)
);
emit JoinedWeightedPool(weightedPool, weightedPoolConfig.tokens, weightedPoolConfig.amounts, userData);
return weightedPool;
}
function getWeightedTokenBalance(address weightedPool) external view returns (uint256 weightedBalance) {
return IERC20(weightedPool).balanceOf(msg.sender);
}
function _findIndexOfFund(address[] memory tokens) internal view returns (int256) {
bool isToken1Fund = _fundTokenAddresses.contains(tokens[0]);
bool isToken2Fund = _fundTokenAddresses.contains(tokens[1]);
require(isToken1Fund == true || isToken2Fund == true, "At least one token must be a collateral token");
require(
isToken1Fund == false || isToken2Fund == false,
"At least one of the token must not be a collateral token"
);
return isToken1Fund == true ? int256(0) : int256(1);
}
function addFundTokenOptions(address[] memory tokens) private {
for (uint256 i = 0; i < tokens.length; i++) {
_fundTokenAddresses.add(tokens[i]);
}
}
}
文件 5 的 7: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);
}
文件 6 的 7:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 7 的 7:TransferHelper.sol
pragma solidity >=0.6.0;
library TransferHelper {
function safeApprove(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::safeApprove: approve failed'
);
}
function safeTransfer(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::safeTransfer: transfer failed'
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::transferFrom: transferFrom failed'
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
}
}
{
"compilationTarget": {
"contracts/FjordLbpProxyV6.sol": "FjordLbpProxyV6"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": [],
"viaIR": true
}
[{"inputs":[{"internalType":"uint256","name":"_platformAccessFeeBPS","type":"uint256"},{"internalType":"address","name":"_LBPFactoryAddress","type":"address"},{"internalType":"address","name":"_WeightedPoolFactoryAddress","type":"address"},{"internalType":"address","name":"_vaultAddress","type":"address"},{"internalType":"address[]","name":"fundTokenAddresses","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"endWeights","type":"uint256[]"}],"name":"GradualWeightUpdateScheduled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"address[]","name":"tokens","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"bytes","name":"userData","type":"bytes"}],"name":"JoinedPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"address[]","name":"tokens","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"bytes","name":"userData","type":"bytes"}],"name":"JoinedWeightedPool","type":"event"},{"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":true,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"bytes32","name":"poolId","type":"bytes32"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"address[]","name":"tokens","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"weights","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"swapFeePercentage","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"bool","name":"swapEnabledOnStart","type":"bool"},{"indexed":false,"internalType":"enum LBPType","name":"lbpType","type":"uint8"}],"name":"PoolCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"recipients","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"recipientShareBPS","type":"uint256[]"}],"name":"RecipientsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"}],"name":"Skimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"bool","name":"swapEnabled","type":"bool"}],"name":"SwapEnabledSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"feeRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"TransferredFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"TransferredPoolOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferredToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"bytes32","name":"poolId","type":"bytes32"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"address[]","name":"tokens","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"weights","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"swapFeePercentage","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"WeightedPoolCreated","type":"event"},{"inputs":[],"name":"LBPFactoryAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VaultAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WeightedPoolFactoryAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowedFundTokens","outputs":[{"internalType":"address[]","name":"fundTokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blockListAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"weights","type":"uint256[]"},{"internalType":"uint256[]","name":"endWeights","type":"uint256[]"},{"internalType":"uint256","name":"swapFeePercentage","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"internalType":"struct PoolConfig","name":"poolConfig","type":"tuple"}],"name":"createLBP","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lbpPool","type":"address"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"weights","type":"uint256[]"},{"internalType":"uint256","name":"swapFeePercentage","type":"uint256"}],"internalType":"struct WeightedPoolConfig","name":"weightedPoolConfig","type":"tuple"}],"name":"createWeightedPoolForLBP","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"maxBPTTokenOut","type":"uint256"},{"internalType":"bool","name":"isStandardFee","type":"bool"}],"name":"exitPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"getBPTTokenBalance","outputs":[{"internalType":"uint256","name":"bptBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeeRecipients","outputs":[{"internalType":"address[]","name":"recipients","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getPoolAt","outputs":[{"internalType":"address","name":"pool","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"getPoolData","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"fundTokenInputAmount","type":"uint256"},{"internalType":"enum LBPType","name":"lbpType","type":"uint8"},{"internalType":"address","name":"weightedPoolAddress","type":"address"}],"internalType":"struct PoolData","name":"poolData","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPools","outputs":[{"internalType":"address[]","name":"pools","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipientAddress","type":"address"}],"name":"getRecipientShareBPS","outputs":[{"internalType":"uint256","name":"shareSize","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWeightedPools","outputs":[{"internalType":"address[]","name":"pools","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"weightedPool","type":"address"}],"name":"getWeightedTokenBalance","outputs":[{"internalType":"uint256","name":"weightedBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"isAllowedFund","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"isPool","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"isWeightedPool","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lbpType","outputs":[{"internalType":"enum LBPType","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformAccessFeeBPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolCount","outputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"bool","name":"swapEnabled","type":"bool"}],"name":"setSwapEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"skim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferPoolOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"updateBlocklistAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"recipientShareBPS","type":"uint256[]"}],"name":"updateRecipients","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weightedPoolCount","outputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"stateMutability":"view","type":"function"}]