diff --git a/brownie/world_base.py b/brownie/world_base.py index 5e2c1614cc..505b5c0262 100644 --- a/brownie/world_base.py +++ b/brownie/world_base.py @@ -23,6 +23,7 @@ aero_helper = load_contract('aerodrome_slipstream_sugar_helper', AERODROME_SUGAR_HELPER_BASE) amo_pool = load_contract('aerodrome_slipstream_pool', AERODROME_WETH_OETHB_POOL_BASE) curve_pool = load_contract('curve_pool_base', CURVE_POOL_BASE) +base_curve_amo_strat = load_contract('ousd_curve_amo_strat', OETHB_CURVE_AMO_STRATEGY) aerodrome_voter = load_contract('aerodrome_voter', AERO_VOTER_BASE) diff --git a/contracts/deploy/base/049_permissioned_rebase_module.js b/contracts/deploy/base/049_permissioned_rebase_module.js index 447daa1930..25cf8a0834 100644 --- a/contracts/deploy/base/049_permissioned_rebase_module.js +++ b/contracts/deploy/base/049_permissioned_rebase_module.js @@ -12,11 +12,12 @@ module.exports = deployOnBase( const cOETHBaseVaultProxy = await ethers.getContract("OETHBaseVaultProxy"); - await deployWithConfirmation("PermissionedRebaseModule", [ - safeAddress, - addresses.permissionedRebaseRelayer, - [cOETHBaseVaultProxy.address], - ]); + await deployWithConfirmation( + "PermissionedRebaseModule", + [safeAddress, addresses.talosRelayer, [cOETHBaseVaultProxy.address]], + undefined, + true + ); const cPermissionedRebaseModule = await ethers.getContract( "PermissionedRebaseModule" ); diff --git a/contracts/deploy/base/049_vault_permissioned_rebase.js b/contracts/deploy/base/050_vault_permissioned_rebase.js similarity index 91% rename from contracts/deploy/base/049_vault_permissioned_rebase.js rename to contracts/deploy/base/050_vault_permissioned_rebase.js index b13876c61b..73e23009e1 100644 --- a/contracts/deploy/base/049_vault_permissioned_rebase.js +++ b/contracts/deploy/base/050_vault_permissioned_rebase.js @@ -4,7 +4,7 @@ const addresses = require("../../utils/addresses"); module.exports = deployOnBase( { - deployName: "049_vault_permissioned_rebase", + deployName: "050_vault_permissioned_rebase", }, async ({ ethers }) => { // 1. Deploy new OETHBaseVault implementation @@ -32,7 +32,7 @@ module.exports = deployOnBase( { contract: cOETHbVault, signature: "setOperatorAddr(address)", - args: [addresses.multichainStrategist], + args: [addresses.talosRelayer], }, ], }; diff --git a/contracts/deploy/mainnet/193_permissioned_rebase_module.js b/contracts/deploy/mainnet/193_permissioned_rebase_module.js index 025b25a099..28c2f10e95 100644 --- a/contracts/deploy/mainnet/193_permissioned_rebase_module.js +++ b/contracts/deploy/mainnet/193_permissioned_rebase_module.js @@ -20,7 +20,7 @@ module.exports = deploymentWithGovernanceProposal( await deployWithConfirmation("PermissionedRebaseModule", [ safeAddress, - addresses.permissionedRebaseRelayer, + addresses.talosRelayer, [cVaultProxy.address, cOETHVaultProxy.address], ]); const cPermissionedRebaseModule = await ethers.getContract( diff --git a/contracts/deploy/mainnet/193_vault_permissioned_rebase.js b/contracts/deploy/mainnet/194_vault_permissioned_rebase.js similarity index 72% rename from contracts/deploy/mainnet/193_vault_permissioned_rebase.js rename to contracts/deploy/mainnet/194_vault_permissioned_rebase.js index 5cadb13099..9fb7078811 100644 --- a/contracts/deploy/mainnet/193_vault_permissioned_rebase.js +++ b/contracts/deploy/mainnet/194_vault_permissioned_rebase.js @@ -3,22 +3,29 @@ const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { - deployName: "193_vault_permissioned_rebase", + deployName: "194_vault_permissioned_rebase", forceDeploy: false, reduceQueueTime: true, deployerIsProposer: false, - proposalId: "", + proposalId: + "9948092462276445509780797495205471799644905864792185620552351889756709358003", }, async ({ deployWithConfirmation }) => { // 1. Deploy new OUSD Vault implementation - const dOUSDVault = await deployWithConfirmation("OUSDVault", [ - addresses.mainnet.USDC, - ]); + const dOUSDVault = await deployWithConfirmation( + "OUSDVault", + [addresses.mainnet.USDC], + undefined, + true + ); // 2. Deploy new OETH Vault implementation - const dOETHVault = await deployWithConfirmation("OETHVault", [ - addresses.mainnet.WETH, - ]); + const dOETHVault = await deployWithConfirmation( + "OETHVault", + [addresses.mainnet.WETH], + undefined, + true + ); const cVaultProxy = await ethers.getContract("VaultProxy"); const cOUSDVault = await ethers.getContractAt( @@ -43,7 +50,7 @@ module.exports = deploymentWithGovernanceProposal( { contract: cOUSDVault, signature: "setOperatorAddr(address)", - args: [addresses.multichainStrategist], + args: [addresses.talosRelayer], }, { contract: cOETHVaultProxy, @@ -53,7 +60,7 @@ module.exports = deploymentWithGovernanceProposal( { contract: cOETHVault, signature: "setOperatorAddr(address)", - args: [addresses.multichainStrategist], + args: [addresses.talosRelayer], }, ], }; diff --git a/contracts/deploy/sonic/028_permissioned_rebase_module.js b/contracts/deploy/sonic/028_permissioned_rebase_module.js index b58e299760..9e148f72f7 100644 --- a/contracts/deploy/sonic/028_permissioned_rebase_module.js +++ b/contracts/deploy/sonic/028_permissioned_rebase_module.js @@ -14,7 +14,7 @@ module.exports = deployOnSonic( await deployWithConfirmation("PermissionedRebaseModule", [ safeAddress, - addresses.permissionedRebaseRelayer, + addresses.talosRelayer, [cOSonicVaultProxy.address], ]); const cPermissionedRebaseModule = await ethers.getContract( diff --git a/contracts/deploy/sonic/028_vault_permissioned_rebase.js b/contracts/deploy/sonic/029_vault_permissioned_rebase.js similarity index 91% rename from contracts/deploy/sonic/028_vault_permissioned_rebase.js rename to contracts/deploy/sonic/029_vault_permissioned_rebase.js index 935daacc6f..6e6d8f7a8d 100644 --- a/contracts/deploy/sonic/028_vault_permissioned_rebase.js +++ b/contracts/deploy/sonic/029_vault_permissioned_rebase.js @@ -4,7 +4,7 @@ const addresses = require("../../utils/addresses"); module.exports = deployOnSonic( { - deployName: "028_vault_permissioned_rebase", + deployName: "029_vault_permissioned_rebase", }, async ({ ethers }) => { // 1. Deploy new OSVault implementation @@ -32,7 +32,7 @@ module.exports = deployOnSonic( { contract: cOSonicVault, signature: "setOperatorAddr(address)", - args: [addresses.sonic.guardian], + args: [addresses.talosRelayer], }, ], }; diff --git a/contracts/deployments/base/.migrations.json b/contracts/deployments/base/.migrations.json index 848f8130ad..ca14613d2f 100644 --- a/contracts/deployments/base/.migrations.json +++ b/contracts/deployments/base/.migrations.json @@ -46,5 +46,6 @@ "046_crosschain_upgrade_remote": 1772750064, "047_merkl_pb_bribes_module": 1773930124, "048_oethb_hydrex_amo": 1778063838, - "049_permissioned_rebase_module": 1778095983 + "049_permissioned_rebase_module": 1778095983, + "050_vault_permissioned_rebase": 1778496613 } \ No newline at end of file diff --git a/contracts/deployments/base/OETHBaseVault.json b/contracts/deployments/base/OETHBaseVault.json index 3189f51d91..ff10365a7b 100644 --- a/contracts/deployments/base/OETHBaseVault.json +++ b/contracts/deployments/base/OETHBaseVault.json @@ -1,5 +1,5 @@ { - "address": "0xAe9A68E82e76caa35F8ac3f4e494cdb7438BBac1", + "address": "0xfdBE6A80e1D22ff652Cbff44FEaD2E52287393E8", "abi": [ { "inputs": [ @@ -139,6 +139,19 @@ "name": "Mint", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newOperator", + "type": "address" + } + ], + "name": "OperatorUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -177,19 +190,6 @@ "name": "RebasePerSecondMaxChanged", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "_threshold", - "type": "uint256" - } - ], - "name": "RebaseThresholdUpdated", - "type": "event" - }, { "anonymous": false, "inputs": [], @@ -872,6 +872,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "operatorAddr", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "pauseCapital", @@ -945,19 +958,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "rebaseThreshold", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -1063,12 +1063,12 @@ { "inputs": [ { - "internalType": "uint256", - "name": "apr", - "type": "uint256" + "internalType": "address", + "name": "_operator", + "type": "address" } ], - "name": "setRebaseRateMax", + "name": "setOperatorAddr", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -1077,11 +1077,11 @@ "inputs": [ { "internalType": "uint256", - "name": "_threshold", + "name": "apr", "type": "uint256" } ], - "name": "setRebaseThreshold", + "name": "setRebaseRateMax", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -1409,30 +1409,30 @@ "type": "function" } ], - "transactionHash": "0xe8606d7fb092403445632564e20857792913df242834cfdefa081b0f251eb11f", + "transactionHash": "0x32b83e5d4c0431e6504a9af71bc5f69a6c04e1eec660965db7d009c220e633de", "receipt": { "to": null, - "from": "0x074105fdD39e982B2ffE749A193c942db1046AB9", - "contractAddress": "0xAe9A68E82e76caa35F8ac3f4e494cdb7438BBac1", - "transactionIndex": 218, - "gasUsed": "4593636", + "from": "0x58890A9cB27586E83Cb51d2d26bbE18a1a647245", + "contractAddress": "0xfdBE6A80e1D22ff652Cbff44FEaD2E52287393E8", + "transactionIndex": 77, + "gasUsed": "4587393", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x736fbb0ad48372b04b5ae92e03d62ef5fcd4624b28be39e7ea7c1a27b5d6e580", - "transactionHash": "0xe8606d7fb092403445632564e20857792913df242834cfdefa081b0f251eb11f", + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x32b83e5d4c0431e6504a9af71bc5f69a6c04e1eec660965db7d009c220e633de", "logs": [], - "blockNumber": 42610737, - "cumulativeGasUsed": "56601567", + "blockNumber": 45853614, + "cumulativeGasUsed": "18238571", "status": 1, "byzantium": true }, "args": [ "0x4200000000000000000000000000000000000006" ], - "numDeployments": 1, - "solcInputHash": "2618dd94434f6485d501dca95587ea12", - "metadata": "{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"AllocateThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"AssetAllocated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"DefaultStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dripDuration\",\"type\":\"uint256\"}],\"name\":\"DripDurationChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"MaxSupplyDiffChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebasePaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rebaseRatePerSecond\",\"type\":\"uint256\"}],\"name\":\"RebasePerSecondMaxChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"RebaseThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebaseUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"StrategistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyAddedToMintWhitelist\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyRemovedFromMintWhitelist\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"TrusteeAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"TrusteeFeeBpsChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"VaultBufferUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newDelay\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_claimable\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newClaimable\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimable\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_queued\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_yield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"YieldDistribution\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddr\",\"type\":\"address\"}],\"name\":\"addStrategyToMintWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"addWithdrawalQueueLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"allocate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"approveStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"asset\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"autoAllocateThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"burnForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capitalPaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"claimWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_requestIds\",\"type\":\"uint256[]\"}],\"name\":\"claimWithdrawals\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"totalAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultStrategy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyToAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"depositToStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dripDuration\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAssets\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllStrategies\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAssetCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStrategyCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_oToken\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isMintWhitelistedStrategy\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"isSupportedAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRebase\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxSupplyDiff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mintForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oToken\",\"outputs\":[{\"internalType\":\"contract OUSD\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oUSD\",\"outputs\":[{\"internalType\":\"contract OUSD\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previewYield\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"yield\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePerSecondMax\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePerSecondTarget\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebaseThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"removeStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddr\",\"type\":\"address\"}],\"name\":\"removeStrategyFromMintWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"requestWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"queued\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setAutoAllocateThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"setDefaultStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dripDuration\",\"type\":\"uint256\"}],\"name\":\"setDripDuration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"setMaxSupplyDiff\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"apr\",\"type\":\"uint256\"}],\"name\":\"setRebaseRateMax\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setRebaseThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setStrategistAddr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setTrusteeAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"setTrusteeFeeBps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"setVaultBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_delay\",\"type\":\"uint256\"}],\"name\":\"setWithdrawalClaimDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"strategies\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isSupported\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"_deprecated\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategistAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"transferToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAllFromStrategies\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"}],\"name\":\"withdrawAllFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyFromAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"withdrawFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalClaimDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalQueueMetadata\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimable\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimed\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"nextWithdrawalIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"withdrawalRequests\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"claimed\",\"type\":\"bool\"},{\"internalType\":\"uint40\",\"name\":\"timestamp\",\"type\":\"uint40\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"addStrategyToMintWhitelist(address)\":{\"params\":{\"strategyAddr\":\"Strategy address\"}},\"addWithdrawalQueueLiquidity()\":{\"details\":\"is called from the Native Staking strategy when validator withdrawals are processed. It also called before any WETH is allocated to a strategy.\"},\"approveStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to add\"}},\"burnForStrategy(uint256)\":{\"details\":\"Notice: can't use `nonReentrant` modifier since the `redeem` function could require withdrawal on an AMO strategy and that one can call `burnForStrategy` while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\",\"params\":{\"_amount\":\"Amount of OToken to burn\"}},\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of asset\"},\"returns\":{\"_0\":\"uint256 Balance of asset in decimals of asset\"}},\"claimWithdrawal(uint256)\":{\"params\":{\"_requestId\":\"Unique ID for the withdrawal request\"},\"returns\":{\"amount\":\"Amount of asset transferred to the withdrawer\"}},\"claimWithdrawals(uint256[])\":{\"params\":{\"_requestIds\":\"Unique ID of each withdrawal request\"},\"returns\":{\"amounts\":\"Amount of asset received for each request\",\"totalAmount\":\"Total amount of asset transferred to the withdrawer\"}},\"depositToStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to deposit.\",\"_assets\":\"Array of asset address that will be deposited into the strategy.\",\"_strategyToAddress\":\"Address of the Strategy to deposit asset into.\"}},\"isSupportedAsset(address)\":{\"params\":{\"_asset\":\"address of the asset\"},\"returns\":{\"_0\":\"true if supported\"}},\"mint(address,uint256,uint256)\":{\"details\":\"Deprecated: use `mint(uint256 _amount)` instead.Deprecated: param _asset Address of the asset being depositedDeprecated: param _minimumOusdAmount Minimum OTokens to mint\",\"params\":{\"_amount\":\"Amount of the asset being deposited\"}},\"mint(uint256)\":{\"params\":{\"_amount\":\"Amount of the asset being deposited\"}},\"mintForStrategy(uint256)\":{\"params\":{\"_amount\":\"Amount of OToken to mint Notice: can't use `nonReentrant` modifier since the `mint` function can call `allocate`, and that can trigger an AMO strategy to call this function while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\"}},\"previewYield()\":{\"returns\":{\"yield\":\"amount of expected yield\"}},\"removeStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to remove\"}},\"removeStrategyFromMintWhitelist(address)\":{\"params\":{\"strategyAddr\":\"Strategy address\"}},\"requestWithdrawal(uint256)\":{\"params\":{\"_amount\":\"Amount of OToken to burn.\"},\"returns\":{\"queued\":\"Cumulative total of all asset queued including already claimed requests.\",\"requestId\":\"Unique ID for the withdrawal request\"}},\"setAutoAllocateThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setDefaultStrategy(address)\":{\"params\":{\"_strategy\":\"Address of the Strategy\"}},\"setDripDuration(uint256)\":{\"params\":{\"_dripDuration\":\"Time in seconds to target a constant yield rate\"}},\"setRebaseRateMax(uint256)\":{\"params\":{\"apr\":\"in 1e18 notation. 3 * 1e18 = 3% APR\"}},\"setRebaseThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setStrategistAddr(address)\":{\"params\":{\"_address\":\"Address of Strategist\"}},\"setVaultBuffer(uint256)\":{\"params\":{\"_vaultBuffer\":\"Percentage using 18 decimals. 100% = 1e18.\"}},\"setWithdrawalClaimDelay(uint256)\":{\"params\":{\"_delay\":\"Delay period (should be between 10 mins to 7 days). Set to 0 to disable async withdrawals\"}},\"totalValue()\":{\"returns\":{\"value\":\"Total value in USD/ETH (1e18)\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"transferToken(address,uint256)\":{\"params\":{\"_amount\":\"Amount of the asset to transfer\",\"_asset\":\"Address for the asset\"}},\"withdrawAllFromStrategy(address)\":{\"params\":{\"_strategyAddr\":\"Strategy address.\"}},\"withdrawFromStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to withdraw.\",\"_assets\":\"Array of asset address that will be withdrawn from the strategy.\",\"_strategyFromAddress\":\"Address of the Strategy to withdraw asset from.\"}}},\"title\":\"OETH Base VaultAdmin Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"addStrategyToMintWhitelist(address)\":{\"notice\":\"Adds a strategy to the mint whitelist. Reverts if strategy isn't approved on Vault.\"},\"addWithdrawalQueueLiquidity()\":{\"notice\":\"Adds WETH to the withdrawal queue if there is a funding shortfall.\"},\"allocate()\":{\"notice\":\"Allocate unallocated funds on Vault to strategies.\"},\"approveStrategy(address)\":{\"notice\":\"Add a strategy to the Vault.\"},\"autoAllocateThreshold()\":{\"notice\":\"OToken mints over this amount automatically allocate funds. 18 decimals.\"},\"burnForStrategy(uint256)\":{\"notice\":\"Burn OTokens for an allowed Strategy\"},\"capitalPaused()\":{\"notice\":\"pause operations that change the OToken supply. eg mint, redeem, allocate, mint/burn for strategy\"},\"checkBalance(address)\":{\"notice\":\"Get the balance of an asset held in Vault and all strategies.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"claimWithdrawal(uint256)\":{\"notice\":\"Claim a previously requested withdrawal once it is claimable. This request can be claimed once the withdrawal queue's `claimable` amount is greater than or equal this request's `queued` amount and 10 minutes has passed. If the requests is not claimable, the transaction will revert with `Queue pending liquidity`. If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`. OToken is converted to asset at 1:1.\"},\"claimWithdrawals(uint256[])\":{\"notice\":\"Claim a previously requested withdrawals once they are claimable. This requests can be claimed once the withdrawal queue's `claimable` amount is greater than or equal each request's `queued` amount and 10 minutes has passed. If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`. If one of the requests is not older than 10 minutes, the whole transaction will revert with `Claim delay not met`.\"},\"defaultStrategy()\":{\"notice\":\"Default strategy for asset\"},\"depositToStrategy(address,address[],uint256[])\":{\"notice\":\"Deposit multiple asset from the vault into the strategy.\"},\"dripDuration()\":{\"notice\":\"Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\"},\"getAllAssets()\":{\"notice\":\"Return all vault asset addresses in order\"},\"getAllStrategies()\":{\"notice\":\"Return the array of all strategies\"},\"getAssetCount()\":{\"notice\":\"Return the number of asset supported by the Vault.\"},\"getStrategyCount()\":{\"notice\":\"Return the number of strategies active on the Vault.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"isSupportedAsset(address)\":{\"notice\":\"Returns whether the vault supports the asset\"},\"lastRebase()\":{\"notice\":\"Time in seconds that the vault last rebased yield.\"},\"maxSupplyDiff()\":{\"notice\":\"Max difference between total supply and total value of assets. 18 decimals.\"},\"mint(address,uint256,uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mint(uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mintForStrategy(uint256)\":{\"notice\":\"Mint OTokens for an allowed Strategy\"},\"oUSD()\":{\"notice\":\"Deprecated: use `oToken()` instead.\"},\"pauseCapital()\":{\"notice\":\"Set the deposit paused flag to true to prevent capital movement.\"},\"pauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to prevent rebasing.\"},\"previewYield()\":{\"notice\":\"Calculates the amount that would rebase at next rebase. This is before any fees.\"},\"rebase()\":{\"notice\":\"Calculate the total value of asset held by the Vault and all strategies and update the supply of OTokens.\"},\"rebasePaused()\":{\"notice\":\"pause rebasing if true\"},\"rebasePerSecondMax()\":{\"notice\":\"max rebase percentage per second Can be used to set maximum yield of the protocol, spreading out yield over time\"},\"rebasePerSecondTarget()\":{\"notice\":\"target rebase rate limit, based on past rates and funds available.\"},\"rebaseThreshold()\":{\"notice\":\"OToken mints over this amount automatically rebase. 18 decimals.\"},\"removeStrategy(address)\":{\"notice\":\"Remove a strategy from the Vault.\"},\"removeStrategyFromMintWhitelist(address)\":{\"notice\":\"Removes a strategy from the mint whitelist.\"},\"requestWithdrawal(uint256)\":{\"notice\":\"Request an asynchronous withdrawal of asset in exchange for OToken. The OToken is burned on request and the asset is transferred to the withdrawer on claim. This request can be claimed once the withdrawal queue's `claimable` amount is greater than or equal this request's `queued` amount. There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue. OToken is converted to asset at 1:1.\"},\"setAutoAllocateThreshold(uint256)\":{\"notice\":\"Sets the minimum amount of OTokens in a mint to trigger an automatic allocation of funds afterwords.\"},\"setDefaultStrategy(address)\":{\"notice\":\"Set the default Strategy for asset, i.e. the one which the asset will be automatically allocated to and withdrawn from\"},\"setDripDuration(uint256)\":{\"notice\":\"Set the drip duration period\"},\"setMaxSupplyDiff(uint256)\":{\"notice\":\"Sets the maximum allowable difference between total supply and asset' value.\"},\"setRebaseRateMax(uint256)\":{\"notice\":\"Set a yield streaming max rate. This spreads yield over time if it is above the max rate. This is a per rebase APR which due to compounding differs from the yearly APR. Governance should consider this fact when picking a desired APR\"},\"setRebaseThreshold(uint256)\":{\"notice\":\"Set a minimum amount of OTokens in a mint or redeem that triggers a rebase\"},\"setStrategistAddr(address)\":{\"notice\":\"Set address of Strategist\"},\"setTrusteeAddress(address)\":{\"notice\":\"Sets the trusteeAddress that can receive a portion of yield. Setting to the zero address disables this feature.\"},\"setTrusteeFeeBps(uint256)\":{\"notice\":\"Sets the TrusteeFeeBps to the percentage of yield that should be received in basis points.\"},\"setVaultBuffer(uint256)\":{\"notice\":\"Set a buffer of asset to keep in the Vault to handle most redemptions without needing to spend gas unwinding asset from a Strategy.\"},\"setWithdrawalClaimDelay(uint256)\":{\"notice\":\"Changes the async withdrawal claim period for OETH & superOETHb\"},\"strategistAddr()\":{\"notice\":\"Address of the Strategist\"},\"totalValue()\":{\"notice\":\"Determine the total value of asset held by the vault and its strategies.\"},\"transferGovernance(address)\":{\"notice\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\"},\"transferToken(address,uint256)\":{\"notice\":\"Transfer token to governor. Intended for recovering tokens stuck in contract, i.e. mistaken sends.\"},\"trusteeAddress()\":{\"notice\":\"Trustee contract that can collect a percentage of yield\"},\"trusteeFeeBps()\":{\"notice\":\"Amount of yield collected in basis points. eg 2000 = 20%\"},\"unpauseCapital()\":{\"notice\":\"Set the deposit paused flag to false to enable capital movement.\"},\"unpauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to allow rebasing.\"},\"vaultBuffer()\":{\"notice\":\"Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\"},\"withdrawAllFromStrategies()\":{\"notice\":\"Withdraws all asset from all the strategies and sends asset to the Vault.\"},\"withdrawAllFromStrategy(address)\":{\"notice\":\"Withdraws all asset from the strategy and sends asset to the Vault.\"},\"withdrawFromStrategy(address,address[],uint256[])\":{\"notice\":\"Withdraw multiple asset from the strategy to the vault.\"},\"withdrawalClaimDelay()\":{\"notice\":\"Sets a minimum delay that is required to elapse between requesting async withdrawals and claiming the request. When set to 0 async withdrawals are disabled.\"},\"withdrawalQueueMetadata()\":{\"notice\":\"Global metadata for the withdrawal queue including: queued - cumulative total of all withdrawal requests included the ones that have already been claimed claimable - cumulative total of all the requests that can be claimed including the ones already claimed claimed - total of all the requests that have been claimed nextWithdrawalIndex - index of the next withdrawal request starting at 0\"},\"withdrawalRequests(uint256)\":{\"notice\":\"Mapping of withdrawal request indices to the user withdrawal request data\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/vault/OETHBaseVault.sol\":\"OETHBaseVault\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0x61437cb513a887a1bbad006e7b1c8b414478427d33de47c5600af3c748f108da\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeCast.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\\n * checks.\\n *\\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\\n * easily result in undesired exploitation or bugs, since developers usually\\n * assume that overflows raise errors. `SafeCast` restores this intuition by\\n * reverting the transaction when such an operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n *\\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\\n * all math on `uint256` and `int256` and then downcasting.\\n */\\nlibrary SafeCast {\\n /**\\n * @dev Returns the downcasted uint224 from uint256, reverting on\\n * overflow (when the input is greater than largest uint224).\\n *\\n * Counterpart to Solidity's `uint224` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 224 bits\\n */\\n function toUint224(uint256 value) internal pure returns (uint224) {\\n require(value <= type(uint224).max, \\\"SafeCast: value doesn't fit in 224 bits\\\");\\n return uint224(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint128 from uint256, reverting on\\n * overflow (when the input is greater than largest uint128).\\n *\\n * Counterpart to Solidity's `uint128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n */\\n function toUint128(uint256 value) internal pure returns (uint128) {\\n require(value <= type(uint128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return uint128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint96 from uint256, reverting on\\n * overflow (when the input is greater than largest uint96).\\n *\\n * Counterpart to Solidity's `uint96` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 96 bits\\n */\\n function toUint96(uint256 value) internal pure returns (uint96) {\\n require(value <= type(uint96).max, \\\"SafeCast: value doesn't fit in 96 bits\\\");\\n return uint96(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint64 from uint256, reverting on\\n * overflow (when the input is greater than largest uint64).\\n *\\n * Counterpart to Solidity's `uint64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n */\\n function toUint64(uint256 value) internal pure returns (uint64) {\\n require(value <= type(uint64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return uint64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint32 from uint256, reverting on\\n * overflow (when the input is greater than largest uint32).\\n *\\n * Counterpart to Solidity's `uint32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n */\\n function toUint32(uint256 value) internal pure returns (uint32) {\\n require(value <= type(uint32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return uint32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint16 from uint256, reverting on\\n * overflow (when the input is greater than largest uint16).\\n *\\n * Counterpart to Solidity's `uint16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n */\\n function toUint16(uint256 value) internal pure returns (uint16) {\\n require(value <= type(uint16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return uint16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint8 from uint256, reverting on\\n * overflow (when the input is greater than largest uint8).\\n *\\n * Counterpart to Solidity's `uint8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits.\\n */\\n function toUint8(uint256 value) internal pure returns (uint8) {\\n require(value <= type(uint8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return uint8(value);\\n }\\n\\n /**\\n * @dev Converts a signed int256 into an unsigned uint256.\\n *\\n * Requirements:\\n *\\n * - input must be greater than or equal to 0.\\n */\\n function toUint256(int256 value) internal pure returns (uint256) {\\n require(value >= 0, \\\"SafeCast: value must be positive\\\");\\n return uint256(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int128 from int256, reverting on\\n * overflow (when the input is less than smallest int128 or\\n * greater than largest int128).\\n *\\n * Counterpart to Solidity's `int128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt128(int256 value) internal pure returns (int128) {\\n require(value >= type(int128).min && value <= type(int128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return int128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int64 from int256, reverting on\\n * overflow (when the input is less than smallest int64 or\\n * greater than largest int64).\\n *\\n * Counterpart to Solidity's `int64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt64(int256 value) internal pure returns (int64) {\\n require(value >= type(int64).min && value <= type(int64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return int64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int32 from int256, reverting on\\n * overflow (when the input is less than smallest int32 or\\n * greater than largest int32).\\n *\\n * Counterpart to Solidity's `int32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt32(int256 value) internal pure returns (int32) {\\n require(value >= type(int32).min && value <= type(int32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return int32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int16 from int256, reverting on\\n * overflow (when the input is less than smallest int16 or\\n * greater than largest int16).\\n *\\n * Counterpart to Solidity's `int16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt16(int256 value) internal pure returns (int16) {\\n require(value >= type(int16).min && value <= type(int16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return int16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int8 from int256, reverting on\\n * overflow (when the input is less than smallest int8 or\\n * greater than largest int8).\\n *\\n * Counterpart to Solidity's `int8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits.\\n *\\n * _Available since v3.1._\\n */\\n function toInt8(int256 value) internal pure returns (int8) {\\n require(value >= type(int8).min && value <= type(int8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return int8(value);\\n }\\n\\n /**\\n * @dev Converts an unsigned uint256 into a signed int256.\\n *\\n * Requirements:\\n *\\n * - input must be less than or equal to maxInt256.\\n */\\n function toInt256(uint256 value) internal pure returns (int256) {\\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\\n require(value <= uint256(type(int256).max), \\\"SafeCast: value doesn't fit in an int256\\\");\\n return int256(value);\\n }\\n}\\n\",\"keccak256\":\"0x5c6caab697d302ad7eb59c234a4d2dbc965c1bae87709bd2850060b7695b28c7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa2f576be637946f767aa56601c26d717f48a0aff44f82e46f13807eea1009a21\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @notice Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @notice Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n emit GovernorshipTransferred(_governor(), newGovernor);\\n\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0xf32f873c8bfbacf2e5f01d0cf37bc7f54fbd5aa656e95c8a599114229946f107\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xa562062698aa12572123b36dfd2072f1a39e44fed2031cc19c2c9fd522f96ec2\",\"license\":\"MIT\"},\"contracts/interfaces/IStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\\n */\\ninterface IStrategy {\\n /**\\n * @dev Deposit the given asset to platform\\n * @param _asset asset address\\n * @param _amount Amount to deposit\\n */\\n function deposit(address _asset, uint256 _amount) external;\\n\\n /**\\n * @dev Deposit the entire balance of all supported assets in the Strategy\\n * to the platform\\n */\\n function depositAll() external;\\n\\n /**\\n * @dev Withdraw given asset from Lending platform\\n */\\n function withdraw(\\n address _recipient,\\n address _asset,\\n uint256 _amount\\n ) external;\\n\\n /**\\n * @dev Liquidate all assets in strategy and return them to Vault.\\n */\\n function withdrawAll() external;\\n\\n /**\\n * @dev Returns the current balance of the given asset.\\n */\\n function checkBalance(address _asset)\\n external\\n view\\n returns (uint256 balance);\\n\\n /**\\n * @dev Returns bool indicating whether strategy supports asset.\\n */\\n function supportsAsset(address _asset) external view returns (bool);\\n\\n /**\\n * @dev Collect reward tokens from the Strategy.\\n */\\n function collectRewardTokens() external;\\n\\n /**\\n * @dev The address array of the reward tokens for the Strategy.\\n */\\n function getRewardTokenAddresses() external view returns (address[] memory);\\n\\n function harvesterAddress() external view returns (address);\\n\\n function transferToken(address token, uint256 amount) external;\\n\\n function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\\n external;\\n}\\n\",\"keccak256\":\"0x79ca47defb3b5a56bba13f14c440838152fd1c1aa640476154516a16da4da8ba\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/IVault.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { VaultStorage } from \\\"../vault/VaultStorage.sol\\\";\\n\\ninterface IVault {\\n // slither-disable-start constable-states\\n\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event DefaultStrategyUpdated(address _strategy);\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\\n event DripDurationChanged(uint256 dripDuration);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\\n\\n // Governable.sol\\n function transferGovernance(address _newGovernor) external;\\n\\n function claimGovernance() external;\\n\\n function governor() external view returns (address);\\n\\n // VaultAdmin.sol\\n function setVaultBuffer(uint256 _vaultBuffer) external;\\n\\n function vaultBuffer() external view returns (uint256);\\n\\n function setAutoAllocateThreshold(uint256 _threshold) external;\\n\\n function autoAllocateThreshold() external view returns (uint256);\\n\\n function setRebaseThreshold(uint256 _threshold) external;\\n\\n function rebaseThreshold() external view returns (uint256);\\n\\n function setStrategistAddr(address _address) external;\\n\\n function strategistAddr() external view returns (address);\\n\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\\n\\n function maxSupplyDiff() external view returns (uint256);\\n\\n function setTrusteeAddress(address _address) external;\\n\\n function trusteeAddress() external view returns (address);\\n\\n function setTrusteeFeeBps(uint256 _basis) external;\\n\\n function trusteeFeeBps() external view returns (uint256);\\n\\n function approveStrategy(address _addr) external;\\n\\n function removeStrategy(address _addr) external;\\n\\n function setDefaultStrategy(address _strategy) external;\\n\\n function defaultStrategy() external view returns (address);\\n\\n function pauseRebase() external;\\n\\n function unpauseRebase() external;\\n\\n function rebasePaused() external view returns (bool);\\n\\n function pauseCapital() external;\\n\\n function unpauseCapital() external;\\n\\n function capitalPaused() external view returns (bool);\\n\\n function transferToken(address _asset, uint256 _amount) external;\\n\\n function withdrawAllFromStrategy(address _strategyAddr) external;\\n\\n function withdrawAllFromStrategies() external;\\n\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n // VaultCore.sol\\n function mint(uint256 _amount) external;\\n\\n function mintForStrategy(uint256 _amount) external;\\n\\n function burnForStrategy(uint256 _amount) external;\\n\\n function allocate() external;\\n\\n function rebase() external;\\n\\n function totalValue() external view returns (uint256 value);\\n\\n function checkBalance(address _asset) external view returns (uint256);\\n\\n function getAssetCount() external view returns (uint256);\\n\\n function getAllAssets() external view returns (address[] memory);\\n\\n function getStrategyCount() external view returns (uint256);\\n\\n function getAllStrategies() external view returns (address[] memory);\\n\\n /// @notice Deprecated.\\n function isSupportedAsset(address _asset) external view returns (bool);\\n\\n function asset() external view returns (address);\\n\\n function initialize(address) external;\\n\\n function addWithdrawalQueueLiquidity() external;\\n\\n function requestWithdrawal(uint256 _amount)\\n external\\n returns (uint256 requestId, uint256 queued);\\n\\n function claimWithdrawal(uint256 requestId)\\n external\\n returns (uint256 amount);\\n\\n function claimWithdrawals(uint256[] memory requestIds)\\n external\\n returns (uint256[] memory amounts, uint256 totalAmount);\\n\\n function withdrawalQueueMetadata()\\n external\\n view\\n returns (VaultStorage.WithdrawalQueueMetadata memory);\\n\\n function withdrawalRequests(uint256 requestId)\\n external\\n view\\n returns (VaultStorage.WithdrawalRequest memory);\\n\\n function addStrategyToMintWhitelist(address strategyAddr) external;\\n\\n function removeStrategyFromMintWhitelist(address strategyAddr) external;\\n\\n function isMintWhitelistedStrategy(address strategyAddr)\\n external\\n view\\n returns (bool);\\n\\n function withdrawalClaimDelay() external view returns (uint256);\\n\\n function setWithdrawalClaimDelay(uint256 newDelay) external;\\n\\n function lastRebase() external view returns (uint64);\\n\\n function dripDuration() external view returns (uint64);\\n\\n function setDripDuration(uint256 _dripDuration) external;\\n\\n function rebasePerSecondMax() external view returns (uint64);\\n\\n function setRebaseRateMax(uint256 yearlyApr) external;\\n\\n function rebasePerSecondTarget() external view returns (uint64);\\n\\n function previewYield() external view returns (uint256 yield);\\n\\n // slither-disable-end constable-states\\n}\\n\",\"keccak256\":\"0x5d42df4e6bf7c750a61ba0fba5e49c3b601205ff1f5bfd5b33de63febad89d70\",\"license\":\"BUSL-1.1\"},\"contracts/token/OUSD.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OUSD Token Contract\\n * @dev ERC20 compatible contract for OUSD\\n * @dev Implements an elastic supply\\n * @author Origin Protocol Inc\\n */\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\ncontract OUSD is Governable {\\n using SafeCast for int256;\\n using SafeCast for uint256;\\n\\n /// @dev Event triggered when the supply changes\\n /// @param totalSupply Updated token total supply\\n /// @param rebasingCredits Updated token rebasing credits\\n /// @param rebasingCreditsPerToken Updated token rebasing credits per token\\n event TotalSupplyUpdatedHighres(\\n uint256 totalSupply,\\n uint256 rebasingCredits,\\n uint256 rebasingCreditsPerToken\\n );\\n /// @dev Event triggered when an account opts in for rebasing\\n /// @param account Address of the account\\n event AccountRebasingEnabled(address account);\\n /// @dev Event triggered when an account opts out of rebasing\\n /// @param account Address of the account\\n event AccountRebasingDisabled(address account);\\n /// @dev Emitted when `value` tokens are moved from one account `from` to\\n /// another `to`.\\n /// @param from Address of the account tokens are moved from\\n /// @param to Address of the account tokens are moved to\\n /// @param value Amount of tokens transferred\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n /// @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n /// a call to {approve}. `value` is the new allowance.\\n /// @param owner Address of the owner approving allowance\\n /// @param spender Address of the spender allowance is granted to\\n /// @param value Amount of tokens spender can transfer\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 value\\n );\\n /// @dev Yield resulting from {changeSupply} that a `source` account would\\n /// receive is directed to `target` account.\\n /// @param source Address of the source forwarding the yield\\n /// @param target Address of the target receiving the yield\\n event YieldDelegated(address source, address target);\\n /// @dev Yield delegation from `source` account to the `target` account is\\n /// suspended.\\n /// @param source Address of the source suspending yield forwarding\\n /// @param target Address of the target no longer receiving yield from `source`\\n /// account\\n event YieldUndelegated(address source, address target);\\n\\n enum RebaseOptions {\\n NotSet,\\n StdNonRebasing,\\n StdRebasing,\\n YieldDelegationSource,\\n YieldDelegationTarget\\n }\\n\\n uint256[154] private _gap; // Slots to align with deployed contract\\n uint256 private constant MAX_SUPPLY = type(uint128).max;\\n /// @dev The amount of tokens in existence\\n uint256 public totalSupply;\\n mapping(address => mapping(address => uint256)) private allowances;\\n /// @dev The vault with privileges to execute {mint}, {burn}\\n /// and {changeSupply}\\n address public vaultAddress;\\n mapping(address => uint256) internal creditBalances;\\n // the 2 storage variables below need trailing underscores to not name collide with public functions\\n uint256 private rebasingCredits_; // Sum of all rebasing credits (creditBalances for rebasing accounts)\\n uint256 private rebasingCreditsPerToken_;\\n /// @dev The amount of tokens that are not rebasing - receiving yield\\n uint256 public nonRebasingSupply;\\n mapping(address => uint256) internal alternativeCreditsPerToken;\\n /// @dev A map of all addresses and their respective RebaseOptions\\n mapping(address => RebaseOptions) public rebaseState;\\n mapping(address => uint256) private __deprecated_isUpgraded;\\n /// @dev A map of addresses that have yields forwarded to. This is an\\n /// inverse mapping of {yieldFrom}\\n /// Key Account forwarding yield\\n /// Value Account receiving yield\\n mapping(address => address) public yieldTo;\\n /// @dev A map of addresses that are receiving the yield. This is an\\n /// inverse mapping of {yieldTo}\\n /// Key Account receiving yield\\n /// Value Account forwarding yield\\n mapping(address => address) public yieldFrom;\\n\\n uint256 private constant RESOLUTION_INCREASE = 1e9;\\n uint256[34] private __gap; // including below gap totals up to 200\\n\\n /// @dev Verifies that the caller is the Governor or Strategist.\\n modifier onlyGovernorOrStrategist() {\\n require(\\n isGovernor() || msg.sender == IVault(vaultAddress).strategistAddr(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n /// @dev Initializes the contract and sets necessary variables.\\n /// @param _vaultAddress Address of the vault contract\\n /// @param _initialCreditsPerToken The starting rebasing credits per token.\\n function initialize(address _vaultAddress, uint256 _initialCreditsPerToken)\\n external\\n onlyGovernor\\n {\\n require(_vaultAddress != address(0), \\\"Zero vault address\\\");\\n require(vaultAddress == address(0), \\\"Already initialized\\\");\\n\\n rebasingCreditsPerToken_ = _initialCreditsPerToken;\\n vaultAddress = _vaultAddress;\\n }\\n\\n /// @dev Returns the symbol of the token, a shorter version\\n /// of the name.\\n function symbol() external pure virtual returns (string memory) {\\n return \\\"OUSD\\\";\\n }\\n\\n /// @dev Returns the name of the token.\\n function name() external pure virtual returns (string memory) {\\n return \\\"Origin Dollar\\\";\\n }\\n\\n /// @dev Returns the number of decimals used to get its user representation.\\n function decimals() external pure virtual returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev Verifies that the caller is the Vault contract\\n */\\n modifier onlyVault() {\\n require(vaultAddress == msg.sender, \\\"Caller is not the Vault\\\");\\n _;\\n }\\n\\n /**\\n * @return High resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerTokenHighres() external view returns (uint256) {\\n return rebasingCreditsPerToken_;\\n }\\n\\n /**\\n * @return Low resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerToken() external view returns (uint256) {\\n return rebasingCreditsPerToken_ / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return High resolution total number of rebasing credits\\n */\\n function rebasingCreditsHighres() external view returns (uint256) {\\n return rebasingCredits_;\\n }\\n\\n /**\\n * @return Low resolution total number of rebasing credits\\n */\\n function rebasingCredits() external view returns (uint256) {\\n return rebasingCredits_ / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @notice Gets the balance of the specified address.\\n * @param _account Address to query the balance of.\\n * @return A uint256 representing the amount of base units owned by the\\n * specified address.\\n */\\n function balanceOf(address _account) public view returns (uint256) {\\n RebaseOptions state = rebaseState[_account];\\n if (state == RebaseOptions.YieldDelegationSource) {\\n // Saves a slot read when transferring to or from a yield delegating source\\n // since we know creditBalances equals the balance.\\n return creditBalances[_account];\\n }\\n uint256 baseBalance = (creditBalances[_account] * 1e18) /\\n _creditsPerToken(_account);\\n if (state == RebaseOptions.YieldDelegationTarget) {\\n // creditBalances of yieldFrom accounts equals token balances\\n return baseBalance - creditBalances[yieldFrom[_account]];\\n }\\n return baseBalance;\\n }\\n\\n /**\\n * @notice Gets the credits balance of the specified address.\\n * @dev Backwards compatible with old low res credits per token.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256) Credit balance and credits per token of the\\n * address\\n */\\n function creditsBalanceOf(address _account)\\n external\\n view\\n returns (uint256, uint256)\\n {\\n uint256 cpt = _creditsPerToken(_account);\\n if (cpt == 1e27) {\\n // For a period before the resolution upgrade, we created all new\\n // contract accounts at high resolution. Since they are not changing\\n // as a result of this upgrade, we will return their true values\\n return (creditBalances[_account], cpt);\\n } else {\\n return (\\n creditBalances[_account] / RESOLUTION_INCREASE,\\n cpt / RESOLUTION_INCREASE\\n );\\n }\\n }\\n\\n /**\\n * @notice Gets the credits balance of the specified address.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\\n * address, and isUpgraded\\n */\\n function creditsBalanceOfHighres(address _account)\\n external\\n view\\n returns (\\n uint256,\\n uint256,\\n bool\\n )\\n {\\n return (\\n creditBalances[_account],\\n _creditsPerToken(_account),\\n true // all accounts have their resolution \\\"upgraded\\\"\\n );\\n }\\n\\n // Backwards compatible view\\n function nonRebasingCreditsPerToken(address _account)\\n external\\n view\\n returns (uint256)\\n {\\n return alternativeCreditsPerToken[_account];\\n }\\n\\n /**\\n * @notice Transfer tokens to a specified address.\\n * @param _to the address to transfer to.\\n * @param _value the amount to be transferred.\\n * @return true on success.\\n */\\n function transfer(address _to, uint256 _value) external returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n\\n _executeTransfer(msg.sender, _to, _value);\\n\\n emit Transfer(msg.sender, _to, _value);\\n return true;\\n }\\n\\n /**\\n * @notice Transfer tokens from one address to another.\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value The amount of tokens to be transferred.\\n * @return true on success.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n uint256 userAllowance = allowances[_from][msg.sender];\\n require(_value <= userAllowance, \\\"Allowance exceeded\\\");\\n\\n unchecked {\\n allowances[_from][msg.sender] = userAllowance - _value;\\n }\\n\\n _executeTransfer(_from, _to, _value);\\n\\n emit Transfer(_from, _to, _value);\\n return true;\\n }\\n\\n function _executeTransfer(\\n address _from,\\n address _to,\\n uint256 _value\\n ) internal {\\n (\\n int256 fromRebasingCreditsDiff,\\n int256 fromNonRebasingSupplyDiff\\n ) = _adjustAccount(_from, -_value.toInt256());\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_to, _value.toInt256());\\n\\n _adjustGlobals(\\n fromRebasingCreditsDiff + toRebasingCreditsDiff,\\n fromNonRebasingSupplyDiff + toNonRebasingSupplyDiff\\n );\\n }\\n\\n function _adjustAccount(address _account, int256 _balanceChange)\\n internal\\n returns (int256 rebasingCreditsDiff, int256 nonRebasingSupplyDiff)\\n {\\n RebaseOptions state = rebaseState[_account];\\n int256 currentBalance = balanceOf(_account).toInt256();\\n if (currentBalance + _balanceChange < 0) {\\n revert(\\\"Transfer amount exceeds balance\\\");\\n }\\n uint256 newBalance = (currentBalance + _balanceChange).toUint256();\\n\\n if (state == RebaseOptions.YieldDelegationSource) {\\n address target = yieldTo[_account];\\n uint256 targetOldBalance = balanceOf(target);\\n uint256 targetNewCredits = _balanceToRebasingCredits(\\n targetOldBalance + newBalance\\n );\\n rebasingCreditsDiff =\\n targetNewCredits.toInt256() -\\n creditBalances[target].toInt256();\\n\\n creditBalances[_account] = newBalance;\\n creditBalances[target] = targetNewCredits;\\n } else if (state == RebaseOptions.YieldDelegationTarget) {\\n uint256 newCredits = _balanceToRebasingCredits(\\n newBalance + creditBalances[yieldFrom[_account]]\\n );\\n rebasingCreditsDiff =\\n newCredits.toInt256() -\\n creditBalances[_account].toInt256();\\n creditBalances[_account] = newCredits;\\n } else {\\n _autoMigrate(_account);\\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\\n _account\\n ];\\n if (alternativeCreditsPerTokenMem > 0) {\\n nonRebasingSupplyDiff = _balanceChange;\\n if (alternativeCreditsPerTokenMem != 1e18) {\\n alternativeCreditsPerToken[_account] = 1e18;\\n }\\n creditBalances[_account] = newBalance;\\n } else {\\n uint256 newCredits = _balanceToRebasingCredits(newBalance);\\n rebasingCreditsDiff =\\n newCredits.toInt256() -\\n creditBalances[_account].toInt256();\\n creditBalances[_account] = newCredits;\\n }\\n }\\n }\\n\\n function _adjustGlobals(\\n int256 _rebasingCreditsDiff,\\n int256 _nonRebasingSupplyDiff\\n ) internal {\\n if (_rebasingCreditsDiff != 0) {\\n rebasingCredits_ = (rebasingCredits_.toInt256() +\\n _rebasingCreditsDiff).toUint256();\\n }\\n if (_nonRebasingSupplyDiff != 0) {\\n nonRebasingSupply = (nonRebasingSupply.toInt256() +\\n _nonRebasingSupplyDiff).toUint256();\\n }\\n }\\n\\n /**\\n * @notice Function to check the amount of tokens that _owner has allowed\\n * to `_spender`.\\n * @param _owner The address which owns the funds.\\n * @param _spender The address which will spend the funds.\\n * @return The number of tokens still available for the _spender.\\n */\\n function allowance(address _owner, address _spender)\\n external\\n view\\n returns (uint256)\\n {\\n return allowances[_owner][_spender];\\n }\\n\\n /**\\n * @notice Approve the passed address to spend the specified amount of\\n * tokens on behalf of msg.sender.\\n * @param _spender The address which will spend the funds.\\n * @param _value The amount of tokens to be spent.\\n * @return true on success.\\n */\\n function approve(address _spender, uint256 _value) external returns (bool) {\\n allowances[msg.sender][_spender] = _value;\\n emit Approval(msg.sender, _spender, _value);\\n return true;\\n }\\n\\n /**\\n * @notice Creates `_amount` tokens and assigns them to `_account`,\\n * increasing the total supply.\\n */\\n function mint(address _account, uint256 _amount) external onlyVault {\\n require(_account != address(0), \\\"Mint to the zero address\\\");\\n\\n // Account\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_account, _amount.toInt256());\\n // Globals\\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\\n totalSupply = totalSupply + _amount;\\n\\n require(totalSupply < MAX_SUPPLY, \\\"Max supply\\\");\\n emit Transfer(address(0), _account, _amount);\\n }\\n\\n /**\\n * @notice Destroys `_amount` tokens from `_account`,\\n * reducing the total supply.\\n */\\n function burn(address _account, uint256 _amount) external onlyVault {\\n require(_account != address(0), \\\"Burn from the zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n\\n // Account\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_account, -_amount.toInt256());\\n // Globals\\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\\n totalSupply = totalSupply - _amount;\\n\\n emit Transfer(_account, address(0), _amount);\\n }\\n\\n /**\\n * @dev Get the credits per token for an account. Returns a fixed amount\\n * if the account is non-rebasing.\\n * @param _account Address of the account.\\n */\\n function _creditsPerToken(address _account)\\n internal\\n view\\n returns (uint256)\\n {\\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\\n _account\\n ];\\n if (alternativeCreditsPerTokenMem != 0) {\\n return alternativeCreditsPerTokenMem;\\n } else {\\n return rebasingCreditsPerToken_;\\n }\\n }\\n\\n /**\\n * @dev Auto migrate contracts to be non rebasing,\\n * unless they have opted into yield.\\n * @param _account Address of the account.\\n */\\n function _autoMigrate(address _account) internal {\\n uint256 codeLen = _account.code.length;\\n bool isEOA = (codeLen == 0) ||\\n (codeLen == 23 && bytes3(_account.code) == 0xef0100);\\n // In previous code versions, contracts would not have had their\\n // rebaseState[_account] set to RebaseOptions.NonRebasing when migrated\\n // therefore we check the actual accounting used on the account as well.\\n if (\\n (!isEOA) &&\\n rebaseState[_account] == RebaseOptions.NotSet &&\\n alternativeCreditsPerToken[_account] == 0\\n ) {\\n _rebaseOptOut(_account);\\n }\\n }\\n\\n /**\\n * @dev Calculates credits from contract's global rebasingCreditsPerToken_, and\\n * also balance that corresponds to those credits. The latter is important\\n * when adjusting the contract's global nonRebasingSupply to circumvent any\\n * possible rounding errors.\\n *\\n * @param _balance Balance of the account.\\n */\\n function _balanceToRebasingCredits(uint256 _balance)\\n internal\\n view\\n returns (uint256 rebasingCredits)\\n {\\n // Rounds up, because we need to ensure that accounts always have\\n // at least the balance that they should have.\\n // Note this should always be used on an absolute account value,\\n // not on a possibly negative diff, because then the rounding would be wrong.\\n return ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18;\\n }\\n\\n /**\\n * @notice The calling account will start receiving yield after a successful call.\\n * @param _account Address of the account.\\n */\\n function governanceRebaseOptIn(address _account) external onlyGovernor {\\n require(_account != address(0), \\\"Zero address not allowed\\\");\\n _rebaseOptIn(_account);\\n }\\n\\n /**\\n * @notice The calling account will start receiving yield after a successful call.\\n */\\n function rebaseOptIn() external {\\n _rebaseOptIn(msg.sender);\\n }\\n\\n function _rebaseOptIn(address _account) internal {\\n uint256 balance = balanceOf(_account);\\n\\n // prettier-ignore\\n require(\\n alternativeCreditsPerToken[_account] > 0 ||\\n // Accounts may explicitly `rebaseOptIn` regardless of\\n // accounting if they have a 0 balance.\\n creditBalances[_account] == 0\\n ,\\n \\\"Account must be non-rebasing\\\"\\n );\\n RebaseOptions state = rebaseState[_account];\\n // prettier-ignore\\n require(\\n state == RebaseOptions.StdNonRebasing ||\\n state == RebaseOptions.NotSet,\\n \\\"Only standard non-rebasing accounts can opt in\\\"\\n );\\n\\n uint256 newCredits = _balanceToRebasingCredits(balance);\\n\\n // Account\\n rebaseState[_account] = RebaseOptions.StdRebasing;\\n alternativeCreditsPerToken[_account] = 0;\\n creditBalances[_account] = newCredits;\\n // Globals\\n _adjustGlobals(newCredits.toInt256(), -balance.toInt256());\\n\\n emit AccountRebasingEnabled(_account);\\n }\\n\\n /**\\n * @notice The calling account will no longer receive yield\\n */\\n function rebaseOptOut() external {\\n _rebaseOptOut(msg.sender);\\n }\\n\\n function _rebaseOptOut(address _account) internal {\\n require(\\n alternativeCreditsPerToken[_account] == 0,\\n \\\"Account must be rebasing\\\"\\n );\\n RebaseOptions state = rebaseState[_account];\\n require(\\n state == RebaseOptions.StdRebasing || state == RebaseOptions.NotSet,\\n \\\"Only standard rebasing accounts can opt out\\\"\\n );\\n\\n uint256 oldCredits = creditBalances[_account];\\n uint256 balance = balanceOf(_account);\\n\\n // Account\\n rebaseState[_account] = RebaseOptions.StdNonRebasing;\\n alternativeCreditsPerToken[_account] = 1e18;\\n creditBalances[_account] = balance;\\n // Globals\\n _adjustGlobals(-oldCredits.toInt256(), balance.toInt256());\\n\\n emit AccountRebasingDisabled(_account);\\n }\\n\\n /**\\n * @notice Distribute yield to users. This changes the exchange rate\\n * between \\\"credits\\\" and OUSD tokens to change rebasing user's balances.\\n * @param _newTotalSupply New total supply of OUSD.\\n */\\n function changeSupply(uint256 _newTotalSupply) external onlyVault {\\n require(totalSupply > 0, \\\"Cannot increase 0 supply\\\");\\n\\n if (totalSupply == _newTotalSupply) {\\n emit TotalSupplyUpdatedHighres(\\n totalSupply,\\n rebasingCredits_,\\n rebasingCreditsPerToken_\\n );\\n return;\\n }\\n\\n totalSupply = _newTotalSupply > MAX_SUPPLY\\n ? MAX_SUPPLY\\n : _newTotalSupply;\\n\\n uint256 rebasingSupply = totalSupply - nonRebasingSupply;\\n // round up in the favour of the protocol\\n rebasingCreditsPerToken_ =\\n (rebasingCredits_ * 1e18 + rebasingSupply - 1) /\\n rebasingSupply;\\n\\n require(rebasingCreditsPerToken_ > 0, \\\"Invalid change in supply\\\");\\n\\n emit TotalSupplyUpdatedHighres(\\n totalSupply,\\n rebasingCredits_,\\n rebasingCreditsPerToken_\\n );\\n }\\n\\n /*\\n * @notice Send the yield from one account to another account.\\n * Each account keeps its own balances.\\n */\\n function delegateYield(address _from, address _to)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_from != address(0), \\\"Zero from address not allowed\\\");\\n require(_to != address(0), \\\"Zero to address not allowed\\\");\\n\\n require(_from != _to, \\\"Cannot delegate to self\\\");\\n require(\\n yieldFrom[_to] == address(0) &&\\n yieldTo[_to] == address(0) &&\\n yieldFrom[_from] == address(0) &&\\n yieldTo[_from] == address(0),\\n \\\"Blocked by existing yield delegation\\\"\\n );\\n RebaseOptions stateFrom = rebaseState[_from];\\n RebaseOptions stateTo = rebaseState[_to];\\n\\n require(\\n stateFrom == RebaseOptions.NotSet ||\\n stateFrom == RebaseOptions.StdNonRebasing ||\\n stateFrom == RebaseOptions.StdRebasing,\\n \\\"Invalid rebaseState from\\\"\\n );\\n\\n require(\\n stateTo == RebaseOptions.NotSet ||\\n stateTo == RebaseOptions.StdNonRebasing ||\\n stateTo == RebaseOptions.StdRebasing,\\n \\\"Invalid rebaseState to\\\"\\n );\\n\\n if (alternativeCreditsPerToken[_from] == 0) {\\n _rebaseOptOut(_from);\\n }\\n if (alternativeCreditsPerToken[_to] > 0) {\\n _rebaseOptIn(_to);\\n }\\n\\n uint256 fromBalance = balanceOf(_from);\\n uint256 toBalance = balanceOf(_to);\\n uint256 oldToCredits = creditBalances[_to];\\n uint256 newToCredits = _balanceToRebasingCredits(\\n fromBalance + toBalance\\n );\\n\\n // Set up the bidirectional links\\n yieldTo[_from] = _to;\\n yieldFrom[_to] = _from;\\n\\n // Local\\n rebaseState[_from] = RebaseOptions.YieldDelegationSource;\\n alternativeCreditsPerToken[_from] = 1e18;\\n creditBalances[_from] = fromBalance;\\n rebaseState[_to] = RebaseOptions.YieldDelegationTarget;\\n creditBalances[_to] = newToCredits;\\n\\n // Global\\n int256 creditsChange = newToCredits.toInt256() -\\n oldToCredits.toInt256();\\n _adjustGlobals(creditsChange, -(fromBalance).toInt256());\\n emit YieldDelegated(_from, _to);\\n }\\n\\n /*\\n * @notice Stop sending the yield from one account to another account.\\n */\\n function undelegateYield(address _from) external onlyGovernorOrStrategist {\\n // Require a delegation, which will also ensure a valid delegation\\n require(yieldTo[_from] != address(0), \\\"Zero address not allowed\\\");\\n\\n address to = yieldTo[_from];\\n uint256 fromBalance = balanceOf(_from);\\n uint256 toBalance = balanceOf(to);\\n uint256 oldToCredits = creditBalances[to];\\n uint256 newToCredits = _balanceToRebasingCredits(toBalance);\\n\\n // Remove the bidirectional links\\n yieldFrom[to] = address(0);\\n yieldTo[_from] = address(0);\\n\\n // Local\\n rebaseState[_from] = RebaseOptions.StdNonRebasing;\\n // alternativeCreditsPerToken[from] already 1e18 from `delegateYield()`\\n creditBalances[_from] = fromBalance;\\n rebaseState[to] = RebaseOptions.StdRebasing;\\n // alternativeCreditsPerToken[to] already 0 from `delegateYield()`\\n creditBalances[to] = newToCredits;\\n\\n // Global\\n int256 creditsChange = newToCredits.toInt256() -\\n oldToCredits.toInt256();\\n _adjustGlobals(creditsChange, fromBalance.toInt256());\\n emit YieldUndelegated(_from, to);\\n }\\n}\\n\",\"keccak256\":\"0x73439bef6569f5adf6f5ce2cb54a5f0d3109d4819457532236e172a7091980a9\",\"license\":\"BUSL-1.1\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { IBasicToken } from \\\"../interfaces/IBasicToken.sol\\\";\\n\\nlibrary Helpers {\\n /**\\n * @notice Fetch the `symbol()` from an ERC20 token\\n * @dev Grabs the `symbol()` from a contract\\n * @param _token Address of the ERC20 token\\n * @return string Symbol of the ERC20 token\\n */\\n function getSymbol(address _token) internal view returns (string memory) {\\n string memory symbol = IBasicToken(_token).symbol();\\n return symbol;\\n }\\n\\n /**\\n * @notice Fetch the `decimals()` from an ERC20 token\\n * @dev Grabs the `decimals()` from a contract and fails if\\n * the decimal value does not live within a certain range\\n * @param _token Address of the ERC20 token\\n * @return uint256 Decimals of the ERC20 token\\n */\\n function getDecimals(address _token) internal view returns (uint256) {\\n uint256 decimals = IBasicToken(_token).decimals();\\n require(\\n decimals >= 4 && decimals <= 18,\\n \\\"Token must have sufficient decimal places\\\"\\n );\\n\\n return decimals;\\n }\\n}\\n\",\"keccak256\":\"0x4366f8d90b34c1eef8bbaaf369b1e5cd59f04027bb3c111f208eaee65bbc0346\",\"license\":\"BUSL-1.1\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base contract any contracts that need to initialize state after deployment.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0x50d39ebf38a3d3111f2b77a6c75ece1d4ae731552fec4697ab16fcf6c0d4d5e8\",\"license\":\"BUSL-1.1\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n // slither-disable-next-line divide-before-multiply\\n x = x.div(10**(from - to));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e36 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0x71d6ed0053a1e5ef018d27c3b6d024f336d8157ab6f6859e400b3243a50a71b7\",\"license\":\"BUSL-1.1\"},\"contracts/vault/OETHBaseVault.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { VaultAdmin } from \\\"./VaultAdmin.sol\\\";\\n\\n/**\\n * @title OETH Base VaultAdmin Contract\\n * @author Origin Protocol Inc\\n */\\ncontract OETHBaseVault is VaultAdmin {\\n constructor(address _weth) VaultAdmin(_weth) {}\\n}\\n\",\"keccak256\":\"0x7f8d61656d131bcf705c3b9520933404d7d7c5406bb649247b304f8108bd7dbf\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultAdmin contract\\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\nimport \\\"./VaultCore.sol\\\";\\n\\nabstract contract VaultAdmin is VaultCore {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n using SafeCast for uint256;\\n\\n /**\\n * @dev Verifies that the caller is the Governor or Strategist.\\n */\\n modifier onlyGovernorOrStrategist() {\\n require(\\n msg.sender == strategistAddr || isGovernor(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n constructor(address _asset) VaultCore(_asset) {}\\n\\n /***************************************\\n Configuration\\n ****************************************/\\n /**\\n * @notice Set a buffer of asset to keep in the Vault to handle most\\n * redemptions without needing to spend gas unwinding asset from a Strategy.\\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\\n */\\n function setVaultBuffer(uint256 _vaultBuffer)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_vaultBuffer <= 1e18, \\\"Invalid value\\\");\\n vaultBuffer = _vaultBuffer;\\n emit VaultBufferUpdated(_vaultBuffer);\\n }\\n\\n /**\\n * @notice Sets the minimum amount of OTokens in a mint to trigger an\\n * automatic allocation of funds afterwords.\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setAutoAllocateThreshold(uint256 _threshold)\\n external\\n onlyGovernor\\n {\\n autoAllocateThreshold = _threshold;\\n emit AllocateThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set a minimum amount of OTokens in a mint or redeem that triggers a\\n * rebase\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setRebaseThreshold(uint256 _threshold) external onlyGovernor {\\n rebaseThreshold = _threshold;\\n emit RebaseThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set address of Strategist\\n * @param _address Address of Strategist\\n */\\n function setStrategistAddr(address _address) external onlyGovernor {\\n strategistAddr = _address;\\n emit StrategistUpdated(_address);\\n }\\n\\n /**\\n * @notice Set the default Strategy for asset, i.e. the one which\\n * the asset will be automatically allocated to and withdrawn from\\n * @param _strategy Address of the Strategy\\n */\\n function setDefaultStrategy(address _strategy)\\n external\\n onlyGovernorOrStrategist\\n {\\n emit DefaultStrategyUpdated(_strategy);\\n // If its a zero address being passed for the strategy we are removing\\n // the default strategy\\n if (_strategy != address(0)) {\\n // Make sure the strategy meets some criteria\\n require(strategies[_strategy].isSupported, \\\"Strategy not approved\\\");\\n require(\\n IStrategy(_strategy).supportsAsset(asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n }\\n defaultStrategy = _strategy;\\n }\\n\\n /**\\n * @notice Changes the async withdrawal claim period for OETH & superOETHb\\n * @param _delay Delay period (should be between 10 mins to 7 days).\\n * Set to 0 to disable async withdrawals\\n */\\n function setWithdrawalClaimDelay(uint256 _delay) external onlyGovernor {\\n require(\\n _delay == 0 || (_delay >= 10 minutes && _delay <= 15 days),\\n \\\"Invalid claim delay period\\\"\\n );\\n withdrawalClaimDelay = _delay;\\n emit WithdrawalClaimDelayUpdated(_delay);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Set a yield streaming max rate. This spreads yield over\\n * time if it is above the max rate. This is a per rebase APR which\\n * due to compounding differs from the yearly APR. Governance should\\n * consider this fact when picking a desired APR\\n * @param apr in 1e18 notation. 3 * 1e18 = 3% APR\\n */\\n function setRebaseRateMax(uint256 apr) external onlyGovernorOrStrategist {\\n // The old yield will be at the old rate\\n _rebase();\\n // Change the rate\\n uint256 newPerSecond = apr / 100 / 365 days;\\n require(newPerSecond <= MAX_REBASE_PER_SECOND, \\\"Rate too high\\\");\\n rebasePerSecondMax = newPerSecond.toUint64();\\n emit RebasePerSecondMaxChanged(newPerSecond);\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Set the drip duration period\\n * @param _dripDuration Time in seconds to target a constant yield rate\\n */\\n function setDripDuration(uint256 _dripDuration)\\n external\\n onlyGovernorOrStrategist\\n {\\n // The old yield will be at the old rate\\n _rebase();\\n dripDuration = _dripDuration.toUint64();\\n emit DripDurationChanged(_dripDuration);\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /***************************************\\n Strategy Config\\n ****************************************/\\n\\n /**\\n * @notice Add a strategy to the Vault.\\n * @param _addr Address of the strategy to add\\n */\\n function approveStrategy(address _addr) external onlyGovernor {\\n require(!strategies[_addr].isSupported, \\\"Strategy already approved\\\");\\n require(\\n IStrategy(_addr).supportsAsset(asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\\n allStrategies.push(_addr);\\n emit StrategyApproved(_addr);\\n }\\n\\n /**\\n * @notice Remove a strategy from the Vault.\\n * @param _addr Address of the strategy to remove\\n */\\n\\n function removeStrategy(address _addr) external onlyGovernor {\\n require(strategies[_addr].isSupported, \\\"Strategy not approved\\\");\\n require(defaultStrategy != _addr, \\\"Strategy is default for asset\\\");\\n\\n // Initialize strategyIndex with out of bounds result so function will\\n // revert if no valid index found\\n uint256 stratCount = allStrategies.length;\\n uint256 strategyIndex = stratCount;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n if (allStrategies[i] == _addr) {\\n strategyIndex = i;\\n break;\\n }\\n }\\n\\n if (strategyIndex < stratCount) {\\n allStrategies[strategyIndex] = allStrategies[stratCount - 1];\\n allStrategies.pop();\\n\\n // Mark the strategy as not supported\\n strategies[_addr].isSupported = false;\\n isMintWhitelistedStrategy[_addr] = false;\\n\\n // Withdraw all asset\\n IStrategy strategy = IStrategy(_addr);\\n strategy.withdrawAll();\\n\\n // 1e13 for 18 decimals. And 1e1(10) for 6 decimals\\n uint256 maxDustBalance = uint256(1e13).scaleBy(assetDecimals, 18);\\n\\n /*\\n * Some strategies are not able to withdraw all of their funds in a synchronous call.\\n * Prevent the possible accidental removal of such strategies before their funds are withdrawn.\\n */\\n require(\\n strategy.checkBalance(asset) < maxDustBalance,\\n \\\"Strategy has funds\\\"\\n );\\n emit StrategyRemoved(_addr);\\n }\\n }\\n\\n /**\\n * @notice Adds a strategy to the mint whitelist.\\n * Reverts if strategy isn't approved on Vault.\\n * @param strategyAddr Strategy address\\n */\\n function addStrategyToMintWhitelist(address strategyAddr)\\n external\\n onlyGovernor\\n {\\n require(strategies[strategyAddr].isSupported, \\\"Strategy not approved\\\");\\n\\n require(\\n !isMintWhitelistedStrategy[strategyAddr],\\n \\\"Already whitelisted\\\"\\n );\\n\\n isMintWhitelistedStrategy[strategyAddr] = true;\\n\\n emit StrategyAddedToMintWhitelist(strategyAddr);\\n }\\n\\n /**\\n * @notice Removes a strategy from the mint whitelist.\\n * @param strategyAddr Strategy address\\n */\\n function removeStrategyFromMintWhitelist(address strategyAddr)\\n external\\n onlyGovernor\\n {\\n // Intentionally skipping `strategies.isSupported` check since\\n // we may wanna remove an address even after removing the strategy\\n\\n require(isMintWhitelistedStrategy[strategyAddr], \\\"Not whitelisted\\\");\\n\\n isMintWhitelistedStrategy[strategyAddr] = false;\\n\\n emit StrategyRemovedFromMintWhitelist(strategyAddr);\\n }\\n\\n /***************************************\\n Strategies\\n ****************************************/\\n\\n /**\\n * @notice Deposit multiple asset from the vault into the strategy.\\n * @param _strategyToAddress Address of the Strategy to deposit asset into.\\n * @param _assets Array of asset address that will be deposited into the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to deposit.\\n */\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _depositToStrategy(_strategyToAddress, _assets, _amounts);\\n }\\n\\n function _depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyToAddress].isSupported,\\n \\\"Invalid to Strategy\\\"\\n );\\n require(\\n _assets.length == 1 && _amounts.length == 1 && _assets[0] == asset,\\n \\\"Only asset is supported\\\"\\n );\\n\\n // Check the there is enough asset to transfer once the backing\\n // asset reserved for the withdrawal queue is accounted for\\n require(\\n _amounts[0] <= _assetAvailable(),\\n \\\"Not enough assets available\\\"\\n );\\n\\n // Send required amount of funds to the strategy\\n IERC20(asset).safeTransfer(_strategyToAddress, _amounts[0]);\\n\\n // Deposit all the funds that have been sent to the strategy\\n IStrategy(_strategyToAddress).depositAll();\\n }\\n\\n /**\\n * @notice Withdraw multiple asset from the strategy to the vault.\\n * @param _strategyFromAddress Address of the Strategy to withdraw asset from.\\n * @param _assets Array of asset address that will be withdrawn from the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to withdraw.\\n */\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _withdrawFromStrategy(\\n address(this),\\n _strategyFromAddress,\\n _assets,\\n _amounts\\n );\\n }\\n\\n /**\\n * @param _recipient can either be a strategy or the Vault\\n */\\n function _withdrawFromStrategy(\\n address _recipient,\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyFromAddress].isSupported,\\n \\\"Invalid from Strategy\\\"\\n );\\n require(_assets.length == _amounts.length, \\\"Parameter length mismatch\\\");\\n\\n uint256 assetCount = _assets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n // Withdraw from Strategy to the recipient\\n IStrategy(_strategyFromAddress).withdraw(\\n _recipient,\\n _assets[i],\\n _amounts[i]\\n );\\n }\\n\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @notice Sets the maximum allowable difference between\\n * total supply and asset' value.\\n */\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\\n maxSupplyDiff = _maxSupplyDiff;\\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\\n }\\n\\n /**\\n * @notice Sets the trusteeAddress that can receive a portion of yield.\\n * Setting to the zero address disables this feature.\\n */\\n function setTrusteeAddress(address _address) external onlyGovernor {\\n trusteeAddress = _address;\\n emit TrusteeAddressChanged(_address);\\n }\\n\\n /**\\n * @notice Sets the TrusteeFeeBps to the percentage of yield that should be\\n * received in basis points.\\n */\\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\\n require(_basis <= 5000, \\\"basis cannot exceed 50%\\\");\\n trusteeFeeBps = _basis;\\n emit TrusteeFeeBpsChanged(_basis);\\n }\\n\\n /***************************************\\n Pause\\n ****************************************/\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent rebasing.\\n */\\n function pauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = true;\\n emit RebasePaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to allow rebasing.\\n */\\n function unpauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = false;\\n emit RebaseUnpaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent capital movement.\\n */\\n function pauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = true;\\n emit CapitalPaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to false to enable capital movement.\\n */\\n function unpauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = false;\\n emit CapitalUnpaused();\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\\n * contract, i.e. mistaken sends.\\n * @param _asset Address for the asset\\n * @param _amount Amount of the asset to transfer\\n */\\n function transferToken(address _asset, uint256 _amount)\\n external\\n onlyGovernor\\n {\\n require(asset != _asset, \\\"Only unsupported asset\\\");\\n IERC20(_asset).safeTransfer(governor(), _amount);\\n }\\n\\n /***************************************\\n Strategies Admin\\n ****************************************/\\n\\n /**\\n * @notice Withdraws all asset from the strategy and sends asset to the Vault.\\n * @param _strategyAddr Strategy address.\\n */\\n function withdrawAllFromStrategy(address _strategyAddr)\\n external\\n onlyGovernorOrStrategist\\n {\\n _withdrawAllFromStrategy(_strategyAddr);\\n }\\n\\n function _withdrawAllFromStrategy(address _strategyAddr) internal virtual {\\n require(\\n strategies[_strategyAddr].isSupported,\\n \\\"Strategy is not supported\\\"\\n );\\n IStrategy strategy = IStrategy(_strategyAddr);\\n strategy.withdrawAll();\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @notice Withdraws all asset from all the strategies and sends asset to the Vault.\\n */\\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\\n _withdrawAllFromStrategies();\\n }\\n\\n function _withdrawAllFromStrategies() internal virtual {\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy(allStrategies[i]).withdrawAll();\\n }\\n _addWithdrawalQueueLiquidity();\\n }\\n}\\n\",\"keccak256\":\"0x3ba59fd88e9e3dae7197f04bc76213143f36b2e0922958c6f69d406a4a25f9c2\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultCore.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultCore contract\\n * @notice The Vault contract stores asset. On a deposit, OTokens will be minted\\n and sent to the depositor. On a withdrawal, OTokens will be burned and\\n asset will be sent to the withdrawer. The Vault accepts deposits of\\n interest from yield bearing strategies which will modify the supply\\n of OTokens.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\n\\nimport \\\"./VaultInitializer.sol\\\";\\n\\nabstract contract VaultCore is VaultInitializer {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n\\n /**\\n * @dev Verifies that the rebasing is not paused.\\n */\\n modifier whenNotRebasePaused() {\\n require(!rebasePaused, \\\"Rebasing paused\\\");\\n _;\\n }\\n\\n /**\\n * @dev Verifies that the deposits are not paused.\\n */\\n modifier whenNotCapitalPaused() {\\n require(!capitalPaused, \\\"Capital paused\\\");\\n _;\\n }\\n\\n constructor(address _asset) VaultInitializer(_asset) {}\\n\\n ////////////////////////////////////////////////////\\n /// MINT / BURN ///\\n ////////////////////////////////////////////////////\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @dev Deprecated: use `mint(uint256 _amount)` instead.\\n * @dev Deprecated: param _asset Address of the asset being deposited\\n * @param _amount Amount of the asset being deposited\\n * @dev Deprecated: param _minimumOusdAmount Minimum OTokens to mint\\n */\\n function mint(\\n address,\\n uint256 _amount,\\n uint256\\n ) external whenNotCapitalPaused nonReentrant {\\n _mint(_amount);\\n }\\n\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @param _amount Amount of the asset being deposited\\n */\\n function mint(uint256 _amount) external whenNotCapitalPaused nonReentrant {\\n _mint(_amount);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @dev Deposit a supported asset and mint OTokens.\\n * @param _amount Amount of the asset being deposited\\n */\\n function _mint(uint256 _amount) internal virtual {\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n\\n // Scale amount to 18 decimals\\n uint256 scaledAmount = _amount.scaleBy(18, assetDecimals);\\n\\n emit Mint(msg.sender, scaledAmount);\\n\\n // Rebase must happen before any transfers occur.\\n if (!rebasePaused && scaledAmount >= rebaseThreshold) {\\n _rebase();\\n }\\n\\n // Mint oTokens\\n oToken.mint(msg.sender, scaledAmount);\\n\\n IERC20(asset).safeTransferFrom(msg.sender, address(this), _amount);\\n\\n // Give priority to the withdrawal queue for the new asset liquidity\\n _addWithdrawalQueueLiquidity();\\n\\n // Auto-allocate if necessary\\n if (scaledAmount >= autoAllocateThreshold) {\\n _allocate();\\n }\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /**\\n * @notice Mint OTokens for an allowed Strategy\\n * @param _amount Amount of OToken to mint\\n *\\n * Notice: can't use `nonReentrant` modifier since the `mint` function can\\n * call `allocate`, and that can trigger an AMO strategy to call this function\\n * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function mintForStrategy(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n {\\n require(\\n strategies[msg.sender].isSupported == true,\\n \\\"Unsupported strategy\\\"\\n );\\n require(\\n isMintWhitelistedStrategy[msg.sender] == true,\\n \\\"Not whitelisted strategy\\\"\\n );\\n\\n emit Mint(msg.sender, _amount);\\n // Mint matching amount of OTokens\\n oToken.mint(msg.sender, _amount);\\n }\\n\\n /**\\n * @notice Burn OTokens for an allowed Strategy\\n * @param _amount Amount of OToken to burn\\n *\\n * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could\\n * require withdrawal on an AMO strategy and that one can call `burnForStrategy`\\n * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function burnForStrategy(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n {\\n require(\\n strategies[msg.sender].isSupported == true,\\n \\\"Unsupported strategy\\\"\\n );\\n require(\\n isMintWhitelistedStrategy[msg.sender] == true,\\n \\\"Not whitelisted strategy\\\"\\n );\\n\\n emit Redeem(msg.sender, _amount);\\n\\n // Burn OTokens\\n oToken.burn(msg.sender, _amount);\\n }\\n\\n ////////////////////////////////////////////////////\\n /// ASYNC WITHDRAWALS ///\\n ////////////////////////////////////////////////////\\n /**\\n * @notice Request an asynchronous withdrawal of asset in exchange for OToken.\\n * The OToken is burned on request and the asset is transferred to the withdrawer on claim.\\n * This request can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal this request's `queued` amount.\\n * There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs\\n * enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue.\\n * OToken is converted to asset at 1:1.\\n * @param _amount Amount of OToken to burn.\\n * @return requestId Unique ID for the withdrawal request\\n * @return queued Cumulative total of all asset queued including already claimed requests.\\n */\\n function requestWithdrawal(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 requestId, uint256 queued)\\n {\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n require(withdrawalClaimDelay > 0, \\\"Async withdrawals not enabled\\\");\\n\\n // The check that the requester has enough OToken is done in to later burn call\\n\\n requestId = withdrawalQueueMetadata.nextWithdrawalIndex;\\n queued =\\n withdrawalQueueMetadata.queued +\\n _amount.scaleBy(assetDecimals, 18);\\n\\n // Store the next withdrawal request\\n withdrawalQueueMetadata.nextWithdrawalIndex = SafeCast.toUint128(\\n requestId + 1\\n );\\n // Store the updated queued amount which reserves asset in the withdrawal queue\\n // and reduces the vault's total asset\\n withdrawalQueueMetadata.queued = SafeCast.toUint128(queued);\\n // Store the user's withdrawal request\\n // `queued` is in asset decimals, while `amount` is in OToken decimals (18)\\n withdrawalRequests[requestId] = WithdrawalRequest({\\n withdrawer: msg.sender,\\n claimed: false,\\n timestamp: uint40(block.timestamp),\\n amount: SafeCast.toUint128(_amount),\\n queued: SafeCast.toUint128(queued)\\n });\\n\\n // Burn the user's OToken\\n oToken.burn(msg.sender, _amount);\\n\\n // Prevent withdrawal if the vault is solvent by more than the allowed percentage\\n _postRedeem(_amount);\\n\\n emit WithdrawalRequested(msg.sender, requestId, _amount, queued);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Claim a previously requested withdrawal once it is claimable.\\n * This request can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal this request's `queued` amount and 10 minutes has passed.\\n * If the requests is not claimable, the transaction will revert with `Queue pending liquidity`.\\n * If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`.\\n * OToken is converted to asset at 1:1.\\n * @param _requestId Unique ID for the withdrawal request\\n * @return amount Amount of asset transferred to the withdrawer\\n */\\n function claimWithdrawal(uint256 _requestId)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 amount)\\n {\\n // Try and get more liquidity if there is not enough available\\n if (\\n withdrawalRequests[_requestId].queued >\\n withdrawalQueueMetadata.claimable\\n ) {\\n // Add any asset to the withdrawal queue\\n // this needs to remain here as:\\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\\n // - funds can be withdrawn from a strategy\\n //\\n // Those funds need to be added to withdrawal queue liquidity\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n // Scale amount to asset decimals\\n amount = _claimWithdrawal(_requestId);\\n\\n // transfer asset from the vault to the withdrawer\\n IERC20(asset).safeTransfer(msg.sender, amount);\\n\\n // Prevent insolvency\\n _postRedeem(amount.scaleBy(18, assetDecimals));\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n /**\\n * @notice Claim a previously requested withdrawals once they are claimable.\\n * This requests can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal each request's `queued` amount and 10 minutes has passed.\\n * If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`.\\n * If one of the requests is not older than 10 minutes,\\n * the whole transaction will revert with `Claim delay not met`.\\n * @param _requestIds Unique ID of each withdrawal request\\n * @return amounts Amount of asset received for each request\\n * @return totalAmount Total amount of asset transferred to the withdrawer\\n */\\n function claimWithdrawals(uint256[] calldata _requestIds)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256[] memory amounts, uint256 totalAmount)\\n {\\n // Add any asset to the withdrawal queue\\n // this needs to remain here as:\\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\\n // - funds can be withdrawn from a strategy\\n //\\n // Those funds need to be added to withdrawal queue liquidity\\n _addWithdrawalQueueLiquidity();\\n\\n amounts = new uint256[](_requestIds.length);\\n for (uint256 i; i < _requestIds.length; ++i) {\\n // Scale all amounts to asset decimals, thus totalAmount is also in asset decimals\\n amounts[i] = _claimWithdrawal(_requestIds[i]);\\n totalAmount += amounts[i];\\n }\\n\\n // transfer all the claimed asset from the vault to the withdrawer\\n IERC20(asset).safeTransfer(msg.sender, totalAmount);\\n\\n // Prevent insolvency\\n _postRedeem(totalAmount.scaleBy(18, assetDecimals));\\n\\n return (amounts, totalAmount);\\n }\\n\\n function _claimWithdrawal(uint256 requestId)\\n internal\\n returns (uint256 amount)\\n {\\n require(withdrawalClaimDelay > 0, \\\"Async withdrawals not enabled\\\");\\n\\n // Load the structs from storage into memory\\n WithdrawalRequest memory request = withdrawalRequests[requestId];\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n require(\\n request.timestamp + withdrawalClaimDelay <= block.timestamp,\\n \\\"Claim delay not met\\\"\\n );\\n // If there isn't enough reserved liquidity in the queue to claim\\n require(request.queued <= queue.claimable, \\\"Queue pending liquidity\\\");\\n require(request.withdrawer == msg.sender, \\\"Not requester\\\");\\n require(request.claimed == false, \\\"Already claimed\\\");\\n\\n // Store the request as claimed\\n withdrawalRequests[requestId].claimed = true;\\n // Store the updated claimed amount\\n withdrawalQueueMetadata.claimed =\\n queue.claimed +\\n SafeCast.toUint128(\\n StableMath.scaleBy(request.amount, assetDecimals, 18)\\n );\\n\\n emit WithdrawalClaimed(msg.sender, requestId, request.amount);\\n\\n return StableMath.scaleBy(request.amount, assetDecimals, 18);\\n }\\n\\n function _postRedeem(uint256 _amount) internal {\\n // Until we can prove that we won't affect the prices of our asset\\n // by withdrawing them, this should be here.\\n // It's possible that a strategy was off on its asset total, perhaps\\n // a reward token sold for more or for less than anticipated.\\n uint256 totalUnits = 0;\\n if (_amount >= rebaseThreshold && !rebasePaused) {\\n totalUnits = _rebase();\\n } else {\\n totalUnits = _totalValue();\\n }\\n\\n // Check that the OTokens are backed by enough asset\\n if (maxSupplyDiff > 0) {\\n // If there are more outstanding withdrawal requests than asset in the vault and strategies\\n // then the available asset will be negative and totalUnits will be rounded up to zero.\\n // As we don't know the exact shortfall amount, we will reject all redeem and withdrawals\\n require(totalUnits > 0, \\\"Too many outstanding requests\\\");\\n\\n // Allow a max difference of maxSupplyDiff% between\\n // asset value and OUSD total supply\\n uint256 diff = oToken.totalSupply().divPrecisely(totalUnits);\\n require(\\n (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,\\n \\\"Backing supply liquidity error\\\"\\n );\\n }\\n }\\n\\n /**\\n * @notice Allocate unallocated funds on Vault to strategies.\\n */\\n function allocate() external virtual whenNotCapitalPaused nonReentrant {\\n // Add any unallocated asset to the withdrawal queue first\\n _addWithdrawalQueueLiquidity();\\n\\n _allocate();\\n }\\n\\n /**\\n * @dev Allocate asset (eg. WETH or USDC) to the default asset strategy\\n * if there is excess to the Vault buffer.\\n * This is called from either `mint` or `allocate` and assumes `_addWithdrawalQueueLiquidity`\\n * has been called before this function.\\n */\\n function _allocate() internal virtual {\\n // No need to do anything if no default strategy for asset\\n address depositStrategyAddr = defaultStrategy;\\n if (depositStrategyAddr == address(0)) return;\\n\\n uint256 assetAvailableInVault = _assetAvailable();\\n // No need to do anything if there isn't any asset in the vault to allocate\\n if (assetAvailableInVault == 0) return;\\n\\n // Calculate the target buffer for the vault using the total supply\\n uint256 totalSupply = oToken.totalSupply();\\n // Scaled to asset decimals\\n uint256 targetBuffer = totalSupply.mulTruncate(vaultBuffer).scaleBy(\\n assetDecimals,\\n 18\\n );\\n\\n // If available asset in the Vault is below or equal the target buffer then there's nothing to allocate\\n if (assetAvailableInVault <= targetBuffer) return;\\n\\n // The amount of asset to allocate to the default strategy\\n uint256 allocateAmount = assetAvailableInVault - targetBuffer;\\n\\n IStrategy strategy = IStrategy(depositStrategyAddr);\\n // Transfer asset to the strategy and call the strategy's deposit function\\n IERC20(asset).safeTransfer(address(strategy), allocateAmount);\\n strategy.deposit(asset, allocateAmount);\\n\\n emit AssetAllocated(asset, depositStrategyAddr, allocateAmount);\\n }\\n\\n /**\\n * @notice Calculate the total value of asset held by the Vault and all\\n * strategies and update the supply of OTokens.\\n */\\n function rebase() external virtual nonReentrant {\\n _rebase();\\n }\\n\\n /**\\n * @dev Calculate the total value of asset held by the Vault and all\\n * strategies and update the supply of OTokens, optionally sending a\\n * portion of the yield to the trustee.\\n * @return totalUnits Total balance of Vault in units\\n */\\n function _rebase() internal whenNotRebasePaused returns (uint256) {\\n uint256 supply = oToken.totalSupply();\\n uint256 vaultValue = _totalValue();\\n // If no supply yet, do not rebase\\n if (supply == 0) {\\n return vaultValue;\\n }\\n\\n // Calculate yield and new supply\\n (uint256 yield, uint256 targetRate) = _nextYield(supply, vaultValue);\\n uint256 newSupply = supply + yield;\\n // Only rebase upwards and if we have enough backing funds\\n if (newSupply <= supply || newSupply > vaultValue) {\\n return vaultValue;\\n }\\n\\n rebasePerSecondTarget = uint64(_min(targetRate, type(uint64).max));\\n lastRebase = uint64(block.timestamp); // Intentional cast\\n\\n // Fee collection on yield\\n address _trusteeAddress = trusteeAddress; // gas savings\\n uint256 fee = 0;\\n if (_trusteeAddress != address(0)) {\\n fee = (yield * trusteeFeeBps) / 1e4;\\n if (fee > 0) {\\n require(fee < yield, \\\"Fee must not be greater than yield\\\");\\n oToken.mint(_trusteeAddress, fee);\\n }\\n }\\n emit YieldDistribution(_trusteeAddress, yield, fee);\\n\\n // Only ratchet OToken supply upwards\\n // Final check uses latest totalSupply\\n if (newSupply > oToken.totalSupply()) {\\n oToken.changeSupply(newSupply);\\n }\\n return vaultValue;\\n }\\n\\n /**\\n * @notice Calculates the amount that would rebase at next rebase.\\n * This is before any fees.\\n * @return yield amount of expected yield\\n */\\n function previewYield() external view returns (uint256 yield) {\\n (yield, ) = _nextYield(oToken.totalSupply(), _totalValue());\\n return yield;\\n }\\n\\n /**\\n * @dev Calculates the amount that would rebase at next rebase.\\n * See this Readme for detailed explanation:\\n * contracts/contracts/vault/README - Yield Limits.md\\n */\\n function _nextYield(uint256 supply, uint256 vaultValue)\\n internal\\n view\\n virtual\\n returns (uint256 yield, uint256 targetRate)\\n {\\n uint256 nonRebasing = oToken.nonRebasingSupply();\\n uint256 rebasing = supply - nonRebasing;\\n uint256 elapsed = block.timestamp - lastRebase;\\n targetRate = rebasePerSecondTarget;\\n\\n if (\\n elapsed == 0 || // Yield only once per block.\\n rebasing == 0 || // No yield if there are no rebasing tokens to give it to.\\n supply > vaultValue || // No yield if we do not have yield to give.\\n block.timestamp >= type(uint64).max // No yield if we are too far in the future to calculate it correctly.\\n ) {\\n return (0, targetRate);\\n }\\n\\n // Start with the full difference available\\n yield = vaultValue - supply;\\n\\n // Cap via optional automatic duration smoothing\\n uint256 _dripDuration = dripDuration;\\n if (_dripDuration > 1) {\\n // If we are able to sustain an increased drip rate for\\n // double the duration, then increase the target drip rate\\n targetRate = _max(targetRate, yield / (_dripDuration * 2));\\n // If we cannot sustain the target rate any more,\\n // then rebase what we can, and reduce the target\\n targetRate = _min(targetRate, yield / _dripDuration);\\n // drip at the new target rate\\n yield = _min(yield, targetRate * elapsed);\\n }\\n\\n // Cap per second. elapsed is not 1e18 denominated\\n yield = _min(yield, (rebasing * elapsed * rebasePerSecondMax) / 1e18);\\n\\n // Cap at a hard max per rebase, to avoid long durations resulting in huge rebases\\n yield = _min(yield, (rebasing * MAX_REBASE) / 1e18);\\n\\n return (yield, targetRate);\\n }\\n\\n /**\\n * @notice Determine the total value of asset held by the vault and its\\n * strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function totalValue() external view virtual returns (uint256 value) {\\n value = _totalValue();\\n }\\n\\n /**\\n * @dev Internal Calculate the total value of the asset held by the\\n * vault and its strategies.\\n * @dev The total value of all WETH held by the vault and all its strategies\\n * less any WETH that is reserved for the withdrawal queue.\\n * If there is not enough WETH in the vault and all strategies to cover\\n * all outstanding withdrawal requests then return a total value of 0.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValue() internal view virtual returns (uint256 value) {\\n // As asset is the only asset, just return the asset balance\\n value = _checkBalance(asset).scaleBy(18, assetDecimals);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @param _asset Address of asset\\n * @return uint256 Balance of asset in decimals of asset\\n */\\n function checkBalance(address _asset) external view returns (uint256) {\\n return _checkBalance(_asset);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @dev Get the balance of an asset held in Vault and all strategies\\n * less any asset that is reserved for the withdrawal queue.\\n * BaseAsset is the only asset that can return a non-zero balance.\\n * All other asset will return 0 even if there is some dust amounts left in the Vault.\\n * For example, there is 1 wei left of stETH (or USDC) in the OETH (or OUSD) Vault but\\n * will return 0 in this function.\\n *\\n * If there is not enough asset in the vault and all strategies to cover all outstanding\\n * withdrawal requests then return a asset balance of 0\\n * @param _asset Address of asset\\n * @return balance Balance of asset in decimals of asset\\n */\\n function _checkBalance(address _asset)\\n internal\\n view\\n virtual\\n returns (uint256 balance)\\n {\\n if (_asset != asset) return 0;\\n\\n // Get the asset in the vault and the strategies\\n IERC20 asset = IERC20(_asset);\\n balance = asset.balanceOf(address(this));\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy strategy = IStrategy(allStrategies[i]);\\n if (strategy.supportsAsset(_asset)) {\\n balance = balance + strategy.checkBalance(_asset);\\n }\\n }\\n\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // If the vault becomes insolvent enough that the total value in the vault and all strategies\\n // is less than the outstanding withdrawals.\\n // For example, there was a mass slashing event and most users request a withdrawal.\\n if (balance + queue.claimed < queue.queued) {\\n return 0;\\n }\\n\\n // Need to remove asset that is reserved for the withdrawal queue\\n return balance + queue.claimed - queue.queued;\\n }\\n\\n /**\\n * @notice Adds WETH to the withdrawal queue if there is a funding shortfall.\\n * @dev is called from the Native Staking strategy when validator withdrawals are processed.\\n * It also called before any WETH is allocated to a strategy.\\n */\\n function addWithdrawalQueueLiquidity() external {\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @dev Adds asset (eg. WETH or USDC) to the withdrawal queue if there is a funding shortfall.\\n * This assumes 1 asset equal 1 corresponding OToken.\\n */\\n function _addWithdrawalQueueLiquidity()\\n internal\\n returns (uint256 addedClaimable)\\n {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // Check if the claimable asset is less than the queued amount\\n uint256 queueShortfall = queue.queued - queue.claimable;\\n\\n // No need to do anything is the withdrawal queue is full funded\\n if (queueShortfall == 0) {\\n return 0;\\n }\\n\\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\\n\\n // Of the claimable withdrawal requests, how much is unclaimed?\\n // That is, the amount of asset that is currently allocated for the withdrawal queue\\n uint256 allocatedBaseAsset = queue.claimable - queue.claimed;\\n\\n // If there is no unallocated asset then there is nothing to add to the queue\\n if (assetBalance <= allocatedBaseAsset) {\\n return 0;\\n }\\n\\n uint256 unallocatedBaseAsset = assetBalance - allocatedBaseAsset;\\n // the new claimable amount is the smaller of the queue shortfall or unallocated asset\\n addedClaimable = queueShortfall < unallocatedBaseAsset\\n ? queueShortfall\\n : unallocatedBaseAsset;\\n uint256 newClaimable = queue.claimable + addedClaimable;\\n\\n // Store the new claimable amount back to storage\\n withdrawalQueueMetadata.claimable = SafeCast.toUint128(newClaimable);\\n\\n // emit a WithdrawalClaimable event\\n emit WithdrawalClaimable(newClaimable, addedClaimable);\\n }\\n\\n /**\\n * @dev Calculate how much asset (eg. WETH or USDC) in the vault is not reserved for the withdrawal queue.\\n * That is, it is available to be redeemed or deposited into a strategy.\\n */\\n function _assetAvailable() internal view returns (uint256 assetAvailable) {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // The amount of asset that is still to be claimed in the withdrawal queue\\n uint256 outstandingWithdrawals = queue.queued - queue.claimed;\\n\\n // The amount of sitting in asset in the vault\\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\\n // If there is not enough asset in the vault to cover the outstanding withdrawals\\n if (assetBalance <= outstandingWithdrawals) return 0;\\n\\n return assetBalance - outstandingWithdrawals;\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Return the number of asset supported by the Vault.\\n */\\n function getAssetCount() public view returns (uint256) {\\n return 1;\\n }\\n\\n /**\\n * @notice Return all vault asset addresses in order\\n */\\n function getAllAssets() external view returns (address[] memory) {\\n address[] memory a = new address[](1);\\n a[0] = asset;\\n return a;\\n }\\n\\n /**\\n * @notice Return the number of strategies active on the Vault.\\n */\\n function getStrategyCount() external view returns (uint256) {\\n return allStrategies.length;\\n }\\n\\n /**\\n * @notice Return the array of all strategies\\n */\\n function getAllStrategies() external view returns (address[] memory) {\\n return allStrategies;\\n }\\n\\n /**\\n * @notice Returns whether the vault supports the asset\\n * @param _asset address of the asset\\n * @return true if supported\\n */\\n function isSupportedAsset(address _asset) external view returns (bool) {\\n return asset == _asset;\\n }\\n\\n function _min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n function _max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a > b ? a : b;\\n }\\n}\\n\",\"keccak256\":\"0xf5c7295587db70ea009853009724ded12486dfabf420d589ee1eec37e9a681eb\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultInitializer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultInitializer contract\\n * @notice The Vault contract initializes the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport \\\"./VaultStorage.sol\\\";\\n\\nabstract contract VaultInitializer is VaultStorage {\\n constructor(address _asset) VaultStorage(_asset) {}\\n\\n function initialize(address _oToken) external onlyGovernor initializer {\\n require(_oToken != address(0), \\\"oToken address is zero\\\");\\n\\n oToken = OUSD(_oToken);\\n\\n rebasePaused = false;\\n capitalPaused = true;\\n\\n // Initial Vault buffer of 0%\\n vaultBuffer = 0;\\n // Initial allocate threshold of 25,000 OUSD\\n autoAllocateThreshold = 25000e18;\\n // Threshold for rebasing\\n rebaseThreshold = 1000e18;\\n // Initialize all strategies\\n allStrategies = new address[](0);\\n // Start with drip duration: 7 days\\n dripDuration = 604800;\\n }\\n}\\n\",\"keccak256\":\"0xb0b99b4b9279ab87b6008fb9675b581cc009a51cc5f9c0fb838eda86b1bca02b\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultStorage.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultStorage contract\\n * @notice The VaultStorage contract defines the storage for the Vault contracts\\n * @author Origin Protocol Inc\\n */\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { IERC20Metadata } from \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { OUSD } from \\\"../token/OUSD.sol\\\";\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport \\\"../utils/Helpers.sol\\\";\\n\\nabstract contract VaultStorage is Initializable, Governable {\\n using SafeERC20 for IERC20;\\n\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event DefaultStrategyUpdated(address _strategy);\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\\n event DripDurationChanged(uint256 dripDuration);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\\n\\n // Since we are proxy, all state should be uninitalized.\\n // Since this storage contract does not have logic directly on it\\n // we should not be checking for to see if these variables can be constant.\\n // slither-disable-start uninitialized-state\\n // slither-disable-start constable-states\\n\\n /// @dev mapping of supported vault assets to their configuration\\n uint256 private _deprecated_assets;\\n /// @dev list of all assets supported by the vault.\\n address[] private _deprecated_allAssets;\\n\\n // Strategies approved for use by the Vault\\n struct Strategy {\\n bool isSupported;\\n uint256 _deprecated; // Deprecated storage slot\\n }\\n /// @dev mapping of strategy contracts to their configuration\\n mapping(address => Strategy) public strategies;\\n /// @dev list of all vault strategies\\n address[] internal allStrategies;\\n\\n /// @notice Address of the Oracle price provider contract\\n address private _deprecated_priceProvider;\\n /// @notice pause rebasing if true\\n bool public rebasePaused;\\n /// @notice pause operations that change the OToken supply.\\n /// eg mint, redeem, allocate, mint/burn for strategy\\n bool public capitalPaused;\\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\\n uint256 private _deprecated_redeemFeeBps;\\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\\n uint256 public vaultBuffer;\\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\\n uint256 public autoAllocateThreshold;\\n /// @notice OToken mints over this amount automatically rebase. 18 decimals.\\n uint256 public rebaseThreshold;\\n\\n /// @dev Address of the OToken token. eg OUSD or OETH.\\n OUSD public oToken;\\n\\n /// @dev Address of the contract responsible for post rebase syncs with AMMs\\n address private _deprecated_rebaseHooksAddr = address(0);\\n\\n /// @dev Deprecated: Address of Uniswap\\n address private _deprecated_uniswapAddr = address(0);\\n\\n /// @notice Address of the Strategist\\n address public strategistAddr = address(0);\\n\\n /// @notice Mapping of asset address to the Strategy that they should automatically\\n // be allocated to\\n uint256 private _deprecated_assetDefaultStrategies;\\n\\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\\n uint256 public maxSupplyDiff;\\n\\n /// @notice Trustee contract that can collect a percentage of yield\\n address public trusteeAddress;\\n\\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\\n uint256 public trusteeFeeBps;\\n\\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\\n address[] private _deprecated_swapTokens;\\n\\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\\n\\n address private _deprecated_ousdMetaStrategy;\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n int256 private _deprecated_netOusdMintedForStrategy;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n uint256 private _deprecated_netOusdMintForStrategyThreshold;\\n\\n uint256 private _deprecated_swapConfig;\\n\\n // List of strategies that can mint oTokens directly\\n // Used in OETHBaseVaultCore\\n mapping(address => bool) public isMintWhitelistedStrategy;\\n\\n /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\\n /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\\n address private _deprecated_dripper;\\n\\n /// Withdrawal Queue Storage /////\\n\\n struct WithdrawalQueueMetadata {\\n // cumulative total of all withdrawal requests included the ones that have already been claimed\\n uint128 queued;\\n // cumulative total of all the requests that can be claimed including the ones that have already been claimed\\n uint128 claimable;\\n // total of all the requests that have been claimed\\n uint128 claimed;\\n // index of the next withdrawal request starting at 0\\n uint128 nextWithdrawalIndex;\\n }\\n\\n /// @notice Global metadata for the withdrawal queue including:\\n /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed\\n /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed\\n /// claimed - total of all the requests that have been claimed\\n /// nextWithdrawalIndex - index of the next withdrawal request starting at 0\\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\\n\\n struct WithdrawalRequest {\\n address withdrawer;\\n bool claimed;\\n uint40 timestamp; // timestamp of the withdrawal request\\n // Amount of oTokens to redeem. eg OETH\\n uint128 amount;\\n // cumulative total of all withdrawal requests including this one.\\n // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\\n uint128 queued;\\n }\\n\\n /// @notice Mapping of withdrawal request indices to the user withdrawal request data\\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\\n\\n /// @notice Sets a minimum delay that is required to elapse between\\n /// requesting async withdrawals and claiming the request.\\n /// When set to 0 async withdrawals are disabled.\\n uint256 public withdrawalClaimDelay;\\n\\n /// @notice Time in seconds that the vault last rebased yield.\\n uint64 public lastRebase;\\n\\n /// @notice Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\\n uint64 public dripDuration;\\n\\n /// @notice max rebase percentage per second\\n /// Can be used to set maximum yield of the protocol,\\n /// spreading out yield over time\\n uint64 public rebasePerSecondMax;\\n\\n /// @notice target rebase rate limit, based on past rates and funds available.\\n uint64 public rebasePerSecondTarget;\\n\\n uint256 internal constant MAX_REBASE = 0.02 ether;\\n uint256 internal constant MAX_REBASE_PER_SECOND =\\n uint256(0.05 ether) / 1 days;\\n\\n /// @notice Default strategy for asset\\n address public defaultStrategy;\\n\\n // For future use\\n uint256[42] private __gap;\\n\\n /// @notice Index of WETH asset in allAssets array\\n /// Legacy OETHVaultCore code, relocated here for vault consistency.\\n uint256 private _deprecated_wethAssetIndex;\\n\\n /// @dev Address of the asset (eg. WETH or USDC)\\n address public immutable asset;\\n uint8 internal immutable assetDecimals;\\n\\n // slither-disable-end constable-states\\n // slither-disable-end uninitialized-state\\n\\n constructor(address _asset) {\\n uint8 _decimals = IERC20Metadata(_asset).decimals();\\n require(_decimals <= 18, \\\"invalid asset decimals\\\");\\n asset = _asset;\\n assetDecimals = _decimals;\\n }\\n\\n /// @notice Deprecated: use `oToken()` instead.\\n function oUSD() external view returns (OUSD) {\\n return oToken;\\n }\\n}\\n\",\"keccak256\":\"0xcca0e0ebbbbda50b23fba7aea96a1e34f6a9d58c8f2e86e84b0911d4a9e5d418\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x60c0604052603d80546001600160a01b0319908116909155603e805482169055603f8054909116905534801561003457600080fd5b5060405161544638038061544683398101604081905261005391610133565b808080806000816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100bb9190610163565b905060128160ff1611156101155760405162461bcd60e51b815260206004820152601660248201527f696e76616c696420617373657420646563696d616c7300000000000000000000604482015260640160405180910390fd5b6001600160a01b0390911660805260ff1660a0525061018692505050565b60006020828403121561014557600080fd5b81516001600160a01b038116811461015c57600080fd5b9392505050565b60006020828403121561017557600080fd5b815160ff8116811461015c57600080fd5b60805160a0516151e561026160003960008181610fa60152818161178b0152818161205401528181612c6f015281816131560152818161376201528181613806015281816140ae01526144630152600081816105870152818161089401528181610c4e01528181610fe4015281816112d301528181611438015281816117570152818161189401528181612c3b015281816132520152818161338001528181613b0501528181613dda01528181613f110152818161411901528181614164015281816141cc0152818161448a01526148c501526151e56000f3fe608060405234801561001057600080fd5b50600436106104075760003560e01c80636217f3ea11610220578063ae69f3cb11610130578063c5f00841116100b8578063d4c3eea011610087578063d4c3eea0146109e6578063e6cc5432146109ee578063ea33b8e414610a02578063f844443614610a0a578063fac5bb9b14610a1d57600080fd5b8063c5f00841146109bb578063c7af3352146109c3578063c9919112146109cb578063d38bfff4146109d357600080fd5b8063b890ebf6116100ff578063b890ebf61461096b578063b9b17f9f1461097e578063bb7a632e14610986578063c3b28864146109a0578063c4d66de8146109a857600080fd5b8063ae69f3cb1461092a578063af14052c1461093d578063b2c9336d14610945578063b4925a201461095857600080fd5b806394828ffd116101b35780639fa1826e116101825780639fa1826e146108ec578063a0712d68146108f5578063a0aead4d14610908578063ab80dafb1461090f578063abaa99161461092257600080fd5b806394828ffd1461086957806395b166bc146108715780639be918e6146108845780639ee679e8146108c457600080fd5b8063840c4c7a116101ef578063840c4c7a146107925780638e510b52146107a55780638ec489a2146107ae578063937b2581146107c157600080fd5b80636217f3ea14610746578063663e64ce14610759578063773540b31461076c57806378f353a11461077f57600080fd5b806339ebf8231161031b578063527e83a8116102ae57806357bee9441161027d57806357bee944146106f45780635802a17214610707578063597c8910146107185780635d36b1901461072b5780635f5152261461073357600080fd5b8063527e83a8146106aa57806352d38e5d146106c457806353ca9f24146106cd578063570d8e1d146106e157600080fd5b806345e4213b116102ea57806345e4213b1461063b57806348e30f541461064457806349c1d54d146106655780634d5f46291461067857600080fd5b806339ebf823146105a95780633b8ae397146105ed5780633dbc911f146106005780634530820a1461060857600080fd5b80631a32aad61161039e5780632acada4d1161036d5780632acada4d146104f35780632da845a81461050857806331e19cfa1461051b578063362bd1a31461052357806338d52e0f1461058257600080fd5b80631a32aad6146104ad5780631cfbe7bc146104c05780631edfe3da146104d3578063207134b0146104ea57600080fd5b80631072cbea116103da5780631072cbea14610461578063156e29f614610474578063175188e8146104875780631816dd4a1461049a57600080fd5b80630493a0fa1461040c57806309f49bf5146104215780630acbda75146104295780630c340a241461043c575b600080fd5b61041f61041a366004614b73565b610a30565b005b61041f610ae6565b61041f610437366004614b73565b610b56565b610444610c01565b6040516001600160a01b0390911681526020015b60405180910390f35b61041f61046f366004614ba8565b610c1e565b61041f610482366004614bd2565b610cdc565b61041f610495366004614c05565b610d4f565b61041f6104a8366004614c05565b6110e2565b603c54610444906001600160a01b031681565b61041f6104ce366004614b73565b6111e9565b6104dc60395481565b604051908152602001610458565b6104dc60435481565b6104fb6112ab565b6040516104589190614c20565b61041f610516366004614c05565b611322565b6036546104dc565b604b54604c5461054f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610458565b6104447f000000000000000000000000000000000000000000000000000000000000000081565b6105d66105b7366004614c05565b6035602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610458565b61041f6105fb366004614c05565b611394565b61041f6115a7565b61062b610616366004614c05565b60496020526000908152604090205460ff1681565b6040519015158152602001610458565b6104dc604e5481565b610657610652366004614cb0565b61161d565b604051610458929190614cf1565b604254610444906001600160a01b031681565b604f5461069290600160c01b90046001600160401b031681565b6040516001600160401b039091168152602001610458565b604f5461069290600160801b90046001600160401b031681565b6104dc603b5481565b60375461062b90600160a01b900460ff1681565b603f54610444906001600160a01b031681565b61041f610702366004614c05565b6117c2565b603c546001600160a01b0316610444565b61041f610726366004614c05565b611975565b61041f6119b9565b6104dc610741366004614c05565b611a5f565b61041f610754366004614b73565b611a70565b61041f610767366004614b73565b611bf4565b61041f61077a366004614c05565b611c4d565b604f54610692906001600160401b031681565b61041f6107a0366004614d3e565b611cbf565b6104dc60415481565b61041f6107bc366004614b73565b611d46565b6108226107cf366004614b73565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a001610458565b61041f611dfb565b61041f61087f366004614c05565b611e6b565b61062b610892366004614c05565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b6108d76108d2366004614b73565b611f32565b60408051928352602083019190915201610458565b6104dc603a5481565b61041f610903366004614b73565b612273565b60016104dc565b61041f61091d366004614b73565b6122e4565b61041f612433565b61041f610938366004614d3e565b6124ab565b61041f612527565b61041f610953366004614b73565b61256d565b61041f610966366004614b73565b6125c6565b61041f610979366004614b73565b6126e4565b61041f61273d565b604f5461069290600160401b90046001600160401b031681565b6104fb612745565b61041f6109b6366004614c05565b6127a7565b61041f61295f565b61062b6129d5565b61041f612a06565b61041f6109e1366004614c05565b612a46565b6104dc612aea565b60375461062b90600160a81b900460ff1681565b6104dc612af4565b6104dc610a18366004614b73565b612b83565b605054610444906001600160a01b031681565b603f546001600160a01b0316331480610a4c5750610a4c6129d5565b610a715760405162461bcd60e51b8152600401610a6890614dc2565b60405180910390fd5b610a79612c9e565b50610a8381613038565b604f80546001600160401b0392909216600160401b0267ffffffffffffffff60401b199092169190911790556040518181527f406e15fbca1d8ded2dbb06765fea3a54f18395c54125a4c9916dd00ea14ee15e906020015b60405180910390a150565b603f546001600160a01b0316331480610b025750610b026129d5565b610b1e5760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b610b5e6129d5565b610b7a5760405162461bcd60e51b8152600401610a6890614e0a565b611388811115610bcc5760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f7420657863656564203530250000000000000000006044820152606401610a68565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c790602001610adb565b6000610c196000805160206151908339815191525490565b905090565b610c266129d5565b610c425760405162461bcd60e51b8152600401610a6890614e0a565b816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610cbc5760405162461bcd60e51b815260206004820152601660248201527513db9b1e481d5b9cdd5c1c1bdc9d195908185cdcd95d60521b6044820152606401610a68565b610cd8610cc7610c01565b6001600160a01b03841690836130a4565b5050565b603754600160a81b900460ff1615610d065760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101610d385760405162461bcd60e51b8152600401610a6890614e69565b60028255610d45846130fa565b5060019055505050565b610d576129d5565b610d735760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff16610dab5760405162461bcd60e51b8152600401610a6890614e91565b6050546001600160a01b03808316911603610e085760405162461bcd60e51b815260206004820152601d60248201527f53747261746567792069732064656661756c7420666f722061737365740000006044820152606401610a68565b6036548060005b82811015610e5e57836001600160a01b031660368281548110610e3457610e34614ec0565b6000918252602090912001546001600160a01b031603610e5657809150610e5e565b600101610e0f565b50818110156110dd576036610e74600184614eec565b81548110610e8457610e84614ec0565b600091825260209091200154603680546001600160a01b039092169183908110610eb057610eb0614ec0565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610eef57610eef614eff565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038516808352603582526040808420805460ff1990811690915560499093528084208054909316909255815163429c145b60e11b815291518693919263853828b692600480830193919282900301818387803b158015610f7b57600080fd5b505af1158015610f8f573d6000803e3d6000fd5b5060009250610fcd91506509184e72a000905060ff7f0000000000000000000000000000000000000000000000000000000000000000166012613296565b604051632fa8a91360e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192508291841690635f51522690602401602060405180830381865afa158015611038573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105c9190614f15565b1061109e5760405162461bcd60e51b81526020600482015260126024820152715374726174656779206861732066756e647360701b6044820152606401610a68565b6040516001600160a01b03861681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49060200160405180910390a150505b505050565b6110ea6129d5565b6111065760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff1661113e5760405162461bcd60e51b8152600401610a6890614e91565b6001600160a01b03811660009081526049602052604090205460ff161561119d5760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481dda1a5d195b1a5cdd1959606a1b6044820152606401610a68565b6001600160a01b038116600081815260496020526040808220805460ff19166001179055517f47c8c96a5942f094264111c5fe7f6a4fe86efe63254a6fa7afa5fc84f07d58e89190a250565b6111f16129d5565b61120d5760405162461bcd60e51b8152600401610a6890614e0a565b80158061122a5750610258811015801561122a57506213c6808111155b6112765760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636c61696d2064656c617920706572696f640000000000006044820152606401610a68565b604e8190556040518181527fc59f5e32049abab44ddea11021f5abb89422a2f550837afcf25df9fc8d0db6b090602001610adb565b60408051600180825281830190925260609160009190602080830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061130557611305614ec0565b6001600160a01b0390921660209283029190910190910152919050565b61132a6129d5565b6113465760405162461bcd60e51b8152600401610a6890614e0a565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610adb565b61139c6129d5565b6113b85760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff16156114215760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f766564000000000000006044820152606401610a68565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa158015611487573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ab9190614f44565b6114f75760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a68565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610adb565b603f546001600160a01b03163314806115c357506115c36129d5565b6115df5760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b603754606090600090600160a81b900460ff161561164d5760405162461bcd60e51b8152600401610a6890614e41565b6000805160206151708339815191528054600119810161167f5760405162461bcd60e51b8152600401610a6890614e69565b6002825561168b6132fa565b50846001600160401b038111156116a4576116a4614f2e565b6040519080825280602002602001820160405280156116cd578160200160208202803683370190505b50935060005b85811015611749576116fc8787838181106116f0576116f0614ec0565b905060200201356134d6565b85828151811061170e5761170e614ec0565b60200260200101818152505084818151811061172c5761172c614ec0565b60200260200101518461173f9190614f66565b93506001016116d3565b5061177e6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130a4565b6117b56117b084601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b613837565b6001825550509250929050565b603f546001600160a01b03163314806117de57506117de6129d5565b6117fa5760405162461bcd60e51b8152600401610a6890614dc2565b6040516001600160a01b03821681527f45a9e715f8779ebeab88d3e8d081fb8b484b7730857e7c4478a95a5b1d8f79489060200160405180910390a16001600160a01b03811615611953576001600160a01b03811660009081526035602052604090205460ff1661187d5760405162461bcd60e51b8152600401610a6890614e91565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa1580156118e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119079190614f44565b6119535760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a68565b605080546001600160a01b0319166001600160a01b0392909216919091179055565b603f546001600160a01b031633148061199157506119916129d5565b6119ad5760405162461bcd60e51b8152600401610a6890614dc2565b6119b6816139da565b50565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614611a545760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610a68565b611a5d33613aa2565b565b6000611a6a82613b01565b92915050565b603754600160a81b900460ff1615611a9a5760405162461bcd60e51b8152600401610a6890614e41565b3360009081526035602052604090205460ff161515600114611af55760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a68565b3360009081526049602052604090205460ff161515600114611b545760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a68565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051611b85929190614f79565b60405180910390a1603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90611bbf9033908590600401614f79565b600060405180830381600087803b158015611bd957600080fd5b505af1158015611bed573d6000803e3d6000fd5b5050505050565b611bfc6129d5565b611c185760405162461bcd60e51b8152600401610a6890614e0a565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610adb565b611c556129d5565b611c715760405162461bcd60e51b8152600401610a6890614e0a565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610adb565b603f546001600160a01b0316331480611cdb5750611cdb6129d5565b611cf75760405162461bcd60e51b8152600401610a6890614dc2565b60008051602061517083398151915280546001198101611d295760405162461bcd60e51b8152600401610a6890614e69565b60028255611d3a8787878787613d63565b50600190555050505050565b603f546001600160a01b0316331480611d625750611d626129d5565b611d7e5760405162461bcd60e51b8152600401610a6890614dc2565b670de0b6b3a7640000811115611dc65760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b6044820152606401610a68565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610adb565b603f546001600160a01b0316331480611e175750611e176129d5565b611e335760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e736129d5565b611e8f5760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526049602052604090205460ff16611ee95760405162461bcd60e51b815260206004820152600f60248201526e139bdd081dda1a5d195b1a5cdd1959608a1b6044820152606401610a68565b6001600160a01b038116600081815260496020526040808220805460ff19169055517f0ec40967a61509853550658e51d0e4297f7cba244fe4adc8ba18b5631ac20e2f9190a250565b6037546000908190600160a81b900460ff1615611f615760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101611f935760405162461bcd60e51b8152600401610a6890614e69565b6002825560008511611fe75760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a68565b6000604e54116120395760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a68565b604c54600160801b90046001600160801b0316935061207d857f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b604b5461209391906001600160801b0316614f66565b92506120a86120a3856001614f66565b613fa2565b604c80546001600160801b03928316600160801b0292169190911790556120ce83613fa2565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff16918101919091526060810161211e87613fa2565b6001600160801b0316815260200161213585613fa2565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906121f09033908990600401614f79565b600060405180830381600087803b15801561220a57600080fd5b505af115801561221e573d6000803e3d6000fd5b5050505061222b85613837565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff161561229d5760405162461bcd60e51b8152600401610a6890614e41565b600080516020615170833981519152805460011981016122cf5760405162461bcd60e51b8152600401610a6890614e69565b600282556122dc836130fa565b506001905550565b603754600160a81b900460ff161561230e5760405162461bcd60e51b8152600401610a6890614e41565b3360009081526035602052604090205460ff1615156001146123695760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a68565b3360009081526049602052604090205460ff1615156001146123c85760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a68565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516123f9929190614f79565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611bbf9033908590600401614f79565b603754600160a81b900460ff161561245d5760405162461bcd60e51b8152600401610a6890614e41565b6000805160206151708339815191528054600119810161248f5760405162461bcd60e51b8152600401610a6890614e69565b6002825561249b6132fa565b506124a461400b565b5060019055565b603f546001600160a01b03163314806124c757506124c76129d5565b6124e35760405162461bcd60e51b8152600401610a6890614dc2565b600080516020615170833981519152805460011981016125155760405162461bcd60e51b8152600401610a6890614e69565b60028255611d3a308888888888614234565b600080516020615170833981519152805460011981016125595760405162461bcd60e51b8152600401610a6890614e69565b60028255612565612c9e565b505060019055565b6125756129d5565b6125915760405162461bcd60e51b8152600401610a6890614e0a565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610adb565b603f546001600160a01b03163314806125e257506125e26129d5565b6125fe5760405162461bcd60e51b8152600401610a6890614dc2565b612606612c9e565b5060006301e13380612619606484614f92565b6126239190614f92565b90506126396201518066b1a2bc2ec50000614f92565b8111156126785760405162461bcd60e51b815260206004820152600d60248201526c0a4c2e8ca40e8dede40d0d2ced609b1b6044820152606401610a68565b61268181613038565b604f80546001600160401b0392909216600160801b0267ffffffffffffffff60801b199092169190911790556040518181527fef46f143af5fead0010484fe7d6ec2e2972420faa76157f5a6075aa72e614cb59060200160405180910390a15050565b6126ec6129d5565b6127085760405162461bcd60e51b8152600401610a6890614e0a565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d90602001610adb565b6119b66132fa565b6060603680548060200260200160405190810160405280929190818152602001828054801561279d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161277f575b5050505050905090565b6127af6129d5565b6127cb5760405162461bcd60e51b8152600401610a6890614e0a565b600054610100900460ff16806127e4575060005460ff16155b6128475760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a68565b600054610100900460ff16158015612869576000805461ffff19166101011790555b6001600160a01b0382166128b85760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b6044820152606401610a68565b603c80546001600160a01b0384166001600160a01b03199091161790556037805461ffff60a01b1916600160a81b1790556000603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b55604080519182526020820190819052905161292891603691614b02565b50604f805467ffffffffffffffff60401b19166a093a8000000000000000001790558015610cd8576000805461ff00191690555050565b603f546001600160a01b031633148061297b575061297b6129d5565b6129975760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b60006129ed6000805160206151908339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612a225750612a226129d5565b612a3e5760405162461bcd60e51b8152600401610a6890614dc2565b611a5d6143c5565b612a4e6129d5565b612a6a5760405162461bcd60e51b8152600401610a6890614e0a565b612a92817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612ab26000805160206151908339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000610c1961445a565b6000612b7d603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b709190614f15565b612b7861445a565b6144ae565b50919050565b603754600090600160a81b900460ff1615612bb05760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101612be25760405162461bcd60e51b8152600401610a6890614e69565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115612c2357612c216132fa565b505b612c2c846134d6565b9250612c626001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130a4565b612c946117b084601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b5060019055919050565b603754600090600160a01b900460ff1615612ced5760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b6044820152606401610a68565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612d37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d5b9190614f15565b90506000612d6761445a565b905081600003612d7a5791506130359050565b600080612d8784846144ae565b90925090506000612d988386614f66565b90508481111580612da857508381115b15612db7575091949350505050565b612dc8826001600160401b03614681565b604f805477ffffffffffffffffffffffffffffffff000000000000000016600160c01b6001600160401b039384160267ffffffffffffffff19161742929092169190911790556042546001600160a01b031660008115612f045761271060435486612e339190614fb4565b612e3d9190614f92565b90508015612f0457848110612e9f5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b6064820152608401610a68565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612ed19085908590600401614f79565b600060405180830381600087803b158015612eeb57600080fd5b505af1158015612eff573d6000803e3d6000fd5b505050505b604080516001600160a01b0384168152602081018790529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a1603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc59190614f15565b83111561302b57603c546040516339a7919f60e01b8152600481018590526001600160a01b03909116906339a7919f90602401600060405180830381600087803b15801561301257600080fd5b505af1158015613026573d6000803e3d6000fd5b505050505b5093955050505050505b90565b60006001600160401b038211156130a05760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610a68565b5090565b6110dd8363a9059cbb60e01b84846040516024016130c3929190614f79565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614697565b6000811161314a5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a68565b600061317b82601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b90507f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516131ae929190614f79565b60405180910390a1603754600160a01b900460ff161580156131d25750603b548110155b156131e1576131df612c9e565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132139033908590600401614f79565b600060405180830381600087803b15801561322d57600080fd5b505af1158015613241573d6000803e3d6000fd5b5061327c9250506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169050333085614769565b6132846132fa565b50603a548110610cd857610cd861400b565b6000818311156132c6576132bf6132ad8385614eec565b6132b890600a6150b2565b85906147a7565b93506132f0565b818310156132f0576132ed6132db8484614eec565b6132e690600a6150b2565b85906147b3565b93505b50825b9392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c548084169686019690965292909404166060830152600092839161334c916150be565b6001600160801b03169050806000036133685760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156133cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133f39190614f15565b905060008360400151846020015161340b91906150be565b6001600160801b0316905080821161342857600094505050505090565b60006134348284614eec565b90508084106134435780613445565b835b955060008686602001516001600160801b03166134629190614f66565b905061346d81613fa2565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f463333906134c59083908a90918252602082015260400190565b60405180910390a150505050505090565b600080604e54116135295760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a68565b6000828152604d6020908152604091829020825160a08101845281546001600160a01b038116825260ff600160a01b82041615158285015264ffffffffff600160a81b90910481168286019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915288519081018952604b548084168252849004831697810197909752604c54808316988801989098529190960490951694840194909452604e549151909342926135f092909116614f66565b11156136345760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b6044820152606401610a68565b80602001516001600160801b031682608001516001600160801b0316111561369e5760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c69717569646974790000000000000000006044820152606401610a68565b81516001600160a01b031633146136e75760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b6044820152606401610a68565b60208201511561372b5760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b6044820152606401610a68565b6000848152604d60205260409020805460ff60a01b1916600160a01b179055606082015161378b906120a3906001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b816040015161379a91906150dd565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a361382f82606001516001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b949350505050565b6000603b5482101580156138555750603754600160a01b900460ff16155b1561386957613862612c9e565b9050613874565b61387161445a565b90505b60415415610cd857600081116138cc5760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e672072657175657374730000006044820152606401610a68565b600061394f82603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613925573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139499190614f15565b906147bf565b9050604154670de0b6b3a7640000821161397a5761397582670de0b6b3a7640000614eec565b61398c565b61398c670de0b6b3a764000083614eec565b11156110dd5760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f7200006044820152606401610a68565b6001600160a01b03811660009081526035602052604090205460ff16613a425760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f72746564000000000000006044820152606401610a68565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a8257600080fd5b505af1158015613a96573d6000803e3d6000fd5b505050506110dd6132fa565b6001600160a01b038116613af85760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610a68565b6119b6816147e0565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614613b4457506000919050565b6040516370a0823160e01b815230600482015282906001600160a01b038216906370a0823190602401602060405180830381865afa158015613b8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bae9190614f15565b60365490925060005b81811015613cd357600060368281548110613bd457613bd4614ec0565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af690602401602060405180830381865afa158015613c2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4e9190614f44565b15613cca57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f51522690602401602060405180830381865afa158015613c99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cbd9190614f15565b613cc79086614f66565b94505b50600101613bb7565b5060408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529091613d219086614f66565b1015613d3257506000949350505050565b805160408201516001600160801b0391821691613d50911686614f66565b613d5a9190614eec565b95945050505050565b6001600160a01b03851660009081526035602052604090205460ff16613dc15760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b6044820152606401610a68565b600183148015613dd15750600181145b8015613e3557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684846000818110613e1557613e15614ec0565b9050602002016020810190613e2a9190614c05565b6001600160a01b0316145b613e815760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920617373657420697320737570706f727465640000000000000000006044820152606401610a68565b613e89614847565b82826000818110613e9c57613e9c614ec0565b905060200201351115613ef15760405162461bcd60e51b815260206004820152601b60248201527f4e6f7420656e6f7567682061737365747320617661696c61626c6500000000006044820152606401610a68565b613f488583836000818110613f0857613f08614ec0565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166130a49092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613f8357600080fd5b505af1158015613f97573d6000803e3d6000fd5b505050505050505050565b60006001600160801b038211156130a05760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610a68565b6050546001600160a01b03168061401f5750565b6000614029614847565b905080600003614037575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015614081573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140a59190614f15565b905060006140ee7f000000000000000000000000000000000000000000000000000000000000000060ff1660126140e76039548661495590919063ffffffff16565b9190613296565b90508083116140fd5750505050565b60006141098285614eec565b9050846141406001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682846130a4565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061418e907f0000000000000000000000000000000000000000000000000000000000000000908690600401614f79565b600060405180830381600087803b1580156141a857600080fd5b505af11580156141bc573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b6001600160a01b03851660009081526035602052604090205460ff166142945760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b6044820152606401610a68565b8281146142e35760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d61746368000000000000006044820152606401610a68565b8260005b818110156143b257866001600160a01b031663d9caed128988888581811061431157614311614ec0565b90506020020160208101906143269190614c05565b87878681811061433857614338614ec0565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561438f57600080fd5b505af11580156143a3573d6000803e3d6000fd5b505050508060010190506142e7565b506143bb6132fa565b5050505050505050565b60365460005b8181101561445157603681815481106143e6576143e6614ec0565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b15801561442e57600080fd5b505af1158015614442573d6000803e3d6000fd5b505050508060010190506143cb565b50610cd86132fa565b6000610c1960127f000000000000000000000000000000000000000000000000000000000000000060ff166140e77f0000000000000000000000000000000000000000000000000000000000000000613b01565b6000806000603c60009054906101000a90046001600160a01b03166001600160a01b031663e696393a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614506573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061452a9190614f15565b905060006145388287614eec565b604f54909150600090614554906001600160401b031642614eec565b604f54600160c01b90046001600160401b031694509050801580614576575081155b8061458057508587115b8061459257506001600160401b034210155b156145a3576000945050505061467a565b6145ad8787614eec565b604f54909550600160401b90046001600160401b03166001811115614612576145ea856145db836002614fb4565b6145e59089614f92565b61496a565b94506145ff856145fa8389614f92565b614681565b945061460f866145fa8488614fb4565b95505b604f54614653908790670de0b6b3a764000090600160801b90046001600160401b031661463f8688614fb4565b6146499190614fb4565b6145fa9190614f92565b955061467386670de0b6b3a764000061464966470de4df82000087614fb4565b9550505050505b9250929050565b600081831061469057816132f3565b5090919050565b60006146ec826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166149799092919063ffffffff16565b8051909150156110dd578080602001905181019061470a9190614f44565b6110dd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a68565b6040516001600160a01b03808516602483015283166044820152606481018290526147a19085906323b872dd60e01b906084016130c3565b50505050565b60006132f38284614fb4565b60006132f38284614f92565b6000806147d484670de0b6b3a76400006147a7565b905061382f81846147b3565b806001600160a01b03166148006000805160206151908339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a360008051602061519083398151915255565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c5480831695850186905292909204166060830152600092839161489791906150be565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561490c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149309190614f15565b9050818111614943576000935050505090565b61494d8282614eec565b935050505090565b60006132f38383670de0b6b3a7640000614988565b600081831161469057816132f3565b606061382f84846000856149a1565b60008061499585856147a7565b9050613d5a81846147b3565b606082471015614a025760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a68565b843b614a505760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a68565b600080866001600160a01b03168587604051614a6c9190615120565b60006040518083038185875af1925050503d8060008114614aa9576040519150601f19603f3d011682016040523d82523d6000602084013e614aae565b606091505b5091509150614abe828286614ac9565b979650505050505050565b60608315614ad85750816132f3565b825115614ae85782518084602001fd5b8160405162461bcd60e51b8152600401610a68919061513c565b828054828255906000526020600020908101928215614b57579160200282015b82811115614b5757825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614b22565b506130a09291505b808211156130a05760008155600101614b5f565b600060208284031215614b8557600080fd5b5035919050565b80356001600160a01b0381168114614ba357600080fd5b919050565b60008060408385031215614bbb57600080fd5b614bc483614b8c565b946020939093013593505050565b600080600060608486031215614be757600080fd5b614bf084614b8c565b95602085013595506040909401359392505050565b600060208284031215614c1757600080fd5b6132f382614b8c565b602080825282518282018190526000918401906040840190835b81811015614c615783516001600160a01b0316835260209384019390920191600101614c3a565b509095945050505050565b60008083601f840112614c7e57600080fd5b5081356001600160401b03811115614c9557600080fd5b6020830191508360208260051b850101111561467a57600080fd5b60008060208385031215614cc357600080fd5b82356001600160401b03811115614cd957600080fd5b614ce585828601614c6c565b90969095509350505050565b6040808252835190820181905260009060208501906060840190835b81811015614d2b578351835260209384019390920191600101614d0d565b5050602093909301939093525092915050565b600080600080600060608688031215614d5657600080fd5b614d5f86614b8c565b945060208601356001600160401b03811115614d7a57600080fd5b614d8688828901614c6c565b90955093505060408601356001600160401b03811115614da557600080fd5b614db188828901614c6c565b969995985093965092949392505050565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60208082526015908201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115611a6a57611a6a614ed6565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614f2757600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215614f5657600080fd5b815180151581146132f357600080fd5b80820180821115611a6a57611a6a614ed6565b6001600160a01b03929092168252602082015260400190565b600082614faf57634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417611a6a57611a6a614ed6565b6001815b600184111561500657808504811115614fea57614fea614ed6565b6001841615614ff857908102905b60019390931c928002614fcf565b935093915050565b60008261501d57506001611a6a565b8161502a57506000611a6a565b8160018114615040576002811461504a57615066565b6001915050611a6a565b60ff84111561505b5761505b614ed6565b50506001821b611a6a565b5060208310610133831016604e8410600b8410161715615089575081810a611a6a565b6150966000198484614fcb565b80600019048211156150aa576150aa614ed6565b029392505050565b60006132f3838361500e565b6001600160801b038281168282160390811115611a6a57611a6a614ed6565b6001600160801b038181168382160190811115611a6a57611a6a614ed6565b60005b838110156151175781810151838201526020016150ff565b50506000910152565b600082516151328184602087016150fc565b9190910192915050565b602081526000825180602084015261515b8160408501602087016150fc565b601f01601f1916919091016040019291505056fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212200cdd5db756a1aea299f90ff8372c8ef5ec7b7ae12b5a635315185203b7aa4b3964736f6c634300081c0033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106104075760003560e01c80636217f3ea11610220578063ae69f3cb11610130578063c5f00841116100b8578063d4c3eea011610087578063d4c3eea0146109e6578063e6cc5432146109ee578063ea33b8e414610a02578063f844443614610a0a578063fac5bb9b14610a1d57600080fd5b8063c5f00841146109bb578063c7af3352146109c3578063c9919112146109cb578063d38bfff4146109d357600080fd5b8063b890ebf6116100ff578063b890ebf61461096b578063b9b17f9f1461097e578063bb7a632e14610986578063c3b28864146109a0578063c4d66de8146109a857600080fd5b8063ae69f3cb1461092a578063af14052c1461093d578063b2c9336d14610945578063b4925a201461095857600080fd5b806394828ffd116101b35780639fa1826e116101825780639fa1826e146108ec578063a0712d68146108f5578063a0aead4d14610908578063ab80dafb1461090f578063abaa99161461092257600080fd5b806394828ffd1461086957806395b166bc146108715780639be918e6146108845780639ee679e8146108c457600080fd5b8063840c4c7a116101ef578063840c4c7a146107925780638e510b52146107a55780638ec489a2146107ae578063937b2581146107c157600080fd5b80636217f3ea14610746578063663e64ce14610759578063773540b31461076c57806378f353a11461077f57600080fd5b806339ebf8231161031b578063527e83a8116102ae57806357bee9441161027d57806357bee944146106f45780635802a17214610707578063597c8910146107185780635d36b1901461072b5780635f5152261461073357600080fd5b8063527e83a8146106aa57806352d38e5d146106c457806353ca9f24146106cd578063570d8e1d146106e157600080fd5b806345e4213b116102ea57806345e4213b1461063b57806348e30f541461064457806349c1d54d146106655780634d5f46291461067857600080fd5b806339ebf823146105a95780633b8ae397146105ed5780633dbc911f146106005780634530820a1461060857600080fd5b80631a32aad61161039e5780632acada4d1161036d5780632acada4d146104f35780632da845a81461050857806331e19cfa1461051b578063362bd1a31461052357806338d52e0f1461058257600080fd5b80631a32aad6146104ad5780631cfbe7bc146104c05780631edfe3da146104d3578063207134b0146104ea57600080fd5b80631072cbea116103da5780631072cbea14610461578063156e29f614610474578063175188e8146104875780631816dd4a1461049a57600080fd5b80630493a0fa1461040c57806309f49bf5146104215780630acbda75146104295780630c340a241461043c575b600080fd5b61041f61041a366004614b73565b610a30565b005b61041f610ae6565b61041f610437366004614b73565b610b56565b610444610c01565b6040516001600160a01b0390911681526020015b60405180910390f35b61041f61046f366004614ba8565b610c1e565b61041f610482366004614bd2565b610cdc565b61041f610495366004614c05565b610d4f565b61041f6104a8366004614c05565b6110e2565b603c54610444906001600160a01b031681565b61041f6104ce366004614b73565b6111e9565b6104dc60395481565b604051908152602001610458565b6104dc60435481565b6104fb6112ab565b6040516104589190614c20565b61041f610516366004614c05565b611322565b6036546104dc565b604b54604c5461054f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610458565b6104447f000000000000000000000000000000000000000000000000000000000000000081565b6105d66105b7366004614c05565b6035602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610458565b61041f6105fb366004614c05565b611394565b61041f6115a7565b61062b610616366004614c05565b60496020526000908152604090205460ff1681565b6040519015158152602001610458565b6104dc604e5481565b610657610652366004614cb0565b61161d565b604051610458929190614cf1565b604254610444906001600160a01b031681565b604f5461069290600160c01b90046001600160401b031681565b6040516001600160401b039091168152602001610458565b604f5461069290600160801b90046001600160401b031681565b6104dc603b5481565b60375461062b90600160a01b900460ff1681565b603f54610444906001600160a01b031681565b61041f610702366004614c05565b6117c2565b603c546001600160a01b0316610444565b61041f610726366004614c05565b611975565b61041f6119b9565b6104dc610741366004614c05565b611a5f565b61041f610754366004614b73565b611a70565b61041f610767366004614b73565b611bf4565b61041f61077a366004614c05565b611c4d565b604f54610692906001600160401b031681565b61041f6107a0366004614d3e565b611cbf565b6104dc60415481565b61041f6107bc366004614b73565b611d46565b6108226107cf366004614b73565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a001610458565b61041f611dfb565b61041f61087f366004614c05565b611e6b565b61062b610892366004614c05565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b6108d76108d2366004614b73565b611f32565b60408051928352602083019190915201610458565b6104dc603a5481565b61041f610903366004614b73565b612273565b60016104dc565b61041f61091d366004614b73565b6122e4565b61041f612433565b61041f610938366004614d3e565b6124ab565b61041f612527565b61041f610953366004614b73565b61256d565b61041f610966366004614b73565b6125c6565b61041f610979366004614b73565b6126e4565b61041f61273d565b604f5461069290600160401b90046001600160401b031681565b6104fb612745565b61041f6109b6366004614c05565b6127a7565b61041f61295f565b61062b6129d5565b61041f612a06565b61041f6109e1366004614c05565b612a46565b6104dc612aea565b60375461062b90600160a81b900460ff1681565b6104dc612af4565b6104dc610a18366004614b73565b612b83565b605054610444906001600160a01b031681565b603f546001600160a01b0316331480610a4c5750610a4c6129d5565b610a715760405162461bcd60e51b8152600401610a6890614dc2565b60405180910390fd5b610a79612c9e565b50610a8381613038565b604f80546001600160401b0392909216600160401b0267ffffffffffffffff60401b199092169190911790556040518181527f406e15fbca1d8ded2dbb06765fea3a54f18395c54125a4c9916dd00ea14ee15e906020015b60405180910390a150565b603f546001600160a01b0316331480610b025750610b026129d5565b610b1e5760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b610b5e6129d5565b610b7a5760405162461bcd60e51b8152600401610a6890614e0a565b611388811115610bcc5760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f7420657863656564203530250000000000000000006044820152606401610a68565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c790602001610adb565b6000610c196000805160206151908339815191525490565b905090565b610c266129d5565b610c425760405162461bcd60e51b8152600401610a6890614e0a565b816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610cbc5760405162461bcd60e51b815260206004820152601660248201527513db9b1e481d5b9cdd5c1c1bdc9d195908185cdcd95d60521b6044820152606401610a68565b610cd8610cc7610c01565b6001600160a01b03841690836130a4565b5050565b603754600160a81b900460ff1615610d065760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101610d385760405162461bcd60e51b8152600401610a6890614e69565b60028255610d45846130fa565b5060019055505050565b610d576129d5565b610d735760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff16610dab5760405162461bcd60e51b8152600401610a6890614e91565b6050546001600160a01b03808316911603610e085760405162461bcd60e51b815260206004820152601d60248201527f53747261746567792069732064656661756c7420666f722061737365740000006044820152606401610a68565b6036548060005b82811015610e5e57836001600160a01b031660368281548110610e3457610e34614ec0565b6000918252602090912001546001600160a01b031603610e5657809150610e5e565b600101610e0f565b50818110156110dd576036610e74600184614eec565b81548110610e8457610e84614ec0565b600091825260209091200154603680546001600160a01b039092169183908110610eb057610eb0614ec0565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610eef57610eef614eff565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038516808352603582526040808420805460ff1990811690915560499093528084208054909316909255815163429c145b60e11b815291518693919263853828b692600480830193919282900301818387803b158015610f7b57600080fd5b505af1158015610f8f573d6000803e3d6000fd5b5060009250610fcd91506509184e72a000905060ff7f0000000000000000000000000000000000000000000000000000000000000000166012613296565b604051632fa8a91360e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192508291841690635f51522690602401602060405180830381865afa158015611038573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105c9190614f15565b1061109e5760405162461bcd60e51b81526020600482015260126024820152715374726174656779206861732066756e647360701b6044820152606401610a68565b6040516001600160a01b03861681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49060200160405180910390a150505b505050565b6110ea6129d5565b6111065760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff1661113e5760405162461bcd60e51b8152600401610a6890614e91565b6001600160a01b03811660009081526049602052604090205460ff161561119d5760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481dda1a5d195b1a5cdd1959606a1b6044820152606401610a68565b6001600160a01b038116600081815260496020526040808220805460ff19166001179055517f47c8c96a5942f094264111c5fe7f6a4fe86efe63254a6fa7afa5fc84f07d58e89190a250565b6111f16129d5565b61120d5760405162461bcd60e51b8152600401610a6890614e0a565b80158061122a5750610258811015801561122a57506213c6808111155b6112765760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636c61696d2064656c617920706572696f640000000000006044820152606401610a68565b604e8190556040518181527fc59f5e32049abab44ddea11021f5abb89422a2f550837afcf25df9fc8d0db6b090602001610adb565b60408051600180825281830190925260609160009190602080830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061130557611305614ec0565b6001600160a01b0390921660209283029190910190910152919050565b61132a6129d5565b6113465760405162461bcd60e51b8152600401610a6890614e0a565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610adb565b61139c6129d5565b6113b85760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff16156114215760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f766564000000000000006044820152606401610a68565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa158015611487573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ab9190614f44565b6114f75760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a68565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610adb565b603f546001600160a01b03163314806115c357506115c36129d5565b6115df5760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b603754606090600090600160a81b900460ff161561164d5760405162461bcd60e51b8152600401610a6890614e41565b6000805160206151708339815191528054600119810161167f5760405162461bcd60e51b8152600401610a6890614e69565b6002825561168b6132fa565b50846001600160401b038111156116a4576116a4614f2e565b6040519080825280602002602001820160405280156116cd578160200160208202803683370190505b50935060005b85811015611749576116fc8787838181106116f0576116f0614ec0565b905060200201356134d6565b85828151811061170e5761170e614ec0565b60200260200101818152505084818151811061172c5761172c614ec0565b60200260200101518461173f9190614f66565b93506001016116d3565b5061177e6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130a4565b6117b56117b084601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b613837565b6001825550509250929050565b603f546001600160a01b03163314806117de57506117de6129d5565b6117fa5760405162461bcd60e51b8152600401610a6890614dc2565b6040516001600160a01b03821681527f45a9e715f8779ebeab88d3e8d081fb8b484b7730857e7c4478a95a5b1d8f79489060200160405180910390a16001600160a01b03811615611953576001600160a01b03811660009081526035602052604090205460ff1661187d5760405162461bcd60e51b8152600401610a6890614e91565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa1580156118e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119079190614f44565b6119535760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a68565b605080546001600160a01b0319166001600160a01b0392909216919091179055565b603f546001600160a01b031633148061199157506119916129d5565b6119ad5760405162461bcd60e51b8152600401610a6890614dc2565b6119b6816139da565b50565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614611a545760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610a68565b611a5d33613aa2565b565b6000611a6a82613b01565b92915050565b603754600160a81b900460ff1615611a9a5760405162461bcd60e51b8152600401610a6890614e41565b3360009081526035602052604090205460ff161515600114611af55760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a68565b3360009081526049602052604090205460ff161515600114611b545760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a68565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051611b85929190614f79565b60405180910390a1603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90611bbf9033908590600401614f79565b600060405180830381600087803b158015611bd957600080fd5b505af1158015611bed573d6000803e3d6000fd5b5050505050565b611bfc6129d5565b611c185760405162461bcd60e51b8152600401610a6890614e0a565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610adb565b611c556129d5565b611c715760405162461bcd60e51b8152600401610a6890614e0a565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610adb565b603f546001600160a01b0316331480611cdb5750611cdb6129d5565b611cf75760405162461bcd60e51b8152600401610a6890614dc2565b60008051602061517083398151915280546001198101611d295760405162461bcd60e51b8152600401610a6890614e69565b60028255611d3a8787878787613d63565b50600190555050505050565b603f546001600160a01b0316331480611d625750611d626129d5565b611d7e5760405162461bcd60e51b8152600401610a6890614dc2565b670de0b6b3a7640000811115611dc65760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b6044820152606401610a68565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610adb565b603f546001600160a01b0316331480611e175750611e176129d5565b611e335760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e736129d5565b611e8f5760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526049602052604090205460ff16611ee95760405162461bcd60e51b815260206004820152600f60248201526e139bdd081dda1a5d195b1a5cdd1959608a1b6044820152606401610a68565b6001600160a01b038116600081815260496020526040808220805460ff19169055517f0ec40967a61509853550658e51d0e4297f7cba244fe4adc8ba18b5631ac20e2f9190a250565b6037546000908190600160a81b900460ff1615611f615760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101611f935760405162461bcd60e51b8152600401610a6890614e69565b6002825560008511611fe75760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a68565b6000604e54116120395760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a68565b604c54600160801b90046001600160801b0316935061207d857f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b604b5461209391906001600160801b0316614f66565b92506120a86120a3856001614f66565b613fa2565b604c80546001600160801b03928316600160801b0292169190911790556120ce83613fa2565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff16918101919091526060810161211e87613fa2565b6001600160801b0316815260200161213585613fa2565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906121f09033908990600401614f79565b600060405180830381600087803b15801561220a57600080fd5b505af115801561221e573d6000803e3d6000fd5b5050505061222b85613837565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff161561229d5760405162461bcd60e51b8152600401610a6890614e41565b600080516020615170833981519152805460011981016122cf5760405162461bcd60e51b8152600401610a6890614e69565b600282556122dc836130fa565b506001905550565b603754600160a81b900460ff161561230e5760405162461bcd60e51b8152600401610a6890614e41565b3360009081526035602052604090205460ff1615156001146123695760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a68565b3360009081526049602052604090205460ff1615156001146123c85760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a68565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516123f9929190614f79565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611bbf9033908590600401614f79565b603754600160a81b900460ff161561245d5760405162461bcd60e51b8152600401610a6890614e41565b6000805160206151708339815191528054600119810161248f5760405162461bcd60e51b8152600401610a6890614e69565b6002825561249b6132fa565b506124a461400b565b5060019055565b603f546001600160a01b03163314806124c757506124c76129d5565b6124e35760405162461bcd60e51b8152600401610a6890614dc2565b600080516020615170833981519152805460011981016125155760405162461bcd60e51b8152600401610a6890614e69565b60028255611d3a308888888888614234565b600080516020615170833981519152805460011981016125595760405162461bcd60e51b8152600401610a6890614e69565b60028255612565612c9e565b505060019055565b6125756129d5565b6125915760405162461bcd60e51b8152600401610a6890614e0a565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610adb565b603f546001600160a01b03163314806125e257506125e26129d5565b6125fe5760405162461bcd60e51b8152600401610a6890614dc2565b612606612c9e565b5060006301e13380612619606484614f92565b6126239190614f92565b90506126396201518066b1a2bc2ec50000614f92565b8111156126785760405162461bcd60e51b815260206004820152600d60248201526c0a4c2e8ca40e8dede40d0d2ced609b1b6044820152606401610a68565b61268181613038565b604f80546001600160401b0392909216600160801b0267ffffffffffffffff60801b199092169190911790556040518181527fef46f143af5fead0010484fe7d6ec2e2972420faa76157f5a6075aa72e614cb59060200160405180910390a15050565b6126ec6129d5565b6127085760405162461bcd60e51b8152600401610a6890614e0a565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d90602001610adb565b6119b66132fa565b6060603680548060200260200160405190810160405280929190818152602001828054801561279d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161277f575b5050505050905090565b6127af6129d5565b6127cb5760405162461bcd60e51b8152600401610a6890614e0a565b600054610100900460ff16806127e4575060005460ff16155b6128475760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a68565b600054610100900460ff16158015612869576000805461ffff19166101011790555b6001600160a01b0382166128b85760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b6044820152606401610a68565b603c80546001600160a01b0384166001600160a01b03199091161790556037805461ffff60a01b1916600160a81b1790556000603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b55604080519182526020820190819052905161292891603691614b02565b50604f805467ffffffffffffffff60401b19166a093a8000000000000000001790558015610cd8576000805461ff00191690555050565b603f546001600160a01b031633148061297b575061297b6129d5565b6129975760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b60006129ed6000805160206151908339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612a225750612a226129d5565b612a3e5760405162461bcd60e51b8152600401610a6890614dc2565b611a5d6143c5565b612a4e6129d5565b612a6a5760405162461bcd60e51b8152600401610a6890614e0a565b612a92817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612ab26000805160206151908339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000610c1961445a565b6000612b7d603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b709190614f15565b612b7861445a565b6144ae565b50919050565b603754600090600160a81b900460ff1615612bb05760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101612be25760405162461bcd60e51b8152600401610a6890614e69565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115612c2357612c216132fa565b505b612c2c846134d6565b9250612c626001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130a4565b612c946117b084601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b5060019055919050565b603754600090600160a01b900460ff1615612ced5760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b6044820152606401610a68565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612d37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d5b9190614f15565b90506000612d6761445a565b905081600003612d7a5791506130359050565b600080612d8784846144ae565b90925090506000612d988386614f66565b90508481111580612da857508381115b15612db7575091949350505050565b612dc8826001600160401b03614681565b604f805477ffffffffffffffffffffffffffffffff000000000000000016600160c01b6001600160401b039384160267ffffffffffffffff19161742929092169190911790556042546001600160a01b031660008115612f045761271060435486612e339190614fb4565b612e3d9190614f92565b90508015612f0457848110612e9f5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b6064820152608401610a68565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612ed19085908590600401614f79565b600060405180830381600087803b158015612eeb57600080fd5b505af1158015612eff573d6000803e3d6000fd5b505050505b604080516001600160a01b0384168152602081018790529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a1603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc59190614f15565b83111561302b57603c546040516339a7919f60e01b8152600481018590526001600160a01b03909116906339a7919f90602401600060405180830381600087803b15801561301257600080fd5b505af1158015613026573d6000803e3d6000fd5b505050505b5093955050505050505b90565b60006001600160401b038211156130a05760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610a68565b5090565b6110dd8363a9059cbb60e01b84846040516024016130c3929190614f79565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614697565b6000811161314a5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a68565b600061317b82601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b90507f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516131ae929190614f79565b60405180910390a1603754600160a01b900460ff161580156131d25750603b548110155b156131e1576131df612c9e565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132139033908590600401614f79565b600060405180830381600087803b15801561322d57600080fd5b505af1158015613241573d6000803e3d6000fd5b5061327c9250506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169050333085614769565b6132846132fa565b50603a548110610cd857610cd861400b565b6000818311156132c6576132bf6132ad8385614eec565b6132b890600a6150b2565b85906147a7565b93506132f0565b818310156132f0576132ed6132db8484614eec565b6132e690600a6150b2565b85906147b3565b93505b50825b9392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c548084169686019690965292909404166060830152600092839161334c916150be565b6001600160801b03169050806000036133685760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156133cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133f39190614f15565b905060008360400151846020015161340b91906150be565b6001600160801b0316905080821161342857600094505050505090565b60006134348284614eec565b90508084106134435780613445565b835b955060008686602001516001600160801b03166134629190614f66565b905061346d81613fa2565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f463333906134c59083908a90918252602082015260400190565b60405180910390a150505050505090565b600080604e54116135295760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a68565b6000828152604d6020908152604091829020825160a08101845281546001600160a01b038116825260ff600160a01b82041615158285015264ffffffffff600160a81b90910481168286019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915288519081018952604b548084168252849004831697810197909752604c54808316988801989098529190960490951694840194909452604e549151909342926135f092909116614f66565b11156136345760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b6044820152606401610a68565b80602001516001600160801b031682608001516001600160801b0316111561369e5760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c69717569646974790000000000000000006044820152606401610a68565b81516001600160a01b031633146136e75760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b6044820152606401610a68565b60208201511561372b5760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b6044820152606401610a68565b6000848152604d60205260409020805460ff60a01b1916600160a01b179055606082015161378b906120a3906001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b816040015161379a91906150dd565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a361382f82606001516001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b949350505050565b6000603b5482101580156138555750603754600160a01b900460ff16155b1561386957613862612c9e565b9050613874565b61387161445a565b90505b60415415610cd857600081116138cc5760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e672072657175657374730000006044820152606401610a68565b600061394f82603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613925573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139499190614f15565b906147bf565b9050604154670de0b6b3a7640000821161397a5761397582670de0b6b3a7640000614eec565b61398c565b61398c670de0b6b3a764000083614eec565b11156110dd5760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f7200006044820152606401610a68565b6001600160a01b03811660009081526035602052604090205460ff16613a425760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f72746564000000000000006044820152606401610a68565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a8257600080fd5b505af1158015613a96573d6000803e3d6000fd5b505050506110dd6132fa565b6001600160a01b038116613af85760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610a68565b6119b6816147e0565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614613b4457506000919050565b6040516370a0823160e01b815230600482015282906001600160a01b038216906370a0823190602401602060405180830381865afa158015613b8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bae9190614f15565b60365490925060005b81811015613cd357600060368281548110613bd457613bd4614ec0565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af690602401602060405180830381865afa158015613c2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4e9190614f44565b15613cca57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f51522690602401602060405180830381865afa158015613c99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cbd9190614f15565b613cc79086614f66565b94505b50600101613bb7565b5060408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529091613d219086614f66565b1015613d3257506000949350505050565b805160408201516001600160801b0391821691613d50911686614f66565b613d5a9190614eec565b95945050505050565b6001600160a01b03851660009081526035602052604090205460ff16613dc15760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b6044820152606401610a68565b600183148015613dd15750600181145b8015613e3557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684846000818110613e1557613e15614ec0565b9050602002016020810190613e2a9190614c05565b6001600160a01b0316145b613e815760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920617373657420697320737570706f727465640000000000000000006044820152606401610a68565b613e89614847565b82826000818110613e9c57613e9c614ec0565b905060200201351115613ef15760405162461bcd60e51b815260206004820152601b60248201527f4e6f7420656e6f7567682061737365747320617661696c61626c6500000000006044820152606401610a68565b613f488583836000818110613f0857613f08614ec0565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166130a49092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613f8357600080fd5b505af1158015613f97573d6000803e3d6000fd5b505050505050505050565b60006001600160801b038211156130a05760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610a68565b6050546001600160a01b03168061401f5750565b6000614029614847565b905080600003614037575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015614081573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140a59190614f15565b905060006140ee7f000000000000000000000000000000000000000000000000000000000000000060ff1660126140e76039548661495590919063ffffffff16565b9190613296565b90508083116140fd5750505050565b60006141098285614eec565b9050846141406001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682846130a4565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061418e907f0000000000000000000000000000000000000000000000000000000000000000908690600401614f79565b600060405180830381600087803b1580156141a857600080fd5b505af11580156141bc573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b6001600160a01b03851660009081526035602052604090205460ff166142945760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b6044820152606401610a68565b8281146142e35760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d61746368000000000000006044820152606401610a68565b8260005b818110156143b257866001600160a01b031663d9caed128988888581811061431157614311614ec0565b90506020020160208101906143269190614c05565b87878681811061433857614338614ec0565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561438f57600080fd5b505af11580156143a3573d6000803e3d6000fd5b505050508060010190506142e7565b506143bb6132fa565b5050505050505050565b60365460005b8181101561445157603681815481106143e6576143e6614ec0565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b15801561442e57600080fd5b505af1158015614442573d6000803e3d6000fd5b505050508060010190506143cb565b50610cd86132fa565b6000610c1960127f000000000000000000000000000000000000000000000000000000000000000060ff166140e77f0000000000000000000000000000000000000000000000000000000000000000613b01565b6000806000603c60009054906101000a90046001600160a01b03166001600160a01b031663e696393a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614506573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061452a9190614f15565b905060006145388287614eec565b604f54909150600090614554906001600160401b031642614eec565b604f54600160c01b90046001600160401b031694509050801580614576575081155b8061458057508587115b8061459257506001600160401b034210155b156145a3576000945050505061467a565b6145ad8787614eec565b604f54909550600160401b90046001600160401b03166001811115614612576145ea856145db836002614fb4565b6145e59089614f92565b61496a565b94506145ff856145fa8389614f92565b614681565b945061460f866145fa8488614fb4565b95505b604f54614653908790670de0b6b3a764000090600160801b90046001600160401b031661463f8688614fb4565b6146499190614fb4565b6145fa9190614f92565b955061467386670de0b6b3a764000061464966470de4df82000087614fb4565b9550505050505b9250929050565b600081831061469057816132f3565b5090919050565b60006146ec826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166149799092919063ffffffff16565b8051909150156110dd578080602001905181019061470a9190614f44565b6110dd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a68565b6040516001600160a01b03808516602483015283166044820152606481018290526147a19085906323b872dd60e01b906084016130c3565b50505050565b60006132f38284614fb4565b60006132f38284614f92565b6000806147d484670de0b6b3a76400006147a7565b905061382f81846147b3565b806001600160a01b03166148006000805160206151908339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a360008051602061519083398151915255565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c5480831695850186905292909204166060830152600092839161489791906150be565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561490c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149309190614f15565b9050818111614943576000935050505090565b61494d8282614eec565b935050505090565b60006132f38383670de0b6b3a7640000614988565b600081831161469057816132f3565b606061382f84846000856149a1565b60008061499585856147a7565b9050613d5a81846147b3565b606082471015614a025760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a68565b843b614a505760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a68565b600080866001600160a01b03168587604051614a6c9190615120565b60006040518083038185875af1925050503d8060008114614aa9576040519150601f19603f3d011682016040523d82523d6000602084013e614aae565b606091505b5091509150614abe828286614ac9565b979650505050505050565b60608315614ad85750816132f3565b825115614ae85782518084602001fd5b8160405162461bcd60e51b8152600401610a68919061513c565b828054828255906000526020600020908101928215614b57579160200282015b82811115614b5757825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614b22565b506130a09291505b808211156130a05760008155600101614b5f565b600060208284031215614b8557600080fd5b5035919050565b80356001600160a01b0381168114614ba357600080fd5b919050565b60008060408385031215614bbb57600080fd5b614bc483614b8c565b946020939093013593505050565b600080600060608486031215614be757600080fd5b614bf084614b8c565b95602085013595506040909401359392505050565b600060208284031215614c1757600080fd5b6132f382614b8c565b602080825282518282018190526000918401906040840190835b81811015614c615783516001600160a01b0316835260209384019390920191600101614c3a565b509095945050505050565b60008083601f840112614c7e57600080fd5b5081356001600160401b03811115614c9557600080fd5b6020830191508360208260051b850101111561467a57600080fd5b60008060208385031215614cc357600080fd5b82356001600160401b03811115614cd957600080fd5b614ce585828601614c6c565b90969095509350505050565b6040808252835190820181905260009060208501906060840190835b81811015614d2b578351835260209384019390920191600101614d0d565b5050602093909301939093525092915050565b600080600080600060608688031215614d5657600080fd5b614d5f86614b8c565b945060208601356001600160401b03811115614d7a57600080fd5b614d8688828901614c6c565b90955093505060408601356001600160401b03811115614da557600080fd5b614db188828901614c6c565b969995985093965092949392505050565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60208082526015908201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115611a6a57611a6a614ed6565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614f2757600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215614f5657600080fd5b815180151581146132f357600080fd5b80820180821115611a6a57611a6a614ed6565b6001600160a01b03929092168252602082015260400190565b600082614faf57634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417611a6a57611a6a614ed6565b6001815b600184111561500657808504811115614fea57614fea614ed6565b6001841615614ff857908102905b60019390931c928002614fcf565b935093915050565b60008261501d57506001611a6a565b8161502a57506000611a6a565b8160018114615040576002811461504a57615066565b6001915050611a6a565b60ff84111561505b5761505b614ed6565b50506001821b611a6a565b5060208310610133831016604e8410600b8410161715615089575081810a611a6a565b6150966000198484614fcb565b80600019048211156150aa576150aa614ed6565b029392505050565b60006132f3838361500e565b6001600160801b038281168282160390811115611a6a57611a6a614ed6565b6001600160801b038181168382160190811115611a6a57611a6a614ed6565b60005b838110156151175781810151838201526020016150ff565b50506000910152565b600082516151328184602087016150fc565b9190910192915050565b602081526000825180602084015261515b8160408501602087016150fc565b601f01601f1916919091016040019291505056fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212200cdd5db756a1aea299f90ff8372c8ef5ec7b7ae12b5a635315185203b7aa4b3964736f6c634300081c0033", + "numDeployments": 2, + "solcInputHash": "f4384e86fd2a870879603d18d53c5b16", + "metadata": "{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"AllocateThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"AssetAllocated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"DefaultStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dripDuration\",\"type\":\"uint256\"}],\"name\":\"DripDurationChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"MaxSupplyDiffChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newOperator\",\"type\":\"address\"}],\"name\":\"OperatorUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebasePaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rebaseRatePerSecond\",\"type\":\"uint256\"}],\"name\":\"RebasePerSecondMaxChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebaseUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"StrategistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyAddedToMintWhitelist\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyRemovedFromMintWhitelist\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"TrusteeAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"TrusteeFeeBpsChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"VaultBufferUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newDelay\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_claimable\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newClaimable\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimable\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_queued\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_yield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"YieldDistribution\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddr\",\"type\":\"address\"}],\"name\":\"addStrategyToMintWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"addWithdrawalQueueLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"allocate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"approveStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"asset\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"autoAllocateThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"burnForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capitalPaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"claimWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_requestIds\",\"type\":\"uint256[]\"}],\"name\":\"claimWithdrawals\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"totalAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultStrategy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyToAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"depositToStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dripDuration\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAssets\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllStrategies\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAssetCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStrategyCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_oToken\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isMintWhitelistedStrategy\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"isSupportedAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRebase\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxSupplyDiff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mintForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oToken\",\"outputs\":[{\"internalType\":\"contract OUSD\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oUSD\",\"outputs\":[{\"internalType\":\"contract OUSD\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatorAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previewYield\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"yield\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePerSecondMax\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePerSecondTarget\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"removeStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddr\",\"type\":\"address\"}],\"name\":\"removeStrategyFromMintWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"requestWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"queued\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setAutoAllocateThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"setDefaultStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dripDuration\",\"type\":\"uint256\"}],\"name\":\"setDripDuration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"setMaxSupplyDiff\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_operator\",\"type\":\"address\"}],\"name\":\"setOperatorAddr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"apr\",\"type\":\"uint256\"}],\"name\":\"setRebaseRateMax\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setStrategistAddr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setTrusteeAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"setTrusteeFeeBps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"setVaultBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_delay\",\"type\":\"uint256\"}],\"name\":\"setWithdrawalClaimDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"strategies\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isSupported\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"_deprecated\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategistAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"transferToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAllFromStrategies\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"}],\"name\":\"withdrawAllFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyFromAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"withdrawFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalClaimDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalQueueMetadata\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimable\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimed\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"nextWithdrawalIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"withdrawalRequests\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"claimed\",\"type\":\"bool\"},{\"internalType\":\"uint40\",\"name\":\"timestamp\",\"type\":\"uint40\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"addStrategyToMintWhitelist(address)\":{\"params\":{\"strategyAddr\":\"Strategy address\"}},\"addWithdrawalQueueLiquidity()\":{\"details\":\"is called from the Native Staking strategy when validator withdrawals are processed. It also called before any WETH is allocated to a strategy.\"},\"approveStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to add\"}},\"burnForStrategy(uint256)\":{\"details\":\"Notice: can't use `nonReentrant` modifier since the `redeem` function could require withdrawal on an AMO strategy and that one can call `burnForStrategy` while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\",\"params\":{\"_amount\":\"Amount of OToken to burn\"}},\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of asset\"},\"returns\":{\"_0\":\"uint256 Balance of asset in decimals of asset\"}},\"claimWithdrawal(uint256)\":{\"params\":{\"_requestId\":\"Unique ID for the withdrawal request\"},\"returns\":{\"amount\":\"Amount of asset transferred to the withdrawer\"}},\"claimWithdrawals(uint256[])\":{\"params\":{\"_requestIds\":\"Unique ID of each withdrawal request\"},\"returns\":{\"amounts\":\"Amount of asset received for each request\",\"totalAmount\":\"Total amount of asset transferred to the withdrawer\"}},\"depositToStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to deposit.\",\"_assets\":\"Array of asset address that will be deposited into the strategy.\",\"_strategyToAddress\":\"Address of the Strategy to deposit asset into.\"}},\"isSupportedAsset(address)\":{\"params\":{\"_asset\":\"address of the asset\"},\"returns\":{\"_0\":\"true if supported\"}},\"mint(address,uint256,uint256)\":{\"details\":\"Deprecated: use `mint(uint256 _amount)` instead.Deprecated: param _asset Address of the asset being depositedDeprecated: param _minimumOusdAmount Minimum OTokens to mint\",\"params\":{\"_amount\":\"Amount of the asset being deposited\"}},\"mint(uint256)\":{\"params\":{\"_amount\":\"Amount of the asset being deposited\"}},\"mintForStrategy(uint256)\":{\"params\":{\"_amount\":\"Amount of OToken to mint Notice: can't use `nonReentrant` modifier since the `mint` function can call `allocate`, and that can trigger an AMO strategy to call this function while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\"}},\"previewYield()\":{\"returns\":{\"yield\":\"amount of expected yield\"}},\"rebase()\":{\"details\":\"Restricted to the Operator, Strategist or Governor.\"},\"removeStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to remove\"}},\"removeStrategyFromMintWhitelist(address)\":{\"params\":{\"strategyAddr\":\"Strategy address\"}},\"requestWithdrawal(uint256)\":{\"params\":{\"_amount\":\"Amount of OToken to burn.\"},\"returns\":{\"queued\":\"Cumulative total of all asset queued including already claimed requests.\",\"requestId\":\"Unique ID for the withdrawal request\"}},\"setAutoAllocateThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setDefaultStrategy(address)\":{\"params\":{\"_strategy\":\"Address of the Strategy\"}},\"setDripDuration(uint256)\":{\"params\":{\"_dripDuration\":\"Time in seconds to target a constant yield rate\"}},\"setOperatorAddr(address)\":{\"params\":{\"_operator\":\"New operator address. May be set to the zero address to disable operator-initiated rebases.\"}},\"setRebaseRateMax(uint256)\":{\"params\":{\"apr\":\"in 1e18 notation. 3 * 1e18 = 3% APR\"}},\"setStrategistAddr(address)\":{\"params\":{\"_address\":\"Address of Strategist\"}},\"setVaultBuffer(uint256)\":{\"params\":{\"_vaultBuffer\":\"Percentage using 18 decimals. 100% = 1e18.\"}},\"setWithdrawalClaimDelay(uint256)\":{\"params\":{\"_delay\":\"Delay period (should be between 10 mins to 7 days). Set to 0 to disable async withdrawals\"}},\"totalValue()\":{\"returns\":{\"value\":\"Total value in USD/ETH (1e18)\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"transferToken(address,uint256)\":{\"params\":{\"_amount\":\"Amount of the asset to transfer\",\"_asset\":\"Address for the asset\"}},\"withdrawAllFromStrategy(address)\":{\"params\":{\"_strategyAddr\":\"Strategy address.\"}},\"withdrawFromStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to withdraw.\",\"_assets\":\"Array of asset address that will be withdrawn from the strategy.\",\"_strategyFromAddress\":\"Address of the Strategy to withdraw asset from.\"}}},\"title\":\"OETH Base VaultAdmin Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"addStrategyToMintWhitelist(address)\":{\"notice\":\"Adds a strategy to the mint whitelist. Reverts if strategy isn't approved on Vault.\"},\"addWithdrawalQueueLiquidity()\":{\"notice\":\"Adds WETH to the withdrawal queue if there is a funding shortfall.\"},\"allocate()\":{\"notice\":\"Allocate unallocated funds on Vault to strategies.\"},\"approveStrategy(address)\":{\"notice\":\"Add a strategy to the Vault.\"},\"autoAllocateThreshold()\":{\"notice\":\"OToken mints over this amount automatically allocate funds. 18 decimals.\"},\"burnForStrategy(uint256)\":{\"notice\":\"Burn OTokens for an allowed Strategy\"},\"capitalPaused()\":{\"notice\":\"pause operations that change the OToken supply. eg mint, redeem, allocate, mint/burn for strategy\"},\"checkBalance(address)\":{\"notice\":\"Get the balance of an asset held in Vault and all strategies.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"claimWithdrawal(uint256)\":{\"notice\":\"Claim a previously requested withdrawal once it is claimable. This request can be claimed once the withdrawal queue's `claimable` amount is greater than or equal this request's `queued` amount and 10 minutes has passed. If the requests is not claimable, the transaction will revert with `Queue pending liquidity`. If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`. OToken is converted to asset at 1:1.\"},\"claimWithdrawals(uint256[])\":{\"notice\":\"Claim a previously requested withdrawals once they are claimable. This requests can be claimed once the withdrawal queue's `claimable` amount is greater than or equal each request's `queued` amount and 10 minutes has passed. If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`. If one of the requests is not older than 10 minutes, the whole transaction will revert with `Claim delay not met`.\"},\"defaultStrategy()\":{\"notice\":\"Default strategy for asset\"},\"depositToStrategy(address,address[],uint256[])\":{\"notice\":\"Deposit multiple asset from the vault into the strategy.\"},\"dripDuration()\":{\"notice\":\"Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\"},\"getAllAssets()\":{\"notice\":\"Return all vault asset addresses in order\"},\"getAllStrategies()\":{\"notice\":\"Return the array of all strategies\"},\"getAssetCount()\":{\"notice\":\"Return the number of asset supported by the Vault.\"},\"getStrategyCount()\":{\"notice\":\"Return the number of strategies active on the Vault.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"isSupportedAsset(address)\":{\"notice\":\"Returns whether the vault supports the asset\"},\"lastRebase()\":{\"notice\":\"Time in seconds that the vault last rebased yield.\"},\"maxSupplyDiff()\":{\"notice\":\"Max difference between total supply and total value of assets. 18 decimals.\"},\"mint(address,uint256,uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mint(uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mintForStrategy(uint256)\":{\"notice\":\"Mint OTokens for an allowed Strategy\"},\"oUSD()\":{\"notice\":\"Deprecated: use `oToken()` instead.\"},\"operatorAddr()\":{\"notice\":\"Address authorized to call `rebase()` directly. The Governor and Strategist are always allowed in addition to this address.\"},\"pauseCapital()\":{\"notice\":\"Set the deposit paused flag to true to prevent capital movement.\"},\"pauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to prevent rebasing.\"},\"previewYield()\":{\"notice\":\"Calculates the amount that would rebase at next rebase. This is before any fees.\"},\"rebase()\":{\"notice\":\"Calculate the total value of asset held by the Vault and all strategies and update the supply of OTokens.\"},\"rebasePaused()\":{\"notice\":\"pause rebasing if true\"},\"rebasePerSecondMax()\":{\"notice\":\"max rebase percentage per second Can be used to set maximum yield of the protocol, spreading out yield over time\"},\"rebasePerSecondTarget()\":{\"notice\":\"target rebase rate limit, based on past rates and funds available.\"},\"removeStrategy(address)\":{\"notice\":\"Remove a strategy from the Vault.\"},\"removeStrategyFromMintWhitelist(address)\":{\"notice\":\"Removes a strategy from the mint whitelist.\"},\"requestWithdrawal(uint256)\":{\"notice\":\"Request an asynchronous withdrawal of asset in exchange for OToken. The OToken is burned on request and the asset is transferred to the withdrawer on claim. This request can be claimed once the withdrawal queue's `claimable` amount is greater than or equal this request's `queued` amount. There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue. OToken is converted to asset at 1:1.\"},\"setAutoAllocateThreshold(uint256)\":{\"notice\":\"Sets the minimum amount of OTokens in a mint to trigger an automatic allocation of funds afterwords.\"},\"setDefaultStrategy(address)\":{\"notice\":\"Set the default Strategy for asset, i.e. the one which the asset will be automatically allocated to and withdrawn from\"},\"setDripDuration(uint256)\":{\"notice\":\"Set the drip duration period\"},\"setMaxSupplyDiff(uint256)\":{\"notice\":\"Sets the maximum allowable difference between total supply and asset' value.\"},\"setOperatorAddr(address)\":{\"notice\":\"Set the address authorized to call `rebase()`.\"},\"setRebaseRateMax(uint256)\":{\"notice\":\"Set a yield streaming max rate. This spreads yield over time if it is above the max rate. This is a per rebase APR which due to compounding differs from the yearly APR. Governance should consider this fact when picking a desired APR\"},\"setStrategistAddr(address)\":{\"notice\":\"Set address of Strategist\"},\"setTrusteeAddress(address)\":{\"notice\":\"Sets the trusteeAddress that can receive a portion of yield. Setting to the zero address disables this feature.\"},\"setTrusteeFeeBps(uint256)\":{\"notice\":\"Sets the TrusteeFeeBps to the percentage of yield that should be received in basis points.\"},\"setVaultBuffer(uint256)\":{\"notice\":\"Set a buffer of asset to keep in the Vault to handle most redemptions without needing to spend gas unwinding asset from a Strategy.\"},\"setWithdrawalClaimDelay(uint256)\":{\"notice\":\"Changes the async withdrawal claim period for OETH & superOETHb\"},\"strategistAddr()\":{\"notice\":\"Address of the Strategist\"},\"totalValue()\":{\"notice\":\"Determine the total value of asset held by the vault and its strategies.\"},\"transferGovernance(address)\":{\"notice\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\"},\"transferToken(address,uint256)\":{\"notice\":\"Transfer token to governor. Intended for recovering tokens stuck in contract, i.e. mistaken sends.\"},\"trusteeAddress()\":{\"notice\":\"Trustee contract that can collect a percentage of yield\"},\"trusteeFeeBps()\":{\"notice\":\"Amount of yield collected in basis points. eg 2000 = 20%\"},\"unpauseCapital()\":{\"notice\":\"Set the deposit paused flag to false to enable capital movement.\"},\"unpauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to allow rebasing.\"},\"vaultBuffer()\":{\"notice\":\"Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\"},\"withdrawAllFromStrategies()\":{\"notice\":\"Withdraws all asset from all the strategies and sends asset to the Vault.\"},\"withdrawAllFromStrategy(address)\":{\"notice\":\"Withdraws all asset from the strategy and sends asset to the Vault.\"},\"withdrawFromStrategy(address,address[],uint256[])\":{\"notice\":\"Withdraw multiple asset from the strategy to the vault.\"},\"withdrawalClaimDelay()\":{\"notice\":\"Sets a minimum delay that is required to elapse between requesting async withdrawals and claiming the request. When set to 0 async withdrawals are disabled.\"},\"withdrawalQueueMetadata()\":{\"notice\":\"Global metadata for the withdrawal queue including: queued - cumulative total of all withdrawal requests included the ones that have already been claimed claimable - cumulative total of all the requests that can be claimed including the ones already claimed claimed - total of all the requests that have been claimed nextWithdrawalIndex - index of the next withdrawal request starting at 0\"},\"withdrawalRequests(uint256)\":{\"notice\":\"Mapping of withdrawal request indices to the user withdrawal request data\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/vault/OETHBaseVault.sol\":\"OETHBaseVault\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0x61437cb513a887a1bbad006e7b1c8b414478427d33de47c5600af3c748f108da\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeCast.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\\n * checks.\\n *\\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\\n * easily result in undesired exploitation or bugs, since developers usually\\n * assume that overflows raise errors. `SafeCast` restores this intuition by\\n * reverting the transaction when such an operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n *\\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\\n * all math on `uint256` and `int256` and then downcasting.\\n */\\nlibrary SafeCast {\\n /**\\n * @dev Returns the downcasted uint224 from uint256, reverting on\\n * overflow (when the input is greater than largest uint224).\\n *\\n * Counterpart to Solidity's `uint224` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 224 bits\\n */\\n function toUint224(uint256 value) internal pure returns (uint224) {\\n require(value <= type(uint224).max, \\\"SafeCast: value doesn't fit in 224 bits\\\");\\n return uint224(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint128 from uint256, reverting on\\n * overflow (when the input is greater than largest uint128).\\n *\\n * Counterpart to Solidity's `uint128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n */\\n function toUint128(uint256 value) internal pure returns (uint128) {\\n require(value <= type(uint128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return uint128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint96 from uint256, reverting on\\n * overflow (when the input is greater than largest uint96).\\n *\\n * Counterpart to Solidity's `uint96` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 96 bits\\n */\\n function toUint96(uint256 value) internal pure returns (uint96) {\\n require(value <= type(uint96).max, \\\"SafeCast: value doesn't fit in 96 bits\\\");\\n return uint96(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint64 from uint256, reverting on\\n * overflow (when the input is greater than largest uint64).\\n *\\n * Counterpart to Solidity's `uint64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n */\\n function toUint64(uint256 value) internal pure returns (uint64) {\\n require(value <= type(uint64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return uint64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint32 from uint256, reverting on\\n * overflow (when the input is greater than largest uint32).\\n *\\n * Counterpart to Solidity's `uint32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n */\\n function toUint32(uint256 value) internal pure returns (uint32) {\\n require(value <= type(uint32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return uint32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint16 from uint256, reverting on\\n * overflow (when the input is greater than largest uint16).\\n *\\n * Counterpart to Solidity's `uint16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n */\\n function toUint16(uint256 value) internal pure returns (uint16) {\\n require(value <= type(uint16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return uint16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint8 from uint256, reverting on\\n * overflow (when the input is greater than largest uint8).\\n *\\n * Counterpart to Solidity's `uint8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits.\\n */\\n function toUint8(uint256 value) internal pure returns (uint8) {\\n require(value <= type(uint8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return uint8(value);\\n }\\n\\n /**\\n * @dev Converts a signed int256 into an unsigned uint256.\\n *\\n * Requirements:\\n *\\n * - input must be greater than or equal to 0.\\n */\\n function toUint256(int256 value) internal pure returns (uint256) {\\n require(value >= 0, \\\"SafeCast: value must be positive\\\");\\n return uint256(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int128 from int256, reverting on\\n * overflow (when the input is less than smallest int128 or\\n * greater than largest int128).\\n *\\n * Counterpart to Solidity's `int128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt128(int256 value) internal pure returns (int128) {\\n require(value >= type(int128).min && value <= type(int128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return int128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int64 from int256, reverting on\\n * overflow (when the input is less than smallest int64 or\\n * greater than largest int64).\\n *\\n * Counterpart to Solidity's `int64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt64(int256 value) internal pure returns (int64) {\\n require(value >= type(int64).min && value <= type(int64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return int64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int32 from int256, reverting on\\n * overflow (when the input is less than smallest int32 or\\n * greater than largest int32).\\n *\\n * Counterpart to Solidity's `int32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt32(int256 value) internal pure returns (int32) {\\n require(value >= type(int32).min && value <= type(int32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return int32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int16 from int256, reverting on\\n * overflow (when the input is less than smallest int16 or\\n * greater than largest int16).\\n *\\n * Counterpart to Solidity's `int16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt16(int256 value) internal pure returns (int16) {\\n require(value >= type(int16).min && value <= type(int16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return int16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int8 from int256, reverting on\\n * overflow (when the input is less than smallest int8 or\\n * greater than largest int8).\\n *\\n * Counterpart to Solidity's `int8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits.\\n *\\n * _Available since v3.1._\\n */\\n function toInt8(int256 value) internal pure returns (int8) {\\n require(value >= type(int8).min && value <= type(int8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return int8(value);\\n }\\n\\n /**\\n * @dev Converts an unsigned uint256 into a signed int256.\\n *\\n * Requirements:\\n *\\n * - input must be less than or equal to maxInt256.\\n */\\n function toInt256(uint256 value) internal pure returns (int256) {\\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\\n require(value <= uint256(type(int256).max), \\\"SafeCast: value doesn't fit in an int256\\\");\\n return int256(value);\\n }\\n}\\n\",\"keccak256\":\"0x5c6caab697d302ad7eb59c234a4d2dbc965c1bae87709bd2850060b7695b28c7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa2f576be637946f767aa56601c26d717f48a0aff44f82e46f13807eea1009a21\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @notice Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @notice Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n emit GovernorshipTransferred(_governor(), newGovernor);\\n\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0xf32f873c8bfbacf2e5f01d0cf37bc7f54fbd5aa656e95c8a599114229946f107\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xa562062698aa12572123b36dfd2072f1a39e44fed2031cc19c2c9fd522f96ec2\",\"license\":\"MIT\"},\"contracts/interfaces/IStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\\n */\\ninterface IStrategy {\\n /**\\n * @dev Deposit the given asset to platform\\n * @param _asset asset address\\n * @param _amount Amount to deposit\\n */\\n function deposit(address _asset, uint256 _amount) external;\\n\\n /**\\n * @dev Deposit the entire balance of all supported assets in the Strategy\\n * to the platform\\n */\\n function depositAll() external;\\n\\n /**\\n * @dev Withdraw given asset from Lending platform\\n */\\n function withdraw(\\n address _recipient,\\n address _asset,\\n uint256 _amount\\n ) external;\\n\\n /**\\n * @dev Liquidate all assets in strategy and return them to Vault.\\n */\\n function withdrawAll() external;\\n\\n /**\\n * @dev Returns the current balance of the given asset.\\n */\\n function checkBalance(address _asset)\\n external\\n view\\n returns (uint256 balance);\\n\\n /**\\n * @dev Returns bool indicating whether strategy supports asset.\\n */\\n function supportsAsset(address _asset) external view returns (bool);\\n\\n /**\\n * @dev Collect reward tokens from the Strategy.\\n */\\n function collectRewardTokens() external;\\n\\n /**\\n * @dev The address array of the reward tokens for the Strategy.\\n */\\n function getRewardTokenAddresses() external view returns (address[] memory);\\n\\n function harvesterAddress() external view returns (address);\\n\\n function transferToken(address token, uint256 amount) external;\\n\\n function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\\n external;\\n}\\n\",\"keccak256\":\"0x79ca47defb3b5a56bba13f14c440838152fd1c1aa640476154516a16da4da8ba\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/IVault.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { VaultStorage } from \\\"../vault/VaultStorage.sol\\\";\\n\\ninterface IVault {\\n // slither-disable-start constable-states\\n\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event DefaultStrategyUpdated(address _strategy);\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\\n event DripDurationChanged(uint256 dripDuration);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\\n\\n // Governable.sol\\n function transferGovernance(address _newGovernor) external;\\n\\n function claimGovernance() external;\\n\\n function governor() external view returns (address);\\n\\n // VaultAdmin.sol\\n function setVaultBuffer(uint256 _vaultBuffer) external;\\n\\n function vaultBuffer() external view returns (uint256);\\n\\n function setAutoAllocateThreshold(uint256 _threshold) external;\\n\\n function autoAllocateThreshold() external view returns (uint256);\\n\\n function setStrategistAddr(address _address) external;\\n\\n function strategistAddr() external view returns (address);\\n\\n function setOperatorAddr(address _operator) external;\\n\\n function operatorAddr() external view returns (address);\\n\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\\n\\n function maxSupplyDiff() external view returns (uint256);\\n\\n function setTrusteeAddress(address _address) external;\\n\\n function trusteeAddress() external view returns (address);\\n\\n function setTrusteeFeeBps(uint256 _basis) external;\\n\\n function trusteeFeeBps() external view returns (uint256);\\n\\n function approveStrategy(address _addr) external;\\n\\n function removeStrategy(address _addr) external;\\n\\n function setDefaultStrategy(address _strategy) external;\\n\\n function defaultStrategy() external view returns (address);\\n\\n function pauseRebase() external;\\n\\n function unpauseRebase() external;\\n\\n function rebasePaused() external view returns (bool);\\n\\n function pauseCapital() external;\\n\\n function unpauseCapital() external;\\n\\n function capitalPaused() external view returns (bool);\\n\\n function transferToken(address _asset, uint256 _amount) external;\\n\\n function withdrawAllFromStrategy(address _strategyAddr) external;\\n\\n function withdrawAllFromStrategies() external;\\n\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n // VaultCore.sol\\n function mint(uint256 _amount) external;\\n\\n function mintForStrategy(uint256 _amount) external;\\n\\n function burnForStrategy(uint256 _amount) external;\\n\\n function allocate() external;\\n\\n function rebase() external;\\n\\n function totalValue() external view returns (uint256 value);\\n\\n function checkBalance(address _asset) external view returns (uint256);\\n\\n function getAssetCount() external view returns (uint256);\\n\\n function getAllAssets() external view returns (address[] memory);\\n\\n function getStrategyCount() external view returns (uint256);\\n\\n function getAllStrategies() external view returns (address[] memory);\\n\\n function strategies(address _addr)\\n external\\n view\\n returns (VaultStorage.Strategy memory);\\n\\n /// @notice Deprecated: use `asset()` instead.\\n function isSupportedAsset(address _asset) external view returns (bool);\\n\\n function asset() external view returns (address);\\n\\n function oToken() external view returns (address);\\n\\n function initialize(address) external;\\n\\n function addWithdrawalQueueLiquidity() external;\\n\\n function requestWithdrawal(uint256 _amount)\\n external\\n returns (uint256 requestId, uint256 queued);\\n\\n function claimWithdrawal(uint256 requestId)\\n external\\n returns (uint256 amount);\\n\\n function claimWithdrawals(uint256[] memory requestIds)\\n external\\n returns (uint256[] memory amounts, uint256 totalAmount);\\n\\n function withdrawalQueueMetadata()\\n external\\n view\\n returns (VaultStorage.WithdrawalQueueMetadata memory);\\n\\n function withdrawalRequests(uint256 requestId)\\n external\\n view\\n returns (VaultStorage.WithdrawalRequest memory);\\n\\n function addStrategyToMintWhitelist(address strategyAddr) external;\\n\\n function removeStrategyFromMintWhitelist(address strategyAddr) external;\\n\\n function isMintWhitelistedStrategy(address strategyAddr)\\n external\\n view\\n returns (bool);\\n\\n function withdrawalClaimDelay() external view returns (uint256);\\n\\n function setWithdrawalClaimDelay(uint256 newDelay) external;\\n\\n function lastRebase() external view returns (uint64);\\n\\n function dripDuration() external view returns (uint64);\\n\\n function setDripDuration(uint256 _dripDuration) external;\\n\\n function rebasePerSecondMax() external view returns (uint64);\\n\\n function setRebaseRateMax(uint256 yearlyApr) external;\\n\\n function rebasePerSecondTarget() external view returns (uint64);\\n\\n function previewYield() external view returns (uint256 yield);\\n\\n // slither-disable-end constable-states\\n}\\n\",\"keccak256\":\"0x573ee781634813c659362ca2950f439711c2d2b1f79b285d22ecd14c8c32fb9d\",\"license\":\"BUSL-1.1\"},\"contracts/token/OUSD.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OUSD Token Contract\\n * @dev ERC20 compatible contract for OUSD\\n * @dev Implements an elastic supply\\n * @author Origin Protocol Inc\\n */\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\ncontract OUSD is Governable {\\n using SafeCast for int256;\\n using SafeCast for uint256;\\n\\n /// @dev Event triggered when the supply changes\\n /// @param totalSupply Updated token total supply\\n /// @param rebasingCredits Updated token rebasing credits\\n /// @param rebasingCreditsPerToken Updated token rebasing credits per token\\n event TotalSupplyUpdatedHighres(\\n uint256 totalSupply,\\n uint256 rebasingCredits,\\n uint256 rebasingCreditsPerToken\\n );\\n /// @dev Event triggered when an account opts in for rebasing\\n /// @param account Address of the account\\n event AccountRebasingEnabled(address account);\\n /// @dev Event triggered when an account opts out of rebasing\\n /// @param account Address of the account\\n event AccountRebasingDisabled(address account);\\n /// @dev Emitted when `value` tokens are moved from one account `from` to\\n /// another `to`.\\n /// @param from Address of the account tokens are moved from\\n /// @param to Address of the account tokens are moved to\\n /// @param value Amount of tokens transferred\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n /// @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n /// a call to {approve}. `value` is the new allowance.\\n /// @param owner Address of the owner approving allowance\\n /// @param spender Address of the spender allowance is granted to\\n /// @param value Amount of tokens spender can transfer\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 value\\n );\\n /// @dev Yield resulting from {changeSupply} that a `source` account would\\n /// receive is directed to `target` account.\\n /// @param source Address of the source forwarding the yield\\n /// @param target Address of the target receiving the yield\\n event YieldDelegated(address source, address target);\\n /// @dev Yield delegation from `source` account to the `target` account is\\n /// suspended.\\n /// @param source Address of the source suspending yield forwarding\\n /// @param target Address of the target no longer receiving yield from `source`\\n /// account\\n event YieldUndelegated(address source, address target);\\n\\n enum RebaseOptions {\\n NotSet,\\n StdNonRebasing,\\n StdRebasing,\\n YieldDelegationSource,\\n YieldDelegationTarget\\n }\\n\\n uint256[154] private _gap; // Slots to align with deployed contract\\n uint256 private constant MAX_SUPPLY = type(uint128).max;\\n /// @dev The amount of tokens in existence\\n uint256 public totalSupply;\\n mapping(address => mapping(address => uint256)) private allowances;\\n /// @dev The vault with privileges to execute {mint}, {burn}\\n /// and {changeSupply}\\n address public vaultAddress;\\n mapping(address => uint256) internal creditBalances;\\n // the 2 storage variables below need trailing underscores to not name collide with public functions\\n uint256 private rebasingCredits_; // Sum of all rebasing credits (creditBalances for rebasing accounts)\\n uint256 private rebasingCreditsPerToken_;\\n /// @dev The amount of tokens that are not rebasing - receiving yield\\n uint256 public nonRebasingSupply;\\n mapping(address => uint256) internal alternativeCreditsPerToken;\\n /// @dev A map of all addresses and their respective RebaseOptions\\n mapping(address => RebaseOptions) public rebaseState;\\n mapping(address => uint256) private __deprecated_isUpgraded;\\n /// @dev A map of addresses that have yields forwarded to. This is an\\n /// inverse mapping of {yieldFrom}\\n /// Key Account forwarding yield\\n /// Value Account receiving yield\\n mapping(address => address) public yieldTo;\\n /// @dev A map of addresses that are receiving the yield. This is an\\n /// inverse mapping of {yieldTo}\\n /// Key Account receiving yield\\n /// Value Account forwarding yield\\n mapping(address => address) public yieldFrom;\\n\\n uint256 private constant RESOLUTION_INCREASE = 1e9;\\n uint256[34] private __gap; // including below gap totals up to 200\\n\\n /// @dev Verifies that the caller is the Governor or Strategist.\\n modifier onlyGovernorOrStrategist() {\\n require(\\n isGovernor() || msg.sender == IVault(vaultAddress).strategistAddr(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n /// @dev Initializes the contract and sets necessary variables.\\n /// @param _vaultAddress Address of the vault contract\\n /// @param _initialCreditsPerToken The starting rebasing credits per token.\\n function initialize(address _vaultAddress, uint256 _initialCreditsPerToken)\\n external\\n onlyGovernor\\n {\\n require(_vaultAddress != address(0), \\\"Zero vault address\\\");\\n require(vaultAddress == address(0), \\\"Already initialized\\\");\\n\\n rebasingCreditsPerToken_ = _initialCreditsPerToken;\\n vaultAddress = _vaultAddress;\\n }\\n\\n /// @dev Returns the symbol of the token, a shorter version\\n /// of the name.\\n function symbol() external pure virtual returns (string memory) {\\n return \\\"OUSD\\\";\\n }\\n\\n /// @dev Returns the name of the token.\\n function name() external pure virtual returns (string memory) {\\n return \\\"Origin Dollar\\\";\\n }\\n\\n /// @dev Returns the number of decimals used to get its user representation.\\n function decimals() external pure virtual returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev Verifies that the caller is the Vault contract\\n */\\n modifier onlyVault() {\\n require(vaultAddress == msg.sender, \\\"Caller is not the Vault\\\");\\n _;\\n }\\n\\n /**\\n * @return High resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerTokenHighres() external view returns (uint256) {\\n return rebasingCreditsPerToken_;\\n }\\n\\n /**\\n * @return Low resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerToken() external view returns (uint256) {\\n return rebasingCreditsPerToken_ / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return High resolution total number of rebasing credits\\n */\\n function rebasingCreditsHighres() external view returns (uint256) {\\n return rebasingCredits_;\\n }\\n\\n /**\\n * @return Low resolution total number of rebasing credits\\n */\\n function rebasingCredits() external view returns (uint256) {\\n return rebasingCredits_ / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @notice Gets the balance of the specified address.\\n * @param _account Address to query the balance of.\\n * @return A uint256 representing the amount of base units owned by the\\n * specified address.\\n */\\n function balanceOf(address _account) public view returns (uint256) {\\n RebaseOptions state = rebaseState[_account];\\n if (state == RebaseOptions.YieldDelegationSource) {\\n // Saves a slot read when transferring to or from a yield delegating source\\n // since we know creditBalances equals the balance.\\n return creditBalances[_account];\\n }\\n uint256 baseBalance = (creditBalances[_account] * 1e18) /\\n _creditsPerToken(_account);\\n if (state == RebaseOptions.YieldDelegationTarget) {\\n // creditBalances of yieldFrom accounts equals token balances\\n return baseBalance - creditBalances[yieldFrom[_account]];\\n }\\n return baseBalance;\\n }\\n\\n /**\\n * @notice Gets the credits balance of the specified address.\\n * @dev Backwards compatible with old low res credits per token.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256) Credit balance and credits per token of the\\n * address\\n */\\n function creditsBalanceOf(address _account)\\n external\\n view\\n returns (uint256, uint256)\\n {\\n uint256 cpt = _creditsPerToken(_account);\\n if (cpt == 1e27) {\\n // For a period before the resolution upgrade, we created all new\\n // contract accounts at high resolution. Since they are not changing\\n // as a result of this upgrade, we will return their true values\\n return (creditBalances[_account], cpt);\\n } else {\\n return (\\n creditBalances[_account] / RESOLUTION_INCREASE,\\n cpt / RESOLUTION_INCREASE\\n );\\n }\\n }\\n\\n /**\\n * @notice Gets the credits balance of the specified address.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\\n * address, and isUpgraded\\n */\\n function creditsBalanceOfHighres(address _account)\\n external\\n view\\n returns (\\n uint256,\\n uint256,\\n bool\\n )\\n {\\n return (\\n creditBalances[_account],\\n _creditsPerToken(_account),\\n true // all accounts have their resolution \\\"upgraded\\\"\\n );\\n }\\n\\n // Backwards compatible view\\n function nonRebasingCreditsPerToken(address _account)\\n external\\n view\\n returns (uint256)\\n {\\n return alternativeCreditsPerToken[_account];\\n }\\n\\n /**\\n * @notice Transfer tokens to a specified address.\\n * @param _to the address to transfer to.\\n * @param _value the amount to be transferred.\\n * @return true on success.\\n */\\n function transfer(address _to, uint256 _value) external returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n\\n _executeTransfer(msg.sender, _to, _value);\\n\\n emit Transfer(msg.sender, _to, _value);\\n return true;\\n }\\n\\n /**\\n * @notice Transfer tokens from one address to another.\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value The amount of tokens to be transferred.\\n * @return true on success.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n uint256 userAllowance = allowances[_from][msg.sender];\\n require(_value <= userAllowance, \\\"Allowance exceeded\\\");\\n\\n unchecked {\\n allowances[_from][msg.sender] = userAllowance - _value;\\n }\\n\\n _executeTransfer(_from, _to, _value);\\n\\n emit Transfer(_from, _to, _value);\\n return true;\\n }\\n\\n function _executeTransfer(\\n address _from,\\n address _to,\\n uint256 _value\\n ) internal {\\n (\\n int256 fromRebasingCreditsDiff,\\n int256 fromNonRebasingSupplyDiff\\n ) = _adjustAccount(_from, -_value.toInt256());\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_to, _value.toInt256());\\n\\n _adjustGlobals(\\n fromRebasingCreditsDiff + toRebasingCreditsDiff,\\n fromNonRebasingSupplyDiff + toNonRebasingSupplyDiff\\n );\\n }\\n\\n function _adjustAccount(address _account, int256 _balanceChange)\\n internal\\n returns (int256 rebasingCreditsDiff, int256 nonRebasingSupplyDiff)\\n {\\n RebaseOptions state = rebaseState[_account];\\n int256 currentBalance = balanceOf(_account).toInt256();\\n if (currentBalance + _balanceChange < 0) {\\n revert(\\\"Transfer amount exceeds balance\\\");\\n }\\n uint256 newBalance = (currentBalance + _balanceChange).toUint256();\\n\\n if (state == RebaseOptions.YieldDelegationSource) {\\n address target = yieldTo[_account];\\n uint256 targetOldBalance = balanceOf(target);\\n uint256 targetNewCredits = _balanceToRebasingCredits(\\n targetOldBalance + newBalance\\n );\\n rebasingCreditsDiff =\\n targetNewCredits.toInt256() -\\n creditBalances[target].toInt256();\\n\\n creditBalances[_account] = newBalance;\\n creditBalances[target] = targetNewCredits;\\n } else if (state == RebaseOptions.YieldDelegationTarget) {\\n uint256 newCredits = _balanceToRebasingCredits(\\n newBalance + creditBalances[yieldFrom[_account]]\\n );\\n rebasingCreditsDiff =\\n newCredits.toInt256() -\\n creditBalances[_account].toInt256();\\n creditBalances[_account] = newCredits;\\n } else {\\n _autoMigrate(_account);\\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\\n _account\\n ];\\n if (alternativeCreditsPerTokenMem > 0) {\\n nonRebasingSupplyDiff = _balanceChange;\\n if (alternativeCreditsPerTokenMem != 1e18) {\\n alternativeCreditsPerToken[_account] = 1e18;\\n }\\n creditBalances[_account] = newBalance;\\n } else {\\n uint256 newCredits = _balanceToRebasingCredits(newBalance);\\n rebasingCreditsDiff =\\n newCredits.toInt256() -\\n creditBalances[_account].toInt256();\\n creditBalances[_account] = newCredits;\\n }\\n }\\n }\\n\\n function _adjustGlobals(\\n int256 _rebasingCreditsDiff,\\n int256 _nonRebasingSupplyDiff\\n ) internal {\\n if (_rebasingCreditsDiff != 0) {\\n rebasingCredits_ = (rebasingCredits_.toInt256() +\\n _rebasingCreditsDiff).toUint256();\\n }\\n if (_nonRebasingSupplyDiff != 0) {\\n nonRebasingSupply = (nonRebasingSupply.toInt256() +\\n _nonRebasingSupplyDiff).toUint256();\\n }\\n }\\n\\n /**\\n * @notice Function to check the amount of tokens that _owner has allowed\\n * to `_spender`.\\n * @param _owner The address which owns the funds.\\n * @param _spender The address which will spend the funds.\\n * @return The number of tokens still available for the _spender.\\n */\\n function allowance(address _owner, address _spender)\\n external\\n view\\n returns (uint256)\\n {\\n return allowances[_owner][_spender];\\n }\\n\\n /**\\n * @notice Approve the passed address to spend the specified amount of\\n * tokens on behalf of msg.sender.\\n * @param _spender The address which will spend the funds.\\n * @param _value The amount of tokens to be spent.\\n * @return true on success.\\n */\\n function approve(address _spender, uint256 _value) external returns (bool) {\\n allowances[msg.sender][_spender] = _value;\\n emit Approval(msg.sender, _spender, _value);\\n return true;\\n }\\n\\n /**\\n * @notice Creates `_amount` tokens and assigns them to `_account`,\\n * increasing the total supply.\\n */\\n function mint(address _account, uint256 _amount) external onlyVault {\\n require(_account != address(0), \\\"Mint to the zero address\\\");\\n\\n // Account\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_account, _amount.toInt256());\\n // Globals\\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\\n totalSupply = totalSupply + _amount;\\n\\n require(totalSupply < MAX_SUPPLY, \\\"Max supply\\\");\\n emit Transfer(address(0), _account, _amount);\\n }\\n\\n /**\\n * @notice Destroys `_amount` tokens from `_account`,\\n * reducing the total supply.\\n */\\n function burn(address _account, uint256 _amount) external onlyVault {\\n require(_account != address(0), \\\"Burn from the zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n\\n // Account\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_account, -_amount.toInt256());\\n // Globals\\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\\n totalSupply = totalSupply - _amount;\\n\\n emit Transfer(_account, address(0), _amount);\\n }\\n\\n /**\\n * @dev Get the credits per token for an account. Returns a fixed amount\\n * if the account is non-rebasing.\\n * @param _account Address of the account.\\n */\\n function _creditsPerToken(address _account)\\n internal\\n view\\n returns (uint256)\\n {\\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\\n _account\\n ];\\n if (alternativeCreditsPerTokenMem != 0) {\\n return alternativeCreditsPerTokenMem;\\n } else {\\n return rebasingCreditsPerToken_;\\n }\\n }\\n\\n /**\\n * @dev Auto migrate contracts to be non rebasing,\\n * unless they have opted into yield.\\n * @param _account Address of the account.\\n */\\n function _autoMigrate(address _account) internal {\\n uint256 codeLen = _account.code.length;\\n bool isEOA = (codeLen == 0) ||\\n (codeLen == 23 && bytes3(_account.code) == 0xef0100);\\n // In previous code versions, contracts would not have had their\\n // rebaseState[_account] set to RebaseOptions.NonRebasing when migrated\\n // therefore we check the actual accounting used on the account as well.\\n if (\\n (!isEOA) &&\\n rebaseState[_account] == RebaseOptions.NotSet &&\\n alternativeCreditsPerToken[_account] == 0\\n ) {\\n _rebaseOptOut(_account);\\n }\\n }\\n\\n /**\\n * @dev Calculates credits from contract's global rebasingCreditsPerToken_, and\\n * also balance that corresponds to those credits. The latter is important\\n * when adjusting the contract's global nonRebasingSupply to circumvent any\\n * possible rounding errors.\\n *\\n * @param _balance Balance of the account.\\n */\\n function _balanceToRebasingCredits(uint256 _balance)\\n internal\\n view\\n returns (uint256 rebasingCredits)\\n {\\n // Rounds up, because we need to ensure that accounts always have\\n // at least the balance that they should have.\\n // Note this should always be used on an absolute account value,\\n // not on a possibly negative diff, because then the rounding would be wrong.\\n return ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18;\\n }\\n\\n /**\\n * @notice The calling account will start receiving yield after a successful call.\\n * @param _account Address of the account.\\n */\\n function governanceRebaseOptIn(address _account) external onlyGovernor {\\n require(_account != address(0), \\\"Zero address not allowed\\\");\\n _rebaseOptIn(_account);\\n }\\n\\n /**\\n * @notice The calling account will start receiving yield after a successful call.\\n */\\n function rebaseOptIn() external {\\n _rebaseOptIn(msg.sender);\\n }\\n\\n function _rebaseOptIn(address _account) internal {\\n uint256 balance = balanceOf(_account);\\n\\n // prettier-ignore\\n require(\\n alternativeCreditsPerToken[_account] > 0 ||\\n // Accounts may explicitly `rebaseOptIn` regardless of\\n // accounting if they have a 0 balance.\\n creditBalances[_account] == 0\\n ,\\n \\\"Account must be non-rebasing\\\"\\n );\\n RebaseOptions state = rebaseState[_account];\\n // prettier-ignore\\n require(\\n state == RebaseOptions.StdNonRebasing ||\\n state == RebaseOptions.NotSet,\\n \\\"Only standard non-rebasing accounts can opt in\\\"\\n );\\n\\n uint256 newCredits = _balanceToRebasingCredits(balance);\\n\\n // Account\\n rebaseState[_account] = RebaseOptions.StdRebasing;\\n alternativeCreditsPerToken[_account] = 0;\\n creditBalances[_account] = newCredits;\\n // Globals\\n _adjustGlobals(newCredits.toInt256(), -balance.toInt256());\\n\\n emit AccountRebasingEnabled(_account);\\n }\\n\\n /**\\n * @notice The calling account will no longer receive yield\\n */\\n function rebaseOptOut() external {\\n _rebaseOptOut(msg.sender);\\n }\\n\\n function _rebaseOptOut(address _account) internal {\\n require(\\n alternativeCreditsPerToken[_account] == 0,\\n \\\"Account must be rebasing\\\"\\n );\\n RebaseOptions state = rebaseState[_account];\\n require(\\n state == RebaseOptions.StdRebasing || state == RebaseOptions.NotSet,\\n \\\"Only standard rebasing accounts can opt out\\\"\\n );\\n\\n uint256 oldCredits = creditBalances[_account];\\n uint256 balance = balanceOf(_account);\\n\\n // Account\\n rebaseState[_account] = RebaseOptions.StdNonRebasing;\\n alternativeCreditsPerToken[_account] = 1e18;\\n creditBalances[_account] = balance;\\n // Globals\\n _adjustGlobals(-oldCredits.toInt256(), balance.toInt256());\\n\\n emit AccountRebasingDisabled(_account);\\n }\\n\\n /**\\n * @notice Distribute yield to users. This changes the exchange rate\\n * between \\\"credits\\\" and OUSD tokens to change rebasing user's balances.\\n * @param _newTotalSupply New total supply of OUSD.\\n */\\n function changeSupply(uint256 _newTotalSupply) external onlyVault {\\n require(totalSupply > 0, \\\"Cannot increase 0 supply\\\");\\n\\n if (totalSupply == _newTotalSupply) {\\n emit TotalSupplyUpdatedHighres(\\n totalSupply,\\n rebasingCredits_,\\n rebasingCreditsPerToken_\\n );\\n return;\\n }\\n\\n totalSupply = _newTotalSupply > MAX_SUPPLY\\n ? MAX_SUPPLY\\n : _newTotalSupply;\\n\\n uint256 rebasingSupply = totalSupply - nonRebasingSupply;\\n // round up in the favour of the protocol\\n rebasingCreditsPerToken_ =\\n (rebasingCredits_ * 1e18 + rebasingSupply - 1) /\\n rebasingSupply;\\n\\n require(rebasingCreditsPerToken_ > 0, \\\"Invalid change in supply\\\");\\n\\n emit TotalSupplyUpdatedHighres(\\n totalSupply,\\n rebasingCredits_,\\n rebasingCreditsPerToken_\\n );\\n }\\n\\n /*\\n * @notice Send the yield from one account to another account.\\n * Each account keeps its own balances.\\n */\\n function delegateYield(address _from, address _to)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_from != address(0), \\\"Zero from address not allowed\\\");\\n require(_to != address(0), \\\"Zero to address not allowed\\\");\\n\\n require(_from != _to, \\\"Cannot delegate to self\\\");\\n require(\\n yieldFrom[_to] == address(0) &&\\n yieldTo[_to] == address(0) &&\\n yieldFrom[_from] == address(0) &&\\n yieldTo[_from] == address(0),\\n \\\"Blocked by existing yield delegation\\\"\\n );\\n RebaseOptions stateFrom = rebaseState[_from];\\n RebaseOptions stateTo = rebaseState[_to];\\n\\n require(\\n stateFrom == RebaseOptions.NotSet ||\\n stateFrom == RebaseOptions.StdNonRebasing ||\\n stateFrom == RebaseOptions.StdRebasing,\\n \\\"Invalid rebaseState from\\\"\\n );\\n\\n require(\\n stateTo == RebaseOptions.NotSet ||\\n stateTo == RebaseOptions.StdNonRebasing ||\\n stateTo == RebaseOptions.StdRebasing,\\n \\\"Invalid rebaseState to\\\"\\n );\\n\\n if (alternativeCreditsPerToken[_from] == 0) {\\n _rebaseOptOut(_from);\\n }\\n if (alternativeCreditsPerToken[_to] > 0) {\\n _rebaseOptIn(_to);\\n }\\n\\n uint256 fromBalance = balanceOf(_from);\\n uint256 toBalance = balanceOf(_to);\\n uint256 oldToCredits = creditBalances[_to];\\n uint256 newToCredits = _balanceToRebasingCredits(\\n fromBalance + toBalance\\n );\\n\\n // Set up the bidirectional links\\n yieldTo[_from] = _to;\\n yieldFrom[_to] = _from;\\n\\n // Local\\n rebaseState[_from] = RebaseOptions.YieldDelegationSource;\\n alternativeCreditsPerToken[_from] = 1e18;\\n creditBalances[_from] = fromBalance;\\n rebaseState[_to] = RebaseOptions.YieldDelegationTarget;\\n creditBalances[_to] = newToCredits;\\n\\n // Global\\n int256 creditsChange = newToCredits.toInt256() -\\n oldToCredits.toInt256();\\n _adjustGlobals(creditsChange, -(fromBalance).toInt256());\\n emit YieldDelegated(_from, _to);\\n }\\n\\n /*\\n * @notice Stop sending the yield from one account to another account.\\n */\\n function undelegateYield(address _from) external onlyGovernorOrStrategist {\\n // Require a delegation, which will also ensure a valid delegation\\n require(yieldTo[_from] != address(0), \\\"Zero address not allowed\\\");\\n\\n address to = yieldTo[_from];\\n uint256 fromBalance = balanceOf(_from);\\n uint256 toBalance = balanceOf(to);\\n uint256 oldToCredits = creditBalances[to];\\n uint256 newToCredits = _balanceToRebasingCredits(toBalance);\\n\\n // Remove the bidirectional links\\n yieldFrom[to] = address(0);\\n yieldTo[_from] = address(0);\\n\\n // Local\\n rebaseState[_from] = RebaseOptions.StdNonRebasing;\\n // alternativeCreditsPerToken[from] already 1e18 from `delegateYield()`\\n creditBalances[_from] = fromBalance;\\n rebaseState[to] = RebaseOptions.StdRebasing;\\n // alternativeCreditsPerToken[to] already 0 from `delegateYield()`\\n creditBalances[to] = newToCredits;\\n\\n // Global\\n int256 creditsChange = newToCredits.toInt256() -\\n oldToCredits.toInt256();\\n _adjustGlobals(creditsChange, fromBalance.toInt256());\\n emit YieldUndelegated(_from, to);\\n }\\n}\\n\",\"keccak256\":\"0x73439bef6569f5adf6f5ce2cb54a5f0d3109d4819457532236e172a7091980a9\",\"license\":\"BUSL-1.1\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { IBasicToken } from \\\"../interfaces/IBasicToken.sol\\\";\\n\\nlibrary Helpers {\\n /**\\n * @notice Fetch the `symbol()` from an ERC20 token\\n * @dev Grabs the `symbol()` from a contract\\n * @param _token Address of the ERC20 token\\n * @return string Symbol of the ERC20 token\\n */\\n function getSymbol(address _token) internal view returns (string memory) {\\n string memory symbol = IBasicToken(_token).symbol();\\n return symbol;\\n }\\n\\n /**\\n * @notice Fetch the `decimals()` from an ERC20 token\\n * @dev Grabs the `decimals()` from a contract and fails if\\n * the decimal value does not live within a certain range\\n * @param _token Address of the ERC20 token\\n * @return uint256 Decimals of the ERC20 token\\n */\\n function getDecimals(address _token) internal view returns (uint256) {\\n uint256 decimals = IBasicToken(_token).decimals();\\n require(\\n decimals >= 4 && decimals <= 18,\\n \\\"Token must have sufficient decimal places\\\"\\n );\\n\\n return decimals;\\n }\\n}\\n\",\"keccak256\":\"0x4366f8d90b34c1eef8bbaaf369b1e5cd59f04027bb3c111f208eaee65bbc0346\",\"license\":\"BUSL-1.1\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base contract any contracts that need to initialize state after deployment.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0x50d39ebf38a3d3111f2b77a6c75ece1d4ae731552fec4697ab16fcf6c0d4d5e8\",\"license\":\"BUSL-1.1\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n // slither-disable-next-line divide-before-multiply\\n x = x.div(10**(from - to));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e36 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0x71d6ed0053a1e5ef018d27c3b6d024f336d8157ab6f6859e400b3243a50a71b7\",\"license\":\"BUSL-1.1\"},\"contracts/vault/OETHBaseVault.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { VaultAdmin } from \\\"./VaultAdmin.sol\\\";\\n\\n/**\\n * @title OETH Base VaultAdmin Contract\\n * @author Origin Protocol Inc\\n */\\ncontract OETHBaseVault is VaultAdmin {\\n constructor(address _weth) VaultAdmin(_weth) {}\\n}\\n\",\"keccak256\":\"0x7f8d61656d131bcf705c3b9520933404d7d7c5406bb649247b304f8108bd7dbf\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultAdmin contract\\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\nimport \\\"./VaultCore.sol\\\";\\n\\nabstract contract VaultAdmin is VaultCore {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n using SafeCast for uint256;\\n\\n /**\\n * @dev Verifies that the caller is the Governor or Strategist.\\n */\\n modifier onlyGovernorOrStrategist() {\\n require(\\n msg.sender == strategistAddr || isGovernor(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n constructor(address _asset) VaultCore(_asset) {}\\n\\n /***************************************\\n Configuration\\n ****************************************/\\n /**\\n * @notice Set a buffer of asset to keep in the Vault to handle most\\n * redemptions without needing to spend gas unwinding asset from a Strategy.\\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\\n */\\n function setVaultBuffer(uint256 _vaultBuffer)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_vaultBuffer <= 1e18, \\\"Invalid value\\\");\\n vaultBuffer = _vaultBuffer;\\n emit VaultBufferUpdated(_vaultBuffer);\\n }\\n\\n /**\\n * @notice Sets the minimum amount of OTokens in a mint to trigger an\\n * automatic allocation of funds afterwords.\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setAutoAllocateThreshold(uint256 _threshold)\\n external\\n onlyGovernor\\n {\\n autoAllocateThreshold = _threshold;\\n emit AllocateThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set address of Strategist\\n * @param _address Address of Strategist\\n */\\n function setStrategistAddr(address _address) external onlyGovernor {\\n strategistAddr = _address;\\n emit StrategistUpdated(_address);\\n }\\n\\n /**\\n * @notice Set the address authorized to call `rebase()`.\\n * @param _operator New operator address. May be set to the zero address\\n * to disable operator-initiated rebases.\\n */\\n function setOperatorAddr(address _operator) external onlyGovernor {\\n operatorAddr = _operator;\\n emit OperatorUpdated(_operator);\\n }\\n\\n /**\\n * @notice Set the default Strategy for asset, i.e. the one which\\n * the asset will be automatically allocated to and withdrawn from\\n * @param _strategy Address of the Strategy\\n */\\n function setDefaultStrategy(address _strategy)\\n external\\n onlyGovernorOrStrategist\\n {\\n emit DefaultStrategyUpdated(_strategy);\\n // If its a zero address being passed for the strategy we are removing\\n // the default strategy\\n if (_strategy != address(0)) {\\n // Make sure the strategy meets some criteria\\n require(strategies[_strategy].isSupported, \\\"Strategy not approved\\\");\\n require(\\n IStrategy(_strategy).supportsAsset(asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n }\\n defaultStrategy = _strategy;\\n }\\n\\n /**\\n * @notice Changes the async withdrawal claim period for OETH & superOETHb\\n * @param _delay Delay period (should be between 10 mins to 7 days).\\n * Set to 0 to disable async withdrawals\\n */\\n function setWithdrawalClaimDelay(uint256 _delay) external onlyGovernor {\\n require(\\n _delay == 0 || (_delay >= 10 minutes && _delay <= 15 days),\\n \\\"Invalid claim delay period\\\"\\n );\\n withdrawalClaimDelay = _delay;\\n emit WithdrawalClaimDelayUpdated(_delay);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Set a yield streaming max rate. This spreads yield over\\n * time if it is above the max rate. This is a per rebase APR which\\n * due to compounding differs from the yearly APR. Governance should\\n * consider this fact when picking a desired APR\\n * @param apr in 1e18 notation. 3 * 1e18 = 3% APR\\n */\\n function setRebaseRateMax(uint256 apr) external onlyGovernorOrStrategist {\\n // The old yield will be at the old rate\\n _rebase();\\n // Change the rate\\n uint256 newPerSecond = apr / 100 / 365 days;\\n require(newPerSecond <= MAX_REBASE_PER_SECOND, \\\"Rate too high\\\");\\n rebasePerSecondMax = newPerSecond.toUint64();\\n emit RebasePerSecondMaxChanged(newPerSecond);\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Set the drip duration period\\n * @param _dripDuration Time in seconds to target a constant yield rate\\n */\\n function setDripDuration(uint256 _dripDuration)\\n external\\n onlyGovernorOrStrategist\\n {\\n // The old yield will be at the old rate\\n _rebase();\\n dripDuration = _dripDuration.toUint64();\\n emit DripDurationChanged(_dripDuration);\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /***************************************\\n Strategy Config\\n ****************************************/\\n\\n /**\\n * @notice Add a strategy to the Vault.\\n * @param _addr Address of the strategy to add\\n */\\n function approveStrategy(address _addr) external onlyGovernor {\\n require(!strategies[_addr].isSupported, \\\"Strategy already approved\\\");\\n require(\\n IStrategy(_addr).supportsAsset(asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\\n allStrategies.push(_addr);\\n emit StrategyApproved(_addr);\\n }\\n\\n /**\\n * @notice Remove a strategy from the Vault.\\n * @param _addr Address of the strategy to remove\\n */\\n\\n function removeStrategy(address _addr) external onlyGovernor {\\n require(strategies[_addr].isSupported, \\\"Strategy not approved\\\");\\n require(defaultStrategy != _addr, \\\"Strategy is default for asset\\\");\\n\\n // Initialize strategyIndex with out of bounds result so function will\\n // revert if no valid index found\\n uint256 stratCount = allStrategies.length;\\n uint256 strategyIndex = stratCount;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n if (allStrategies[i] == _addr) {\\n strategyIndex = i;\\n break;\\n }\\n }\\n\\n if (strategyIndex < stratCount) {\\n allStrategies[strategyIndex] = allStrategies[stratCount - 1];\\n allStrategies.pop();\\n\\n // Withdraw all assets BEFORE marking as unsupported so that AMO\\n // strategies can call burnForStrategy/mintForStrategy during withdrawAll\\n IStrategy strategy = IStrategy(_addr);\\n // slither-disable-next-line reentrancy-no-eth\\n strategy.withdrawAll();\\n\\n // Mark the strategy as not supported\\n strategies[_addr].isSupported = false;\\n isMintWhitelistedStrategy[_addr] = false;\\n\\n // 1e13 for 18 decimals. And 1e1(10) for 6 decimals\\n uint256 maxDustBalance = uint256(1e13).scaleBy(assetDecimals, 18);\\n\\n /*\\n * Some strategies are not able to withdraw all of their funds in a synchronous call.\\n * Prevent the possible accidental removal of such strategies before their funds are withdrawn.\\n */\\n require(\\n strategy.checkBalance(asset) < maxDustBalance,\\n \\\"Strategy has funds\\\"\\n );\\n emit StrategyRemoved(_addr);\\n }\\n }\\n\\n /**\\n * @notice Adds a strategy to the mint whitelist.\\n * Reverts if strategy isn't approved on Vault.\\n * @param strategyAddr Strategy address\\n */\\n function addStrategyToMintWhitelist(address strategyAddr)\\n external\\n onlyGovernor\\n {\\n require(strategies[strategyAddr].isSupported, \\\"Strategy not approved\\\");\\n\\n require(\\n !isMintWhitelistedStrategy[strategyAddr],\\n \\\"Already whitelisted\\\"\\n );\\n\\n isMintWhitelistedStrategy[strategyAddr] = true;\\n\\n emit StrategyAddedToMintWhitelist(strategyAddr);\\n }\\n\\n /**\\n * @notice Removes a strategy from the mint whitelist.\\n * @param strategyAddr Strategy address\\n */\\n function removeStrategyFromMintWhitelist(address strategyAddr)\\n external\\n onlyGovernor\\n {\\n // Intentionally skipping `strategies.isSupported` check since\\n // we may wanna remove an address even after removing the strategy\\n\\n require(isMintWhitelistedStrategy[strategyAddr], \\\"Not whitelisted\\\");\\n\\n isMintWhitelistedStrategy[strategyAddr] = false;\\n\\n emit StrategyRemovedFromMintWhitelist(strategyAddr);\\n }\\n\\n /***************************************\\n Strategies\\n ****************************************/\\n\\n /**\\n * @notice Deposit multiple asset from the vault into the strategy.\\n * @param _strategyToAddress Address of the Strategy to deposit asset into.\\n * @param _assets Array of asset address that will be deposited into the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to deposit.\\n */\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _depositToStrategy(_strategyToAddress, _assets, _amounts);\\n }\\n\\n function _depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyToAddress].isSupported,\\n \\\"Invalid to Strategy\\\"\\n );\\n require(\\n _assets.length == 1 && _amounts.length == 1 && _assets[0] == asset,\\n \\\"Only asset is supported\\\"\\n );\\n\\n // Check the there is enough asset to transfer once the backing\\n // asset reserved for the withdrawal queue is accounted for\\n require(\\n _amounts[0] <= _assetAvailable(),\\n \\\"Not enough assets available\\\"\\n );\\n\\n // Send required amount of funds to the strategy\\n IERC20(asset).safeTransfer(_strategyToAddress, _amounts[0]);\\n\\n // Deposit all the funds that have been sent to the strategy\\n IStrategy(_strategyToAddress).depositAll();\\n }\\n\\n /**\\n * @notice Withdraw multiple asset from the strategy to the vault.\\n * @param _strategyFromAddress Address of the Strategy to withdraw asset from.\\n * @param _assets Array of asset address that will be withdrawn from the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to withdraw.\\n */\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _withdrawFromStrategy(\\n address(this),\\n _strategyFromAddress,\\n _assets,\\n _amounts\\n );\\n }\\n\\n /**\\n * @param _recipient can either be a strategy or the Vault\\n */\\n function _withdrawFromStrategy(\\n address _recipient,\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyFromAddress].isSupported,\\n \\\"Invalid from Strategy\\\"\\n );\\n require(_assets.length == _amounts.length, \\\"Parameter length mismatch\\\");\\n\\n uint256 assetCount = _assets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n // Withdraw from Strategy to the recipient\\n IStrategy(_strategyFromAddress).withdraw(\\n _recipient,\\n _assets[i],\\n _amounts[i]\\n );\\n }\\n\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @notice Sets the maximum allowable difference between\\n * total supply and asset' value.\\n */\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\\n maxSupplyDiff = _maxSupplyDiff;\\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\\n }\\n\\n /**\\n * @notice Sets the trusteeAddress that can receive a portion of yield.\\n * Setting to the zero address disables this feature.\\n */\\n function setTrusteeAddress(address _address) external onlyGovernor {\\n trusteeAddress = _address;\\n emit TrusteeAddressChanged(_address);\\n }\\n\\n /**\\n * @notice Sets the TrusteeFeeBps to the percentage of yield that should be\\n * received in basis points.\\n */\\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\\n require(_basis <= 5000, \\\"basis cannot exceed 50%\\\");\\n trusteeFeeBps = _basis;\\n emit TrusteeFeeBpsChanged(_basis);\\n }\\n\\n /***************************************\\n Pause\\n ****************************************/\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent rebasing.\\n */\\n function pauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = true;\\n emit RebasePaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to allow rebasing.\\n */\\n function unpauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = false;\\n emit RebaseUnpaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent capital movement.\\n */\\n function pauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = true;\\n emit CapitalPaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to false to enable capital movement.\\n */\\n function unpauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = false;\\n emit CapitalUnpaused();\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\\n * contract, i.e. mistaken sends.\\n * @param _asset Address for the asset\\n * @param _amount Amount of the asset to transfer\\n */\\n function transferToken(address _asset, uint256 _amount)\\n external\\n onlyGovernor\\n {\\n require(asset != _asset, \\\"Only unsupported asset\\\");\\n IERC20(_asset).safeTransfer(governor(), _amount);\\n }\\n\\n /***************************************\\n Strategies Admin\\n ****************************************/\\n\\n /**\\n * @notice Withdraws all asset from the strategy and sends asset to the Vault.\\n * @param _strategyAddr Strategy address.\\n */\\n function withdrawAllFromStrategy(address _strategyAddr)\\n external\\n onlyGovernorOrStrategist\\n {\\n _withdrawAllFromStrategy(_strategyAddr);\\n }\\n\\n function _withdrawAllFromStrategy(address _strategyAddr) internal virtual {\\n require(\\n strategies[_strategyAddr].isSupported,\\n \\\"Strategy is not supported\\\"\\n );\\n IStrategy strategy = IStrategy(_strategyAddr);\\n strategy.withdrawAll();\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @notice Withdraws all asset from all the strategies and sends asset to the Vault.\\n */\\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\\n _withdrawAllFromStrategies();\\n }\\n\\n function _withdrawAllFromStrategies() internal virtual {\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy(allStrategies[i]).withdrawAll();\\n }\\n _addWithdrawalQueueLiquidity();\\n }\\n}\\n\",\"keccak256\":\"0xa9489d6c1c248bbf2d022d50dcc494f97f85b6d0fe40a13ab8516bd1ffda75ef\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultCore.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultCore contract\\n * @notice The Vault contract stores asset. On a deposit, OTokens will be minted\\n and sent to the depositor. On a withdrawal, OTokens will be burned and\\n asset will be sent to the withdrawer. The Vault accepts deposits of\\n interest from yield bearing strategies which will modify the supply\\n of OTokens.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\n\\nimport \\\"./VaultInitializer.sol\\\";\\n\\nabstract contract VaultCore is VaultInitializer {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n\\n /**\\n * @dev Verifies that the rebasing is not paused.\\n */\\n modifier whenNotRebasePaused() {\\n require(!rebasePaused, \\\"Rebasing paused\\\");\\n _;\\n }\\n\\n /**\\n * @dev Verifies that the deposits are not paused.\\n */\\n modifier whenNotCapitalPaused() {\\n require(!capitalPaused, \\\"Capital paused\\\");\\n _;\\n }\\n\\n constructor(address _asset) VaultInitializer(_asset) {}\\n\\n ////////////////////////////////////////////////////\\n /// MINT / BURN ///\\n ////////////////////////////////////////////////////\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @dev Deprecated: use `mint(uint256 _amount)` instead.\\n * @dev Deprecated: param _asset Address of the asset being deposited\\n * @param _amount Amount of the asset being deposited\\n * @dev Deprecated: param _minimumOusdAmount Minimum OTokens to mint\\n */\\n function mint(\\n address,\\n uint256 _amount,\\n uint256\\n ) external whenNotCapitalPaused nonReentrant {\\n _mint(_amount);\\n }\\n\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @param _amount Amount of the asset being deposited\\n */\\n function mint(uint256 _amount) external whenNotCapitalPaused nonReentrant {\\n _mint(_amount);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @dev Deposit a supported asset and mint OTokens.\\n * @param _amount Amount of the asset being deposited\\n */\\n function _mint(uint256 _amount) internal virtual {\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n\\n // Scale amount to 18 decimals\\n uint256 scaledAmount = _amount.scaleBy(18, assetDecimals);\\n\\n emit Mint(msg.sender, scaledAmount);\\n\\n // Mint oTokens\\n oToken.mint(msg.sender, scaledAmount);\\n\\n IERC20(asset).safeTransferFrom(msg.sender, address(this), _amount);\\n\\n // Give priority to the withdrawal queue for the new asset liquidity\\n _addWithdrawalQueueLiquidity();\\n\\n // Auto-allocate if necessary\\n if (scaledAmount >= autoAllocateThreshold) {\\n _allocate();\\n }\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /**\\n * @notice Mint OTokens for an allowed Strategy\\n * @param _amount Amount of OToken to mint\\n *\\n * Notice: can't use `nonReentrant` modifier since the `mint` function can\\n * call `allocate`, and that can trigger an AMO strategy to call this function\\n * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function mintForStrategy(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n {\\n require(\\n strategies[msg.sender].isSupported == true,\\n \\\"Unsupported strategy\\\"\\n );\\n require(\\n isMintWhitelistedStrategy[msg.sender] == true,\\n \\\"Not whitelisted strategy\\\"\\n );\\n\\n emit Mint(msg.sender, _amount);\\n // Mint matching amount of OTokens\\n oToken.mint(msg.sender, _amount);\\n }\\n\\n /**\\n * @notice Burn OTokens for an allowed Strategy\\n * @param _amount Amount of OToken to burn\\n *\\n * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could\\n * require withdrawal on an AMO strategy and that one can call `burnForStrategy`\\n * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function burnForStrategy(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n {\\n require(\\n strategies[msg.sender].isSupported == true,\\n \\\"Unsupported strategy\\\"\\n );\\n require(\\n isMintWhitelistedStrategy[msg.sender] == true,\\n \\\"Not whitelisted strategy\\\"\\n );\\n\\n emit Redeem(msg.sender, _amount);\\n\\n // Burn OTokens\\n oToken.burn(msg.sender, _amount);\\n }\\n\\n ////////////////////////////////////////////////////\\n /// ASYNC WITHDRAWALS ///\\n ////////////////////////////////////////////////////\\n /**\\n * @notice Request an asynchronous withdrawal of asset in exchange for OToken.\\n * The OToken is burned on request and the asset is transferred to the withdrawer on claim.\\n * This request can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal this request's `queued` amount.\\n * There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs\\n * enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue.\\n * OToken is converted to asset at 1:1.\\n * @param _amount Amount of OToken to burn.\\n * @return requestId Unique ID for the withdrawal request\\n * @return queued Cumulative total of all asset queued including already claimed requests.\\n */\\n function requestWithdrawal(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 requestId, uint256 queued)\\n {\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n require(withdrawalClaimDelay > 0, \\\"Async withdrawals not enabled\\\");\\n\\n // The check that the requester has enough OToken is done in to later burn call\\n\\n requestId = withdrawalQueueMetadata.nextWithdrawalIndex;\\n queued =\\n withdrawalQueueMetadata.queued +\\n _amount.scaleBy(assetDecimals, 18);\\n\\n // Store the next withdrawal request\\n withdrawalQueueMetadata.nextWithdrawalIndex = SafeCast.toUint128(\\n requestId + 1\\n );\\n // Store the updated queued amount which reserves asset in the withdrawal queue\\n // and reduces the vault's total asset\\n withdrawalQueueMetadata.queued = SafeCast.toUint128(queued);\\n // Store the user's withdrawal request\\n // `queued` is in asset decimals, while `amount` is in OToken decimals (18)\\n withdrawalRequests[requestId] = WithdrawalRequest({\\n withdrawer: msg.sender,\\n claimed: false,\\n timestamp: uint40(block.timestamp),\\n amount: SafeCast.toUint128(_amount),\\n queued: SafeCast.toUint128(queued)\\n });\\n\\n // Burn the user's OToken\\n oToken.burn(msg.sender, _amount);\\n\\n // Prevent withdrawal if the vault is solvent by more than the allowed percentage\\n _postRedeem();\\n\\n emit WithdrawalRequested(msg.sender, requestId, _amount, queued);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Claim a previously requested withdrawal once it is claimable.\\n * This request can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal this request's `queued` amount and 10 minutes has passed.\\n * If the requests is not claimable, the transaction will revert with `Queue pending liquidity`.\\n * If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`.\\n * OToken is converted to asset at 1:1.\\n * @param _requestId Unique ID for the withdrawal request\\n * @return amount Amount of asset transferred to the withdrawer\\n */\\n function claimWithdrawal(uint256 _requestId)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 amount)\\n {\\n // Try and get more liquidity if there is not enough available\\n if (\\n withdrawalRequests[_requestId].queued >\\n withdrawalQueueMetadata.claimable\\n ) {\\n // Add any asset to the withdrawal queue\\n // this needs to remain here as:\\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\\n // - funds can be withdrawn from a strategy\\n //\\n // Those funds need to be added to withdrawal queue liquidity\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n // Scale amount to asset decimals\\n amount = _claimWithdrawal(_requestId);\\n\\n // transfer asset from the vault to the withdrawer\\n IERC20(asset).safeTransfer(msg.sender, amount);\\n\\n // Prevent insolvency\\n _postRedeem();\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n /**\\n * @notice Claim a previously requested withdrawals once they are claimable.\\n * This requests can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal each request's `queued` amount and 10 minutes has passed.\\n * If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`.\\n * If one of the requests is not older than 10 minutes,\\n * the whole transaction will revert with `Claim delay not met`.\\n * @param _requestIds Unique ID of each withdrawal request\\n * @return amounts Amount of asset received for each request\\n * @return totalAmount Total amount of asset transferred to the withdrawer\\n */\\n function claimWithdrawals(uint256[] calldata _requestIds)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256[] memory amounts, uint256 totalAmount)\\n {\\n // Add any asset to the withdrawal queue\\n // this needs to remain here as:\\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\\n // - funds can be withdrawn from a strategy\\n //\\n // Those funds need to be added to withdrawal queue liquidity\\n _addWithdrawalQueueLiquidity();\\n\\n amounts = new uint256[](_requestIds.length);\\n for (uint256 i; i < _requestIds.length; ++i) {\\n // Scale all amounts to asset decimals, thus totalAmount is also in asset decimals\\n amounts[i] = _claimWithdrawal(_requestIds[i]);\\n totalAmount += amounts[i];\\n }\\n\\n // transfer all the claimed asset from the vault to the withdrawer\\n IERC20(asset).safeTransfer(msg.sender, totalAmount);\\n\\n // Prevent insolvency\\n _postRedeem();\\n\\n return (amounts, totalAmount);\\n }\\n\\n function _claimWithdrawal(uint256 requestId)\\n internal\\n returns (uint256 amount)\\n {\\n require(withdrawalClaimDelay > 0, \\\"Async withdrawals not enabled\\\");\\n\\n // Load the structs from storage into memory\\n WithdrawalRequest memory request = withdrawalRequests[requestId];\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n require(\\n request.timestamp + withdrawalClaimDelay <= block.timestamp,\\n \\\"Claim delay not met\\\"\\n );\\n // If there isn't enough reserved liquidity in the queue to claim\\n require(request.queued <= queue.claimable, \\\"Queue pending liquidity\\\");\\n require(request.withdrawer == msg.sender, \\\"Not requester\\\");\\n require(request.claimed == false, \\\"Already claimed\\\");\\n\\n // Store the request as claimed\\n withdrawalRequests[requestId].claimed = true;\\n // Store the updated claimed amount\\n withdrawalQueueMetadata.claimed =\\n queue.claimed +\\n SafeCast.toUint128(\\n StableMath.scaleBy(request.amount, assetDecimals, 18)\\n );\\n\\n emit WithdrawalClaimed(msg.sender, requestId, request.amount);\\n\\n return StableMath.scaleBy(request.amount, assetDecimals, 18);\\n }\\n\\n function _postRedeem() internal view {\\n // Until we can prove that we won't affect the prices of our asset\\n // by withdrawing them, this should be here.\\n // It's possible that a strategy was off on its asset total, perhaps\\n // a reward token sold for more or for less than anticipated.\\n uint256 totalUnits = _totalValue();\\n\\n // Check that the OTokens are backed by enough asset\\n if (maxSupplyDiff > 0) {\\n // If there are more outstanding withdrawal requests than asset in the vault and strategies\\n // then the available asset will be negative and totalUnits will be rounded up to zero.\\n // As we don't know the exact shortfall amount, we will reject all redeem and withdrawals\\n require(totalUnits > 0, \\\"Too many outstanding requests\\\");\\n\\n // Allow a max difference of maxSupplyDiff% between\\n // asset value and OUSD total supply\\n uint256 diff = oToken.totalSupply().divPrecisely(totalUnits);\\n require(\\n (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,\\n \\\"Backing supply liquidity error\\\"\\n );\\n }\\n }\\n\\n /**\\n * @notice Allocate unallocated funds on Vault to strategies.\\n */\\n function allocate() external virtual whenNotCapitalPaused nonReentrant {\\n // Add any unallocated asset to the withdrawal queue first\\n _addWithdrawalQueueLiquidity();\\n\\n _allocate();\\n }\\n\\n /**\\n * @dev Allocate asset (eg. WETH or USDC) to the default asset strategy\\n * if there is excess to the Vault buffer.\\n * This is called from either `mint` or `allocate` and assumes `_addWithdrawalQueueLiquidity`\\n * has been called before this function.\\n */\\n function _allocate() internal virtual {\\n // No need to do anything if no default strategy for asset\\n address depositStrategyAddr = defaultStrategy;\\n if (depositStrategyAddr == address(0)) return;\\n\\n uint256 assetAvailableInVault = _assetAvailable();\\n // No need to do anything if there isn't any asset in the vault to allocate\\n if (assetAvailableInVault == 0) return;\\n\\n // Calculate the target buffer for the vault using the total supply\\n uint256 totalSupply = oToken.totalSupply();\\n // Scaled to asset decimals\\n uint256 targetBuffer = totalSupply.mulTruncate(vaultBuffer).scaleBy(\\n assetDecimals,\\n 18\\n );\\n\\n // If available asset in the Vault is below or equal the target buffer then there's nothing to allocate\\n if (assetAvailableInVault <= targetBuffer) return;\\n\\n // The amount of asset to allocate to the default strategy\\n uint256 allocateAmount = assetAvailableInVault - targetBuffer;\\n\\n IStrategy strategy = IStrategy(depositStrategyAddr);\\n // Transfer asset to the strategy and call the strategy's deposit function\\n IERC20(asset).safeTransfer(address(strategy), allocateAmount);\\n strategy.deposit(asset, allocateAmount);\\n\\n emit AssetAllocated(asset, depositStrategyAddr, allocateAmount);\\n }\\n\\n /**\\n * @notice Calculate the total value of asset held by the Vault and all\\n * strategies and update the supply of OTokens.\\n * @dev Restricted to the Operator, Strategist or Governor.\\n */\\n function rebase() external virtual nonReentrant {\\n require(\\n msg.sender == operatorAddr ||\\n msg.sender == strategistAddr ||\\n isGovernor(),\\n \\\"Caller not authorized\\\"\\n );\\n _rebase();\\n }\\n\\n /**\\n * @dev Calculate the total value of asset held by the Vault and all\\n * strategies and update the supply of OTokens, optionally sending a\\n * portion of the yield to the trustee.\\n * @return totalUnits Total balance of Vault in units\\n */\\n function _rebase() internal whenNotRebasePaused returns (uint256) {\\n uint256 supply = oToken.totalSupply();\\n uint256 vaultValue = _totalValue();\\n // If no supply yet, do not rebase\\n if (supply == 0) {\\n return vaultValue;\\n }\\n\\n // Calculate yield and new supply\\n (uint256 yield, uint256 targetRate) = _nextYield(supply, vaultValue);\\n uint256 newSupply = supply + yield;\\n // Only rebase upwards and if we have enough backing funds\\n if (newSupply <= supply || newSupply > vaultValue) {\\n return vaultValue;\\n }\\n\\n rebasePerSecondTarget = uint64(_min(targetRate, type(uint64).max));\\n lastRebase = uint64(block.timestamp); // Intentional cast\\n\\n // Fee collection on yield\\n address _trusteeAddress = trusteeAddress; // gas savings\\n uint256 fee = 0;\\n if (_trusteeAddress != address(0)) {\\n fee = (yield * trusteeFeeBps) / 1e4;\\n if (fee > 0) {\\n require(fee < yield, \\\"Fee must not be greater than yield\\\");\\n oToken.mint(_trusteeAddress, fee);\\n }\\n }\\n emit YieldDistribution(_trusteeAddress, yield, fee);\\n\\n // Only ratchet OToken supply upwards\\n // Final check uses latest totalSupply\\n if (newSupply > oToken.totalSupply()) {\\n oToken.changeSupply(newSupply);\\n }\\n return vaultValue;\\n }\\n\\n /**\\n * @notice Calculates the amount that would rebase at next rebase.\\n * This is before any fees.\\n * @return yield amount of expected yield\\n */\\n function previewYield() external view returns (uint256 yield) {\\n (yield, ) = _nextYield(oToken.totalSupply(), _totalValue());\\n return yield;\\n }\\n\\n /**\\n * @dev Calculates the amount that would rebase at next rebase.\\n * See this Readme for detailed explanation:\\n * contracts/contracts/vault/README - Yield Limits.md\\n */\\n function _nextYield(uint256 supply, uint256 vaultValue)\\n internal\\n view\\n virtual\\n returns (uint256 yield, uint256 targetRate)\\n {\\n uint256 nonRebasing = oToken.nonRebasingSupply();\\n uint256 rebasing = supply - nonRebasing;\\n uint256 elapsed = block.timestamp - lastRebase;\\n targetRate = rebasePerSecondTarget;\\n\\n if (\\n elapsed == 0 || // Yield only once per block.\\n rebasing == 0 || // No yield if there are no rebasing tokens to give it to.\\n supply > vaultValue || // No yield if we do not have yield to give.\\n block.timestamp >= type(uint64).max // No yield if we are too far in the future to calculate it correctly.\\n ) {\\n return (0, targetRate);\\n }\\n\\n // Start with the full difference available\\n yield = vaultValue - supply;\\n\\n // Cap via optional automatic duration smoothing\\n uint256 _dripDuration = dripDuration;\\n if (_dripDuration > 1) {\\n // If we are able to sustain an increased drip rate for\\n // double the duration, then increase the target drip rate\\n targetRate = _max(targetRate, yield / (_dripDuration * 2));\\n // If we cannot sustain the target rate any more,\\n // then rebase what we can, and reduce the target\\n targetRate = _min(targetRate, yield / _dripDuration);\\n // drip at the new target rate\\n yield = _min(yield, targetRate * elapsed);\\n }\\n\\n // Cap per second. elapsed is not 1e18 denominated\\n yield = _min(yield, (rebasing * elapsed * rebasePerSecondMax) / 1e18);\\n\\n // Cap at a hard max per rebase, to avoid long durations resulting in huge rebases\\n yield = _min(yield, (rebasing * MAX_REBASE) / 1e18);\\n\\n return (yield, targetRate);\\n }\\n\\n /**\\n * @notice Determine the total value of asset held by the vault and its\\n * strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function totalValue() external view virtual returns (uint256 value) {\\n value = _totalValue();\\n }\\n\\n /**\\n * @dev Internal Calculate the total value of the asset held by the\\n * vault and its strategies.\\n * @dev The total value of all WETH held by the vault and all its strategies\\n * less any WETH that is reserved for the withdrawal queue.\\n * If there is not enough WETH in the vault and all strategies to cover\\n * all outstanding withdrawal requests then return a total value of 0.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValue() internal view virtual returns (uint256 value) {\\n // As asset is the only asset, just return the asset balance\\n value = _checkBalance(asset).scaleBy(18, assetDecimals);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @param _asset Address of asset\\n * @return uint256 Balance of asset in decimals of asset\\n */\\n function checkBalance(address _asset) external view returns (uint256) {\\n return _checkBalance(_asset);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @dev Get the balance of an asset held in Vault and all strategies\\n * less any asset that is reserved for the withdrawal queue.\\n * BaseAsset is the only asset that can return a non-zero balance.\\n * All other asset will return 0 even if there is some dust amounts left in the Vault.\\n * For example, there is 1 wei left of stETH (or USDC) in the OETH (or OUSD) Vault but\\n * will return 0 in this function.\\n *\\n * If there is not enough asset in the vault and all strategies to cover all outstanding\\n * withdrawal requests then return a asset balance of 0\\n * @param _asset Address of asset\\n * @return balance Balance of asset in decimals of asset\\n */\\n function _checkBalance(address _asset)\\n internal\\n view\\n virtual\\n returns (uint256 balance)\\n {\\n if (_asset != asset) return 0;\\n\\n // Get the asset in the vault and the strategies\\n IERC20 asset = IERC20(_asset);\\n balance = asset.balanceOf(address(this));\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy strategy = IStrategy(allStrategies[i]);\\n if (strategy.supportsAsset(_asset)) {\\n balance = balance + strategy.checkBalance(_asset);\\n }\\n }\\n\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // If the vault becomes insolvent enough that the total value in the vault and all strategies\\n // is less than the outstanding withdrawals.\\n // For example, there was a mass slashing event and most users request a withdrawal.\\n if (balance + queue.claimed < queue.queued) {\\n return 0;\\n }\\n\\n // Need to remove asset that is reserved for the withdrawal queue\\n return balance + queue.claimed - queue.queued;\\n }\\n\\n /**\\n * @notice Adds WETH to the withdrawal queue if there is a funding shortfall.\\n * @dev is called from the Native Staking strategy when validator withdrawals are processed.\\n * It also called before any WETH is allocated to a strategy.\\n */\\n function addWithdrawalQueueLiquidity() external {\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @dev Adds asset (eg. WETH or USDC) to the withdrawal queue if there is a funding shortfall.\\n * This assumes 1 asset equal 1 corresponding OToken.\\n */\\n function _addWithdrawalQueueLiquidity()\\n internal\\n returns (uint256 addedClaimable)\\n {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // Check if the claimable asset is less than the queued amount\\n uint256 queueShortfall = queue.queued - queue.claimable;\\n\\n // No need to do anything is the withdrawal queue is full funded\\n if (queueShortfall == 0) {\\n return 0;\\n }\\n\\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\\n\\n // Of the claimable withdrawal requests, how much is unclaimed?\\n // That is, the amount of asset that is currently allocated for the withdrawal queue\\n uint256 allocatedBaseAsset = queue.claimable - queue.claimed;\\n\\n // If there is no unallocated asset then there is nothing to add to the queue\\n if (assetBalance <= allocatedBaseAsset) {\\n return 0;\\n }\\n\\n uint256 unallocatedBaseAsset = assetBalance - allocatedBaseAsset;\\n // the new claimable amount is the smaller of the queue shortfall or unallocated asset\\n addedClaimable = queueShortfall < unallocatedBaseAsset\\n ? queueShortfall\\n : unallocatedBaseAsset;\\n uint256 newClaimable = queue.claimable + addedClaimable;\\n\\n // Store the new claimable amount back to storage\\n withdrawalQueueMetadata.claimable = SafeCast.toUint128(newClaimable);\\n\\n // emit a WithdrawalClaimable event\\n emit WithdrawalClaimable(newClaimable, addedClaimable);\\n }\\n\\n /**\\n * @dev Calculate how much asset (eg. WETH or USDC) in the vault is not reserved for the withdrawal queue.\\n * That is, it is available to be redeemed or deposited into a strategy.\\n */\\n function _assetAvailable() internal view returns (uint256 assetAvailable) {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // The amount of asset that is still to be claimed in the withdrawal queue\\n uint256 outstandingWithdrawals = queue.queued - queue.claimed;\\n\\n // The amount of sitting in asset in the vault\\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\\n // If there is not enough asset in the vault to cover the outstanding withdrawals\\n if (assetBalance <= outstandingWithdrawals) return 0;\\n\\n return assetBalance - outstandingWithdrawals;\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Return the number of asset supported by the Vault.\\n */\\n function getAssetCount() public view returns (uint256) {\\n return 1;\\n }\\n\\n /**\\n * @notice Return all vault asset addresses in order\\n */\\n function getAllAssets() external view returns (address[] memory) {\\n address[] memory a = new address[](1);\\n a[0] = asset;\\n return a;\\n }\\n\\n /**\\n * @notice Return the number of strategies active on the Vault.\\n */\\n function getStrategyCount() external view returns (uint256) {\\n return allStrategies.length;\\n }\\n\\n /**\\n * @notice Return the array of all strategies\\n */\\n function getAllStrategies() external view returns (address[] memory) {\\n return allStrategies;\\n }\\n\\n /**\\n * @notice Returns whether the vault supports the asset\\n * @param _asset address of the asset\\n * @return true if supported\\n */\\n function isSupportedAsset(address _asset) external view returns (bool) {\\n return asset == _asset;\\n }\\n\\n function _min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n function _max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a > b ? a : b;\\n }\\n}\\n\",\"keccak256\":\"0xc2080a50088fc275eddea5784cef6a561280918679c846de48a8983613acf56e\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultInitializer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultInitializer contract\\n * @notice The Vault contract initializes the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport \\\"./VaultStorage.sol\\\";\\n\\nabstract contract VaultInitializer is VaultStorage {\\n constructor(address _asset) VaultStorage(_asset) {}\\n\\n function initialize(address _oToken) external onlyGovernor initializer {\\n require(_oToken != address(0), \\\"oToken address is zero\\\");\\n\\n oToken = OUSD(_oToken);\\n\\n rebasePaused = false;\\n capitalPaused = true;\\n\\n // Initial Vault buffer of 0%\\n vaultBuffer = 0;\\n // Initial allocate threshold of 25,000 OUSD\\n autoAllocateThreshold = 25000e18;\\n // Initialize all strategies\\n allStrategies = new address[](0);\\n // Start with drip duration: 7 days\\n dripDuration = 604800;\\n }\\n}\\n\",\"keccak256\":\"0x5198442b36146a9c1c1f38294866f4b3a12344ccf67dd9dd2e3958243bbd9c98\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultStorage.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultStorage contract\\n * @notice The VaultStorage contract defines the storage for the Vault contracts\\n * @author Origin Protocol Inc\\n */\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { IERC20Metadata } from \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { OUSD } from \\\"../token/OUSD.sol\\\";\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport \\\"../utils/Helpers.sol\\\";\\n\\nabstract contract VaultStorage is Initializable, Governable {\\n using SafeERC20 for IERC20;\\n\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event DefaultStrategyUpdated(address _strategy);\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\\n event DripDurationChanged(uint256 dripDuration);\\n event OperatorUpdated(address newOperator);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\\n\\n // Since we are proxy, all state should be uninitalized.\\n // Since this storage contract does not have logic directly on it\\n // we should not be checking for to see if these variables can be constant.\\n // slither-disable-start uninitialized-state\\n // slither-disable-start constable-states\\n\\n /// @dev mapping of supported vault assets to their configuration\\n uint256 private _deprecated_assets;\\n /// @dev list of all assets supported by the vault.\\n address[] private _deprecated_allAssets;\\n\\n // Strategies approved for use by the Vault\\n struct Strategy {\\n bool isSupported;\\n uint256 _deprecated; // Deprecated storage slot\\n }\\n /// @dev mapping of strategy contracts to their configuration\\n mapping(address => Strategy) public strategies;\\n /// @dev list of all vault strategies\\n address[] internal allStrategies;\\n\\n /// @notice Address of the Oracle price provider contract\\n address private _deprecated_priceProvider;\\n /// @notice pause rebasing if true\\n bool public rebasePaused;\\n /// @notice pause operations that change the OToken supply.\\n /// eg mint, redeem, allocate, mint/burn for strategy\\n bool public capitalPaused;\\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\\n uint256 private _deprecated_redeemFeeBps;\\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\\n uint256 public vaultBuffer;\\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\\n uint256 public autoAllocateThreshold;\\n /// @dev Deprecated. Was the auto-rebase trigger threshold for mint/redeem.\\n /// Storage slot retained for proxy compatibility; no longer read or written.\\n uint256 internal __deprecatedRebaseThreshold;\\n\\n /// @dev Address of the OToken token. eg OUSD or OETH.\\n OUSD public oToken;\\n\\n /// @dev Address of the contract responsible for post rebase syncs with AMMs\\n address private _deprecated_rebaseHooksAddr = address(0);\\n\\n /// @dev Deprecated: Address of Uniswap\\n address private _deprecated_uniswapAddr = address(0);\\n\\n /// @notice Address of the Strategist\\n address public strategistAddr = address(0);\\n\\n /// @notice Mapping of asset address to the Strategy that they should automatically\\n // be allocated to\\n uint256 private _deprecated_assetDefaultStrategies;\\n\\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\\n uint256 public maxSupplyDiff;\\n\\n /// @notice Trustee contract that can collect a percentage of yield\\n address public trusteeAddress;\\n\\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\\n uint256 public trusteeFeeBps;\\n\\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\\n address[] private _deprecated_swapTokens;\\n\\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\\n\\n address private _deprecated_ousdMetaStrategy;\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n int256 private _deprecated_netOusdMintedForStrategy;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n uint256 private _deprecated_netOusdMintForStrategyThreshold;\\n\\n uint256 private _deprecated_swapConfig;\\n\\n // List of strategies that can mint oTokens directly\\n // Used in OETHBaseVaultCore\\n mapping(address => bool) public isMintWhitelistedStrategy;\\n\\n /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\\n /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\\n address private _deprecated_dripper;\\n\\n /// Withdrawal Queue Storage /////\\n\\n struct WithdrawalQueueMetadata {\\n // cumulative total of all withdrawal requests included the ones that have already been claimed\\n uint128 queued;\\n // cumulative total of all the requests that can be claimed including the ones that have already been claimed\\n uint128 claimable;\\n // total of all the requests that have been claimed\\n uint128 claimed;\\n // index of the next withdrawal request starting at 0\\n uint128 nextWithdrawalIndex;\\n }\\n\\n /// @notice Global metadata for the withdrawal queue including:\\n /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed\\n /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed\\n /// claimed - total of all the requests that have been claimed\\n /// nextWithdrawalIndex - index of the next withdrawal request starting at 0\\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\\n\\n struct WithdrawalRequest {\\n address withdrawer;\\n bool claimed;\\n uint40 timestamp; // timestamp of the withdrawal request\\n // Amount of oTokens to redeem. eg OETH\\n uint128 amount;\\n // cumulative total of all withdrawal requests including this one.\\n // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\\n uint128 queued;\\n }\\n\\n /// @notice Mapping of withdrawal request indices to the user withdrawal request data\\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\\n\\n /// @notice Sets a minimum delay that is required to elapse between\\n /// requesting async withdrawals and claiming the request.\\n /// When set to 0 async withdrawals are disabled.\\n uint256 public withdrawalClaimDelay;\\n\\n /// @notice Time in seconds that the vault last rebased yield.\\n uint64 public lastRebase;\\n\\n /// @notice Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\\n uint64 public dripDuration;\\n\\n /// @notice max rebase percentage per second\\n /// Can be used to set maximum yield of the protocol,\\n /// spreading out yield over time\\n uint64 public rebasePerSecondMax;\\n\\n /// @notice target rebase rate limit, based on past rates and funds available.\\n uint64 public rebasePerSecondTarget;\\n\\n uint256 internal constant MAX_REBASE = 0.02 ether;\\n uint256 internal constant MAX_REBASE_PER_SECOND =\\n uint256(0.05 ether) / 1 days;\\n\\n /// @notice Default strategy for asset\\n address public defaultStrategy;\\n\\n /// @notice Address authorized to call `rebase()` directly. The Governor\\n /// and Strategist are always allowed in addition to this address.\\n address public operatorAddr;\\n\\n // For future use\\n uint256[41] private __gap;\\n\\n /// @notice Index of WETH asset in allAssets array\\n /// Legacy OETHVaultCore code, relocated here for vault consistency.\\n uint256 private _deprecated_wethAssetIndex;\\n\\n /// @dev Address of the asset (eg. WETH or USDC)\\n address public immutable asset;\\n uint8 internal immutable assetDecimals;\\n\\n // slither-disable-end constable-states\\n // slither-disable-end uninitialized-state\\n\\n constructor(address _asset) {\\n uint8 _decimals = IERC20Metadata(_asset).decimals();\\n require(_decimals <= 18, \\\"invalid asset decimals\\\");\\n asset = _asset;\\n assetDecimals = _decimals;\\n }\\n\\n /// @notice Deprecated: use `oToken()` instead.\\n function oUSD() external view returns (OUSD) {\\n return oToken;\\n }\\n}\\n\",\"keccak256\":\"0x9245e680c777afc86fc97e0101940bd0d702b206e49b940c42c574be92860e4f\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x60c0604052603d80546001600160a01b0319908116909155603e805482169055603f8054909116905534801561003457600080fd5b5060405161541938038061541983398101604081905261005391610133565b808080806000816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100bb9190610163565b905060128160ff1611156101155760405162461bcd60e51b815260206004820152601660248201527f696e76616c696420617373657420646563696d616c7300000000000000000000604482015260640160405180910390fd5b6001600160a01b0390911660805260ff1660a0525061018692505050565b60006020828403121561014557600080fd5b81516001600160a01b038116811461015c57600080fd5b9392505050565b60006020828403121561017557600080fd5b815160ff8116811461015c57600080fd5b60805160a0516151c661025360003960008181610fbb015281816120ac0152818161319201528181613773015281816138170152818161408f01526144440152600081816105870152818161088b01528181610c5801528181610ff9015281816112e80152818161144d0152818161176c0152818161187a01528181612ca1015281816132630152818161339101528181613ae601528181613dbb01528181613ef2015281816140fa01528181614145015281816141ad0152818161446b01526148a601526151c66000f3fe608060405234801561001057600080fd5b50600436106104075760003560e01c8063663e64ce11610220578063ae69f3cb11610130578063c7af3352116100b8578063e6cc543211610087578063e6cc5432146109e5578063ea33b8e4146109f9578063f3f18c3714610a01578063f844443614610a14578063fac5bb9b14610a2757600080fd5b8063c7af3352146109ba578063c9919112146109c2578063d38bfff4146109ca578063d4c3eea0146109dd57600080fd5b8063b9b17f9f116100ff578063b9b17f9f14610975578063bb7a632e1461097d578063c3b2886414610997578063c4d66de81461099f578063c5f00841146109b257600080fd5b8063ae69f3cb14610934578063af14052c14610947578063b2c9336d1461094f578063b4925a201461096257600080fd5b806395b166bc116101b35780639fa1826e116101825780639fa1826e146108f6578063a0712d68146108ff578063a0aead4d14610912578063ab80dafb14610919578063abaa99161461092c57600080fd5b806395b166bc146108685780639be918e61461087b5780639e428552146108bb5780639ee679e8146108ce57600080fd5b80638e510b52116101ef5780638e510b521461079c5780638ec489a2146107a5578063937b2581146107b857806394828ffd1461086057600080fd5b8063663e64ce14610750578063773540b31461076357806378f353a114610776578063840c4c7a1461078957600080fd5b806339ebf8231161031b578063527e83a8116102ae5780635802a1721161027d5780635802a172146106fe578063597c89101461070f5780635d36b190146107225780635f5152261461072a5780636217f3ea1461073d57600080fd5b8063527e83a8146106aa57806353ca9f24146106c4578063570d8e1d146106d857806357bee944146106eb57600080fd5b806345e4213b116102ea57806345e4213b1461063b57806348e30f541461064457806349c1d54d146106655780634d5f46291461067857600080fd5b806339ebf823146105a95780633b8ae397146105ed5780633dbc911f146106005780634530820a1461060857600080fd5b80631a32aad61161039e5780632acada4d1161036d5780632acada4d146104f35780632da845a81461050857806331e19cfa1461051b578063362bd1a31461052357806338d52e0f1461058257600080fd5b80631a32aad6146104ad5780631cfbe7bc146104c05780631edfe3da146104d3578063207134b0146104ea57600080fd5b80631072cbea116103da5780631072cbea14610461578063156e29f614610474578063175188e8146104875780631816dd4a1461049a57600080fd5b80630493a0fa1461040c57806309f49bf5146104215780630acbda75146104295780630c340a241461043c575b600080fd5b61041f61041a366004614b54565b610a3a565b005b61041f610af0565b61041f610437366004614b54565b610b60565b610444610c0b565b6040516001600160a01b0390911681526020015b60405180910390f35b61041f61046f366004614b89565b610c28565b61041f610482366004614bb3565b610ce6565b61041f610495366004614be6565b610d59565b61041f6104a8366004614be6565b6110f7565b603c54610444906001600160a01b031681565b61041f6104ce366004614b54565b6111fe565b6104dc60395481565b604051908152602001610458565b6104dc60435481565b6104fb6112c0565b6040516104589190614c01565b61041f610516366004614be6565b611337565b6036546104dc565b604b54604c5461054f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610458565b6104447f000000000000000000000000000000000000000000000000000000000000000081565b6105d66105b7366004614be6565b6035602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610458565b61041f6105fb366004614be6565b6113a9565b61041f6115bc565b61062b610616366004614be6565b60496020526000908152604090205460ff1681565b6040519015158152602001610458565b6104dc604e5481565b610657610652366004614c91565b611632565b604051610458929190614cd2565b604254610444906001600160a01b031681565b604f5461069290600160c01b90046001600160401b031681565b6040516001600160401b039091168152602001610458565b604f5461069290600160801b90046001600160401b031681565b60375461062b90600160a01b900460ff1681565b603f54610444906001600160a01b031681565b61041f6106f9366004614be6565b6117a8565b603c546001600160a01b0316610444565b61041f61071d366004614be6565b61195b565b61041f61199f565b6104dc610738366004614be6565b611a45565b61041f61074b366004614b54565b611a56565b61041f61075e366004614b54565b611bda565b61041f610771366004614be6565b611c33565b604f54610692906001600160401b031681565b61041f610797366004614d1f565b611ca5565b6104dc60415481565b61041f6107b3366004614b54565b611d2c565b6108196107c6366004614b54565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a001610458565b61041f611de1565b61041f610876366004614be6565b611e51565b61062b610889366004614be6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b61041f6108c9366004614be6565b611f18565b6108e16108dc366004614b54565b611f8a565b60408051928352602083019190915201610458565b6104dc603a5481565b61041f61090d366004614b54565b6122ca565b60016104dc565b61041f610927366004614b54565b61233b565b61041f61248a565b61041f610942366004614d1f565b612502565b61041f61257e565b61041f61095d366004614b54565b612639565b61041f610970366004614b54565b612692565b61041f6127b0565b604f5461069290600160401b90046001600160401b031681565b6104fb6127b8565b61041f6109ad366004614be6565b61281a565b61041f6129c5565b61062b612a3b565b61041f612a6c565b61041f6109d8366004614be6565b612aac565b6104dc612b50565b60375461062b90600160a81b900460ff1681565b6104dc612b5a565b605154610444906001600160a01b031681565b6104dc610a22366004614b54565b612be9565b605054610444906001600160a01b031681565b603f546001600160a01b0316331480610a565750610a56612a3b565b610a7b5760405162461bcd60e51b8152600401610a7290614da3565b60405180910390fd5b610a83612cda565b50610a8d81613074565b604f80546001600160401b0392909216600160401b0267ffffffffffffffff60401b199092169190911790556040518181527f406e15fbca1d8ded2dbb06765fea3a54f18395c54125a4c9916dd00ea14ee15e906020015b60405180910390a150565b603f546001600160a01b0316331480610b0c5750610b0c612a3b565b610b285760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b610b68612a3b565b610b845760405162461bcd60e51b8152600401610a7290614deb565b611388811115610bd65760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f7420657863656564203530250000000000000000006044820152606401610a72565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c790602001610ae5565b6000610c236000805160206151718339815191525490565b905090565b610c30612a3b565b610c4c5760405162461bcd60e51b8152600401610a7290614deb565b816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610cc65760405162461bcd60e51b815260206004820152601660248201527513db9b1e481d5b9cdd5c1c1bdc9d195908185cdcd95d60521b6044820152606401610a72565b610ce2610cd1610c0b565b6001600160a01b03841690836130e0565b5050565b603754600160a81b900460ff1615610d105760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101610d425760405162461bcd60e51b8152600401610a7290614e4a565b60028255610d4f84613136565b5060019055505050565b610d61612a3b565b610d7d5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff16610db55760405162461bcd60e51b8152600401610a7290614e72565b6050546001600160a01b03808316911603610e125760405162461bcd60e51b815260206004820152601d60248201527f53747261746567792069732064656661756c7420666f722061737365740000006044820152606401610a72565b6036548060005b82811015610e6857836001600160a01b031660368281548110610e3e57610e3e614ea1565b6000918252602090912001546001600160a01b031603610e6057809150610e68565b600101610e19565b50818110156110f2576036610e7e600184614ecd565b81548110610e8e57610e8e614ea1565b600091825260209091200154603680546001600160a01b039092169183908110610eba57610eba614ea1565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610ef957610ef9614ee0565b6001900381819060005260206000200160006101000a8154906001600160a01b03021916905590556000839050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610f6157600080fd5b505af1158015610f75573d6000803e3d6000fd5b505050506001600160a01b0384166000908152603560209081526040808320805460ff199081169091556049909252822080549091169055610fe26509184e72a00060ff7f00000000000000000000000000000000000000000000000000000000000000001660126132a7565b604051632fa8a91360e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192508291841690635f51522690602401602060405180830381865afa15801561104d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110719190614ef6565b106110b35760405162461bcd60e51b81526020600482015260126024820152715374726174656779206861732066756e647360701b6044820152606401610a72565b6040516001600160a01b03861681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49060200160405180910390a150505b505050565b6110ff612a3b565b61111b5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff166111535760405162461bcd60e51b8152600401610a7290614e72565b6001600160a01b03811660009081526049602052604090205460ff16156111b25760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481dda1a5d195b1a5cdd1959606a1b6044820152606401610a72565b6001600160a01b038116600081815260496020526040808220805460ff19166001179055517f47c8c96a5942f094264111c5fe7f6a4fe86efe63254a6fa7afa5fc84f07d58e89190a250565b611206612a3b565b6112225760405162461bcd60e51b8152600401610a7290614deb565b80158061123f5750610258811015801561123f57506213c6808111155b61128b5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636c61696d2064656c617920706572696f640000000000006044820152606401610a72565b604e8190556040518181527fc59f5e32049abab44ddea11021f5abb89422a2f550837afcf25df9fc8d0db6b090602001610ae5565b60408051600180825281830190925260609160009190602080830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061131a5761131a614ea1565b6001600160a01b0390921660209283029190910190910152919050565b61133f612a3b565b61135b5760405162461bcd60e51b8152600401610a7290614deb565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610ae5565b6113b1612a3b565b6113cd5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff16156114365760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f766564000000000000006044820152606401610a72565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa15801561149c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c09190614f25565b61150c5760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a72565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610ae5565b603f546001600160a01b03163314806115d857506115d8612a3b565b6115f45760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b603754606090600090600160a81b900460ff16156116625760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016116945760405162461bcd60e51b8152600401610a7290614e4a565b600282556116a061330b565b50846001600160401b038111156116b9576116b9614f0f565b6040519080825280602002602001820160405280156116e2578160200160208202803683370190505b50935060005b8581101561175e5761171187878381811061170557611705614ea1565b905060200201356134e7565b85828151811061172357611723614ea1565b60200260200101818152505084818151811061174157611741614ea1565b6020026020010151846117549190614f47565b93506001016116e8565b506117936001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130e0565b61179b613848565b6001825550509250929050565b603f546001600160a01b03163314806117c457506117c4612a3b565b6117e05760405162461bcd60e51b8152600401610a7290614da3565b6040516001600160a01b03821681527f45a9e715f8779ebeab88d3e8d081fb8b484b7730857e7c4478a95a5b1d8f79489060200160405180910390a16001600160a01b03811615611939576001600160a01b03811660009081526035602052604090205460ff166118635760405162461bcd60e51b8152600401610a7290614e72565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa1580156118c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ed9190614f25565b6119395760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a72565b605080546001600160a01b0319166001600160a01b0392909216919091179055565b603f546001600160a01b03163314806119775750611977612a3b565b6119935760405162461bcd60e51b8152600401610a7290614da3565b61199c816139bb565b50565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614611a3a5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610a72565b611a4333613a83565b565b6000611a5082613ae2565b92915050565b603754600160a81b900460ff1615611a805760405162461bcd60e51b8152600401610a7290614e22565b3360009081526035602052604090205460ff161515600114611adb5760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a72565b3360009081526049602052604090205460ff161515600114611b3a5760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a72565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051611b6b929190614f5a565b60405180910390a1603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90611ba59033908590600401614f5a565b600060405180830381600087803b158015611bbf57600080fd5b505af1158015611bd3573d6000803e3d6000fd5b5050505050565b611be2612a3b565b611bfe5760405162461bcd60e51b8152600401610a7290614deb565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610ae5565b611c3b612a3b565b611c575760405162461bcd60e51b8152600401610a7290614deb565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610ae5565b603f546001600160a01b0316331480611cc15750611cc1612a3b565b611cdd5760405162461bcd60e51b8152600401610a7290614da3565b60008051602061515183398151915280546001198101611d0f5760405162461bcd60e51b8152600401610a7290614e4a565b60028255611d208787878787613d44565b50600190555050505050565b603f546001600160a01b0316331480611d485750611d48612a3b565b611d645760405162461bcd60e51b8152600401610a7290614da3565b670de0b6b3a7640000811115611dac5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b6044820152606401610a72565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610ae5565b603f546001600160a01b0316331480611dfd5750611dfd612a3b565b611e195760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e59612a3b565b611e755760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526049602052604090205460ff16611ecf5760405162461bcd60e51b815260206004820152600f60248201526e139bdd081dda1a5d195b1a5cdd1959608a1b6044820152606401610a72565b6001600160a01b038116600081815260496020526040808220805460ff19169055517f0ec40967a61509853550658e51d0e4297f7cba244fe4adc8ba18b5631ac20e2f9190a250565b611f20612a3b565b611f3c5760405162461bcd60e51b8152600401610a7290614deb565b605180546001600160a01b0319166001600160a01b0383169081179091556040519081527fb3b3f5f64ab192e4b5fefde1f51ce9733bbdcf831951543b325aebd49cc27ec490602001610ae5565b6037546000908190600160a81b900460ff1615611fb95760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101611feb5760405162461bcd60e51b8152600401610a7290614e4a565b600282556000851161203f5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a72565b6000604e54116120915760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a72565b604c54600160801b90046001600160801b031693506120d5857f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b604b546120eb91906001600160801b0316614f47565b92506121006120fb856001614f47565b613f83565b604c80546001600160801b03928316600160801b02921691909117905561212683613f83565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff16918101919091526060810161217687613f83565b6001600160801b0316815260200161218d85613f83565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906122489033908990600401614f5a565b600060405180830381600087803b15801561226257600080fd5b505af1158015612276573d6000803e3d6000fd5b50505050612282613848565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff16156122f45760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016123265760405162461bcd60e51b8152600401610a7290614e4a565b6002825561233383613136565b506001905550565b603754600160a81b900460ff16156123655760405162461bcd60e51b8152600401610a7290614e22565b3360009081526035602052604090205460ff1615156001146123c05760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a72565b3360009081526049602052604090205460ff16151560011461241f5760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a72565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853382604051612450929190614f5a565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611ba59033908590600401614f5a565b603754600160a81b900460ff16156124b45760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016124e65760405162461bcd60e51b8152600401610a7290614e4a565b600282556124f261330b565b506124fb613fec565b5060019055565b603f546001600160a01b031633148061251e575061251e612a3b565b61253a5760405162461bcd60e51b8152600401610a7290614da3565b6000805160206151518339815191528054600119810161256c5760405162461bcd60e51b8152600401610a7290614e4a565b60028255611d20308888888888614215565b600080516020615151833981519152805460011981016125b05760405162461bcd60e51b8152600401610a7290614e4a565b600282556051546001600160a01b03163314806125d75750603f546001600160a01b031633145b806125e557506125e5612a3b565b6126295760405162461bcd60e51b815260206004820152601560248201527410d85b1b195c881b9bdd08185d5d1a1bdc9a5e9959605a1b6044820152606401610a72565b612631612cda565b505060019055565b612641612a3b565b61265d5760405162461bcd60e51b8152600401610a7290614deb565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610ae5565b603f546001600160a01b03163314806126ae57506126ae612a3b565b6126ca5760405162461bcd60e51b8152600401610a7290614da3565b6126d2612cda565b5060006301e133806126e5606484614f73565b6126ef9190614f73565b90506127056201518066b1a2bc2ec50000614f73565b8111156127445760405162461bcd60e51b815260206004820152600d60248201526c0a4c2e8ca40e8dede40d0d2ced609b1b6044820152606401610a72565b61274d81613074565b604f80546001600160401b0392909216600160801b0267ffffffffffffffff60801b199092169190911790556040518181527fef46f143af5fead0010484fe7d6ec2e2972420faa76157f5a6075aa72e614cb59060200160405180910390a15050565b61199c61330b565b6060603680548060200260200160405190810160405280929190818152602001828054801561281057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116127f2575b5050505050905090565b612822612a3b565b61283e5760405162461bcd60e51b8152600401610a7290614deb565b600054610100900460ff1680612857575060005460ff16155b6128ba5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a72565b600054610100900460ff161580156128dc576000805461ffff19166101011790555b6001600160a01b03821661292b5760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b6044820152606401610a72565b603c80546001600160a01b0384166001600160a01b03199091161790556037805461ffff60a01b1916600160a81b1790556000603981905569054b40b1f852bda00000603a55604080519182526020820190819052905161298e91603691614ae3565b50604f805467ffffffffffffffff60401b19166a093a8000000000000000001790558015610ce2576000805461ff00191690555050565b603f546001600160a01b03163314806129e157506129e1612a3b565b6129fd5760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b6000612a536000805160206151718339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612a885750612a88612a3b565b612aa45760405162461bcd60e51b8152600401610a7290614da3565b611a436143a6565b612ab4612a3b565b612ad05760405162461bcd60e51b8152600401610a7290614deb565b612af8817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612b186000805160206151718339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000610c2361443b565b6000612be3603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd69190614ef6565b612bde61443b565b61448f565b50919050565b603754600090600160a81b900460ff1615612c165760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101612c485760405162461bcd60e51b8152600401610a7290614e4a565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115612c8957612c8761330b565b505b612c92846134e7565b9250612cc86001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130e0565b612cd0613848565b5060019055919050565b603754600090600160a01b900460ff1615612d295760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b6044820152606401610a72565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612d73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d979190614ef6565b90506000612da361443b565b905081600003612db65791506130719050565b600080612dc3848461448f565b90925090506000612dd48386614f47565b90508481111580612de457508381115b15612df3575091949350505050565b612e04826001600160401b03614662565b604f805477ffffffffffffffffffffffffffffffff000000000000000016600160c01b6001600160401b039384160267ffffffffffffffff19161742929092169190911790556042546001600160a01b031660008115612f405761271060435486612e6f9190614f95565b612e799190614f73565b90508015612f4057848110612edb5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b6064820152608401610a72565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612f0d9085908590600401614f5a565b600060405180830381600087803b158015612f2757600080fd5b505af1158015612f3b573d6000803e3d6000fd5b505050505b604080516001600160a01b0384168152602081018790529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a1603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fdd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130019190614ef6565b83111561306757603c546040516339a7919f60e01b8152600481018590526001600160a01b03909116906339a7919f90602401600060405180830381600087803b15801561304e57600080fd5b505af1158015613062573d6000803e3d6000fd5b505050505b5093955050505050505b90565b60006001600160401b038211156130dc5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610a72565b5090565b6110f28363a9059cbb60e01b84846040516024016130ff929190614f5a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614678565b600081116131865760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a72565b60006131b782601260ff7f0000000000000000000000000000000000000000000000000000000000000000166132a7565b90507f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516131ea929190614f5a565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132249033908590600401614f5a565b600060405180830381600087803b15801561323e57600080fd5b505af1158015613252573d6000803e3d6000fd5b5061328d9250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016905033308561474a565b61329561330b565b50603a548110610ce257610ce2613fec565b6000818311156132d7576132d06132be8385614ecd565b6132c990600a615093565b8590614788565b9350613301565b81831015613301576132fe6132ec8484614ecd565b6132f790600a615093565b8590614794565b93505b50825b9392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c548084169686019690965292909404166060830152600092839161335d9161509f565b6001600160801b03169050806000036133795760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156133e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134049190614ef6565b905060008360400151846020015161341c919061509f565b6001600160801b0316905080821161343957600094505050505090565b60006134458284614ecd565b90508084106134545780613456565b835b955060008686602001516001600160801b03166134739190614f47565b905061347e81613f83565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f463333906134d69083908a90918252602082015260400190565b60405180910390a150505050505090565b600080604e541161353a5760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a72565b6000828152604d6020908152604091829020825160a08101845281546001600160a01b038116825260ff600160a01b82041615158285015264ffffffffff600160a81b90910481168286019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915288519081018952604b548084168252849004831697810197909752604c54808316988801989098529190960490951694840194909452604e5491519093429261360192909116614f47565b11156136455760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b6044820152606401610a72565b80602001516001600160801b031682608001516001600160801b031611156136af5760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c69717569646974790000000000000000006044820152606401610a72565b81516001600160a01b031633146136f85760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b6044820152606401610a72565b60208201511561373c5760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b6044820152606401610a72565b6000848152604d60205260409020805460ff60a01b1916600160a01b179055606082015161379c906120fb906001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b81604001516137ab91906150be565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a361384082606001516001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b949350505050565b600061385261443b565b6041549091501561199c57600081116138ad5760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e672072657175657374730000006044820152606401610a72565b600061393082603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613906573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061392a9190614ef6565b906147a0565b9050604154670de0b6b3a7640000821161395b5761395682670de0b6b3a7640000614ecd565b61396d565b61396d670de0b6b3a764000083614ecd565b1115610ce25760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f7200006044820152606401610a72565b6001600160a01b03811660009081526035602052604090205460ff16613a235760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f72746564000000000000006044820152606401610a72565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a6357600080fd5b505af1158015613a77573d6000803e3d6000fd5b505050506110f261330b565b6001600160a01b038116613ad95760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610a72565b61199c816147c1565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614613b2557506000919050565b6040516370a0823160e01b815230600482015282906001600160a01b038216906370a0823190602401602060405180830381865afa158015613b6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b8f9190614ef6565b60365490925060005b81811015613cb457600060368281548110613bb557613bb5614ea1565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af690602401602060405180830381865afa158015613c0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c2f9190614f25565b15613cab57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f51522690602401602060405180830381865afa158015613c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c9e9190614ef6565b613ca89086614f47565b94505b50600101613b98565b5060408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529091613d029086614f47565b1015613d1357506000949350505050565b805160408201516001600160801b0391821691613d31911686614f47565b613d3b9190614ecd565b95945050505050565b6001600160a01b03851660009081526035602052604090205460ff16613da25760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b6044820152606401610a72565b600183148015613db25750600181145b8015613e1657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684846000818110613df657613df6614ea1565b9050602002016020810190613e0b9190614be6565b6001600160a01b0316145b613e625760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920617373657420697320737570706f727465640000000000000000006044820152606401610a72565b613e6a614828565b82826000818110613e7d57613e7d614ea1565b905060200201351115613ed25760405162461bcd60e51b815260206004820152601b60248201527f4e6f7420656e6f7567682061737365747320617661696c61626c6500000000006044820152606401610a72565b613f298583836000818110613ee957613ee9614ea1565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166130e09092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613f6457600080fd5b505af1158015613f78573d6000803e3d6000fd5b505050505050505050565b60006001600160801b038211156130dc5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610a72565b6050546001600160a01b0316806140005750565b600061400a614828565b905080600003614018575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015614062573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140869190614ef6565b905060006140cf7f000000000000000000000000000000000000000000000000000000000000000060ff1660126140c86039548661493690919063ffffffff16565b91906132a7565b90508083116140de5750505050565b60006140ea8285614ecd565b9050846141216001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682846130e0565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061416f907f0000000000000000000000000000000000000000000000000000000000000000908690600401614f5a565b600060405180830381600087803b15801561418957600080fd5b505af115801561419d573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b6001600160a01b03851660009081526035602052604090205460ff166142755760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b6044820152606401610a72565b8281146142c45760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d61746368000000000000006044820152606401610a72565b8260005b8181101561439357866001600160a01b031663d9caed12898888858181106142f2576142f2614ea1565b90506020020160208101906143079190614be6565b87878681811061431957614319614ea1565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561437057600080fd5b505af1158015614384573d6000803e3d6000fd5b505050508060010190506142c8565b5061439c61330b565b5050505050505050565b60365460005b8181101561443257603681815481106143c7576143c7614ea1565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b15801561440f57600080fd5b505af1158015614423573d6000803e3d6000fd5b505050508060010190506143ac565b50610ce261330b565b6000610c2360127f000000000000000000000000000000000000000000000000000000000000000060ff166140c87f0000000000000000000000000000000000000000000000000000000000000000613ae2565b6000806000603c60009054906101000a90046001600160a01b03166001600160a01b031663e696393a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156144e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061450b9190614ef6565b905060006145198287614ecd565b604f54909150600090614535906001600160401b031642614ecd565b604f54600160c01b90046001600160401b031694509050801580614557575081155b8061456157508587115b8061457357506001600160401b034210155b15614584576000945050505061465b565b61458e8787614ecd565b604f54909550600160401b90046001600160401b031660018111156145f3576145cb856145bc836002614f95565b6145c69089614f73565b61494b565b94506145e0856145db8389614f73565b614662565b94506145f0866145db8488614f95565b95505b604f54614634908790670de0b6b3a764000090600160801b90046001600160401b03166146208688614f95565b61462a9190614f95565b6145db9190614f73565b955061465486670de0b6b3a764000061462a66470de4df82000087614f95565b9550505050505b9250929050565b60008183106146715781613304565b5090919050565b60006146cd826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661495a9092919063ffffffff16565b8051909150156110f257808060200190518101906146eb9190614f25565b6110f25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a72565b6040516001600160a01b03808516602483015283166044820152606481018290526147829085906323b872dd60e01b906084016130ff565b50505050565b60006133048284614f95565b60006133048284614f73565b6000806147b584670de0b6b3a7640000614788565b90506138408184614794565b806001600160a01b03166147e16000805160206151718339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a360008051602061517183398151915255565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301526000928391614878919061509f565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156148ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149119190614ef6565b9050818111614924576000935050505090565b61492e8282614ecd565b935050505090565b60006133048383670de0b6b3a7640000614969565b60008183116146715781613304565b60606138408484600085614982565b6000806149768585614788565b9050613d3b8184614794565b6060824710156149e35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a72565b843b614a315760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a72565b600080866001600160a01b03168587604051614a4d9190615101565b60006040518083038185875af1925050503d8060008114614a8a576040519150601f19603f3d011682016040523d82523d6000602084013e614a8f565b606091505b5091509150614a9f828286614aaa565b979650505050505050565b60608315614ab9575081613304565b825115614ac95782518084602001fd5b8160405162461bcd60e51b8152600401610a72919061511d565b828054828255906000526020600020908101928215614b38579160200282015b82811115614b3857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614b03565b506130dc9291505b808211156130dc5760008155600101614b40565b600060208284031215614b6657600080fd5b5035919050565b80356001600160a01b0381168114614b8457600080fd5b919050565b60008060408385031215614b9c57600080fd5b614ba583614b6d565b946020939093013593505050565b600080600060608486031215614bc857600080fd5b614bd184614b6d565b95602085013595506040909401359392505050565b600060208284031215614bf857600080fd5b61330482614b6d565b602080825282518282018190526000918401906040840190835b81811015614c425783516001600160a01b0316835260209384019390920191600101614c1b565b509095945050505050565b60008083601f840112614c5f57600080fd5b5081356001600160401b03811115614c7657600080fd5b6020830191508360208260051b850101111561465b57600080fd5b60008060208385031215614ca457600080fd5b82356001600160401b03811115614cba57600080fd5b614cc685828601614c4d565b90969095509350505050565b6040808252835190820181905260009060208501906060840190835b81811015614d0c578351835260209384019390920191600101614cee565b5050602093909301939093525092915050565b600080600080600060608688031215614d3757600080fd5b614d4086614b6d565b945060208601356001600160401b03811115614d5b57600080fd5b614d6788828901614c4d565b90955093505060408601356001600160401b03811115614d8657600080fd5b614d9288828901614c4d565b969995985093965092949392505050565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60208082526015908201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115611a5057611a50614eb7565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614f0857600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215614f3757600080fd5b8151801515811461330457600080fd5b80820180821115611a5057611a50614eb7565b6001600160a01b03929092168252602082015260400190565b600082614f9057634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417611a5057611a50614eb7565b6001815b6001841115614fe757808504811115614fcb57614fcb614eb7565b6001841615614fd957908102905b60019390931c928002614fb0565b935093915050565b600082614ffe57506001611a50565b8161500b57506000611a50565b8160018114615021576002811461502b57615047565b6001915050611a50565b60ff84111561503c5761503c614eb7565b50506001821b611a50565b5060208310610133831016604e8410600b841016171561506a575081810a611a50565b6150776000198484614fac565b806000190482111561508b5761508b614eb7565b029392505050565b60006133048383614fef565b6001600160801b038281168282160390811115611a5057611a50614eb7565b6001600160801b038181168382160190811115611a5057611a50614eb7565b60005b838110156150f85781810151838201526020016150e0565b50506000910152565b600082516151138184602087016150dd565b9190910192915050565b602081526000825180602084015261513c8160408501602087016150dd565b601f01601f1916919091016040019291505056fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220a08c3a2bfd7441ee55fb0bc8c317eab6f9a4ec31b9a9340d9674dfe7d874a29864736f6c634300081c0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106104075760003560e01c8063663e64ce11610220578063ae69f3cb11610130578063c7af3352116100b8578063e6cc543211610087578063e6cc5432146109e5578063ea33b8e4146109f9578063f3f18c3714610a01578063f844443614610a14578063fac5bb9b14610a2757600080fd5b8063c7af3352146109ba578063c9919112146109c2578063d38bfff4146109ca578063d4c3eea0146109dd57600080fd5b8063b9b17f9f116100ff578063b9b17f9f14610975578063bb7a632e1461097d578063c3b2886414610997578063c4d66de81461099f578063c5f00841146109b257600080fd5b8063ae69f3cb14610934578063af14052c14610947578063b2c9336d1461094f578063b4925a201461096257600080fd5b806395b166bc116101b35780639fa1826e116101825780639fa1826e146108f6578063a0712d68146108ff578063a0aead4d14610912578063ab80dafb14610919578063abaa99161461092c57600080fd5b806395b166bc146108685780639be918e61461087b5780639e428552146108bb5780639ee679e8146108ce57600080fd5b80638e510b52116101ef5780638e510b521461079c5780638ec489a2146107a5578063937b2581146107b857806394828ffd1461086057600080fd5b8063663e64ce14610750578063773540b31461076357806378f353a114610776578063840c4c7a1461078957600080fd5b806339ebf8231161031b578063527e83a8116102ae5780635802a1721161027d5780635802a172146106fe578063597c89101461070f5780635d36b190146107225780635f5152261461072a5780636217f3ea1461073d57600080fd5b8063527e83a8146106aa57806353ca9f24146106c4578063570d8e1d146106d857806357bee944146106eb57600080fd5b806345e4213b116102ea57806345e4213b1461063b57806348e30f541461064457806349c1d54d146106655780634d5f46291461067857600080fd5b806339ebf823146105a95780633b8ae397146105ed5780633dbc911f146106005780634530820a1461060857600080fd5b80631a32aad61161039e5780632acada4d1161036d5780632acada4d146104f35780632da845a81461050857806331e19cfa1461051b578063362bd1a31461052357806338d52e0f1461058257600080fd5b80631a32aad6146104ad5780631cfbe7bc146104c05780631edfe3da146104d3578063207134b0146104ea57600080fd5b80631072cbea116103da5780631072cbea14610461578063156e29f614610474578063175188e8146104875780631816dd4a1461049a57600080fd5b80630493a0fa1461040c57806309f49bf5146104215780630acbda75146104295780630c340a241461043c575b600080fd5b61041f61041a366004614b54565b610a3a565b005b61041f610af0565b61041f610437366004614b54565b610b60565b610444610c0b565b6040516001600160a01b0390911681526020015b60405180910390f35b61041f61046f366004614b89565b610c28565b61041f610482366004614bb3565b610ce6565b61041f610495366004614be6565b610d59565b61041f6104a8366004614be6565b6110f7565b603c54610444906001600160a01b031681565b61041f6104ce366004614b54565b6111fe565b6104dc60395481565b604051908152602001610458565b6104dc60435481565b6104fb6112c0565b6040516104589190614c01565b61041f610516366004614be6565b611337565b6036546104dc565b604b54604c5461054f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610458565b6104447f000000000000000000000000000000000000000000000000000000000000000081565b6105d66105b7366004614be6565b6035602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610458565b61041f6105fb366004614be6565b6113a9565b61041f6115bc565b61062b610616366004614be6565b60496020526000908152604090205460ff1681565b6040519015158152602001610458565b6104dc604e5481565b610657610652366004614c91565b611632565b604051610458929190614cd2565b604254610444906001600160a01b031681565b604f5461069290600160c01b90046001600160401b031681565b6040516001600160401b039091168152602001610458565b604f5461069290600160801b90046001600160401b031681565b60375461062b90600160a01b900460ff1681565b603f54610444906001600160a01b031681565b61041f6106f9366004614be6565b6117a8565b603c546001600160a01b0316610444565b61041f61071d366004614be6565b61195b565b61041f61199f565b6104dc610738366004614be6565b611a45565b61041f61074b366004614b54565b611a56565b61041f61075e366004614b54565b611bda565b61041f610771366004614be6565b611c33565b604f54610692906001600160401b031681565b61041f610797366004614d1f565b611ca5565b6104dc60415481565b61041f6107b3366004614b54565b611d2c565b6108196107c6366004614b54565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a001610458565b61041f611de1565b61041f610876366004614be6565b611e51565b61062b610889366004614be6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b61041f6108c9366004614be6565b611f18565b6108e16108dc366004614b54565b611f8a565b60408051928352602083019190915201610458565b6104dc603a5481565b61041f61090d366004614b54565b6122ca565b60016104dc565b61041f610927366004614b54565b61233b565b61041f61248a565b61041f610942366004614d1f565b612502565b61041f61257e565b61041f61095d366004614b54565b612639565b61041f610970366004614b54565b612692565b61041f6127b0565b604f5461069290600160401b90046001600160401b031681565b6104fb6127b8565b61041f6109ad366004614be6565b61281a565b61041f6129c5565b61062b612a3b565b61041f612a6c565b61041f6109d8366004614be6565b612aac565b6104dc612b50565b60375461062b90600160a81b900460ff1681565b6104dc612b5a565b605154610444906001600160a01b031681565b6104dc610a22366004614b54565b612be9565b605054610444906001600160a01b031681565b603f546001600160a01b0316331480610a565750610a56612a3b565b610a7b5760405162461bcd60e51b8152600401610a7290614da3565b60405180910390fd5b610a83612cda565b50610a8d81613074565b604f80546001600160401b0392909216600160401b0267ffffffffffffffff60401b199092169190911790556040518181527f406e15fbca1d8ded2dbb06765fea3a54f18395c54125a4c9916dd00ea14ee15e906020015b60405180910390a150565b603f546001600160a01b0316331480610b0c5750610b0c612a3b565b610b285760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b610b68612a3b565b610b845760405162461bcd60e51b8152600401610a7290614deb565b611388811115610bd65760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f7420657863656564203530250000000000000000006044820152606401610a72565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c790602001610ae5565b6000610c236000805160206151718339815191525490565b905090565b610c30612a3b565b610c4c5760405162461bcd60e51b8152600401610a7290614deb565b816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610cc65760405162461bcd60e51b815260206004820152601660248201527513db9b1e481d5b9cdd5c1c1bdc9d195908185cdcd95d60521b6044820152606401610a72565b610ce2610cd1610c0b565b6001600160a01b03841690836130e0565b5050565b603754600160a81b900460ff1615610d105760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101610d425760405162461bcd60e51b8152600401610a7290614e4a565b60028255610d4f84613136565b5060019055505050565b610d61612a3b565b610d7d5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff16610db55760405162461bcd60e51b8152600401610a7290614e72565b6050546001600160a01b03808316911603610e125760405162461bcd60e51b815260206004820152601d60248201527f53747261746567792069732064656661756c7420666f722061737365740000006044820152606401610a72565b6036548060005b82811015610e6857836001600160a01b031660368281548110610e3e57610e3e614ea1565b6000918252602090912001546001600160a01b031603610e6057809150610e68565b600101610e19565b50818110156110f2576036610e7e600184614ecd565b81548110610e8e57610e8e614ea1565b600091825260209091200154603680546001600160a01b039092169183908110610eba57610eba614ea1565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610ef957610ef9614ee0565b6001900381819060005260206000200160006101000a8154906001600160a01b03021916905590556000839050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610f6157600080fd5b505af1158015610f75573d6000803e3d6000fd5b505050506001600160a01b0384166000908152603560209081526040808320805460ff199081169091556049909252822080549091169055610fe26509184e72a00060ff7f00000000000000000000000000000000000000000000000000000000000000001660126132a7565b604051632fa8a91360e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192508291841690635f51522690602401602060405180830381865afa15801561104d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110719190614ef6565b106110b35760405162461bcd60e51b81526020600482015260126024820152715374726174656779206861732066756e647360701b6044820152606401610a72565b6040516001600160a01b03861681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49060200160405180910390a150505b505050565b6110ff612a3b565b61111b5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff166111535760405162461bcd60e51b8152600401610a7290614e72565b6001600160a01b03811660009081526049602052604090205460ff16156111b25760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481dda1a5d195b1a5cdd1959606a1b6044820152606401610a72565b6001600160a01b038116600081815260496020526040808220805460ff19166001179055517f47c8c96a5942f094264111c5fe7f6a4fe86efe63254a6fa7afa5fc84f07d58e89190a250565b611206612a3b565b6112225760405162461bcd60e51b8152600401610a7290614deb565b80158061123f5750610258811015801561123f57506213c6808111155b61128b5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636c61696d2064656c617920706572696f640000000000006044820152606401610a72565b604e8190556040518181527fc59f5e32049abab44ddea11021f5abb89422a2f550837afcf25df9fc8d0db6b090602001610ae5565b60408051600180825281830190925260609160009190602080830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061131a5761131a614ea1565b6001600160a01b0390921660209283029190910190910152919050565b61133f612a3b565b61135b5760405162461bcd60e51b8152600401610a7290614deb565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610ae5565b6113b1612a3b565b6113cd5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff16156114365760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f766564000000000000006044820152606401610a72565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa15801561149c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c09190614f25565b61150c5760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a72565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610ae5565b603f546001600160a01b03163314806115d857506115d8612a3b565b6115f45760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b603754606090600090600160a81b900460ff16156116625760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016116945760405162461bcd60e51b8152600401610a7290614e4a565b600282556116a061330b565b50846001600160401b038111156116b9576116b9614f0f565b6040519080825280602002602001820160405280156116e2578160200160208202803683370190505b50935060005b8581101561175e5761171187878381811061170557611705614ea1565b905060200201356134e7565b85828151811061172357611723614ea1565b60200260200101818152505084818151811061174157611741614ea1565b6020026020010151846117549190614f47565b93506001016116e8565b506117936001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130e0565b61179b613848565b6001825550509250929050565b603f546001600160a01b03163314806117c457506117c4612a3b565b6117e05760405162461bcd60e51b8152600401610a7290614da3565b6040516001600160a01b03821681527f45a9e715f8779ebeab88d3e8d081fb8b484b7730857e7c4478a95a5b1d8f79489060200160405180910390a16001600160a01b03811615611939576001600160a01b03811660009081526035602052604090205460ff166118635760405162461bcd60e51b8152600401610a7290614e72565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa1580156118c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ed9190614f25565b6119395760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a72565b605080546001600160a01b0319166001600160a01b0392909216919091179055565b603f546001600160a01b03163314806119775750611977612a3b565b6119935760405162461bcd60e51b8152600401610a7290614da3565b61199c816139bb565b50565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614611a3a5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610a72565b611a4333613a83565b565b6000611a5082613ae2565b92915050565b603754600160a81b900460ff1615611a805760405162461bcd60e51b8152600401610a7290614e22565b3360009081526035602052604090205460ff161515600114611adb5760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a72565b3360009081526049602052604090205460ff161515600114611b3a5760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a72565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051611b6b929190614f5a565b60405180910390a1603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90611ba59033908590600401614f5a565b600060405180830381600087803b158015611bbf57600080fd5b505af1158015611bd3573d6000803e3d6000fd5b5050505050565b611be2612a3b565b611bfe5760405162461bcd60e51b8152600401610a7290614deb565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610ae5565b611c3b612a3b565b611c575760405162461bcd60e51b8152600401610a7290614deb565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610ae5565b603f546001600160a01b0316331480611cc15750611cc1612a3b565b611cdd5760405162461bcd60e51b8152600401610a7290614da3565b60008051602061515183398151915280546001198101611d0f5760405162461bcd60e51b8152600401610a7290614e4a565b60028255611d208787878787613d44565b50600190555050505050565b603f546001600160a01b0316331480611d485750611d48612a3b565b611d645760405162461bcd60e51b8152600401610a7290614da3565b670de0b6b3a7640000811115611dac5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b6044820152606401610a72565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610ae5565b603f546001600160a01b0316331480611dfd5750611dfd612a3b565b611e195760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e59612a3b565b611e755760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526049602052604090205460ff16611ecf5760405162461bcd60e51b815260206004820152600f60248201526e139bdd081dda1a5d195b1a5cdd1959608a1b6044820152606401610a72565b6001600160a01b038116600081815260496020526040808220805460ff19169055517f0ec40967a61509853550658e51d0e4297f7cba244fe4adc8ba18b5631ac20e2f9190a250565b611f20612a3b565b611f3c5760405162461bcd60e51b8152600401610a7290614deb565b605180546001600160a01b0319166001600160a01b0383169081179091556040519081527fb3b3f5f64ab192e4b5fefde1f51ce9733bbdcf831951543b325aebd49cc27ec490602001610ae5565b6037546000908190600160a81b900460ff1615611fb95760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101611feb5760405162461bcd60e51b8152600401610a7290614e4a565b600282556000851161203f5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a72565b6000604e54116120915760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a72565b604c54600160801b90046001600160801b031693506120d5857f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b604b546120eb91906001600160801b0316614f47565b92506121006120fb856001614f47565b613f83565b604c80546001600160801b03928316600160801b02921691909117905561212683613f83565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff16918101919091526060810161217687613f83565b6001600160801b0316815260200161218d85613f83565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906122489033908990600401614f5a565b600060405180830381600087803b15801561226257600080fd5b505af1158015612276573d6000803e3d6000fd5b50505050612282613848565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff16156122f45760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016123265760405162461bcd60e51b8152600401610a7290614e4a565b6002825561233383613136565b506001905550565b603754600160a81b900460ff16156123655760405162461bcd60e51b8152600401610a7290614e22565b3360009081526035602052604090205460ff1615156001146123c05760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a72565b3360009081526049602052604090205460ff16151560011461241f5760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a72565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853382604051612450929190614f5a565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611ba59033908590600401614f5a565b603754600160a81b900460ff16156124b45760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016124e65760405162461bcd60e51b8152600401610a7290614e4a565b600282556124f261330b565b506124fb613fec565b5060019055565b603f546001600160a01b031633148061251e575061251e612a3b565b61253a5760405162461bcd60e51b8152600401610a7290614da3565b6000805160206151518339815191528054600119810161256c5760405162461bcd60e51b8152600401610a7290614e4a565b60028255611d20308888888888614215565b600080516020615151833981519152805460011981016125b05760405162461bcd60e51b8152600401610a7290614e4a565b600282556051546001600160a01b03163314806125d75750603f546001600160a01b031633145b806125e557506125e5612a3b565b6126295760405162461bcd60e51b815260206004820152601560248201527410d85b1b195c881b9bdd08185d5d1a1bdc9a5e9959605a1b6044820152606401610a72565b612631612cda565b505060019055565b612641612a3b565b61265d5760405162461bcd60e51b8152600401610a7290614deb565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610ae5565b603f546001600160a01b03163314806126ae57506126ae612a3b565b6126ca5760405162461bcd60e51b8152600401610a7290614da3565b6126d2612cda565b5060006301e133806126e5606484614f73565b6126ef9190614f73565b90506127056201518066b1a2bc2ec50000614f73565b8111156127445760405162461bcd60e51b815260206004820152600d60248201526c0a4c2e8ca40e8dede40d0d2ced609b1b6044820152606401610a72565b61274d81613074565b604f80546001600160401b0392909216600160801b0267ffffffffffffffff60801b199092169190911790556040518181527fef46f143af5fead0010484fe7d6ec2e2972420faa76157f5a6075aa72e614cb59060200160405180910390a15050565b61199c61330b565b6060603680548060200260200160405190810160405280929190818152602001828054801561281057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116127f2575b5050505050905090565b612822612a3b565b61283e5760405162461bcd60e51b8152600401610a7290614deb565b600054610100900460ff1680612857575060005460ff16155b6128ba5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a72565b600054610100900460ff161580156128dc576000805461ffff19166101011790555b6001600160a01b03821661292b5760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b6044820152606401610a72565b603c80546001600160a01b0384166001600160a01b03199091161790556037805461ffff60a01b1916600160a81b1790556000603981905569054b40b1f852bda00000603a55604080519182526020820190819052905161298e91603691614ae3565b50604f805467ffffffffffffffff60401b19166a093a8000000000000000001790558015610ce2576000805461ff00191690555050565b603f546001600160a01b03163314806129e157506129e1612a3b565b6129fd5760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b6000612a536000805160206151718339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612a885750612a88612a3b565b612aa45760405162461bcd60e51b8152600401610a7290614da3565b611a436143a6565b612ab4612a3b565b612ad05760405162461bcd60e51b8152600401610a7290614deb565b612af8817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612b186000805160206151718339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000610c2361443b565b6000612be3603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd69190614ef6565b612bde61443b565b61448f565b50919050565b603754600090600160a81b900460ff1615612c165760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101612c485760405162461bcd60e51b8152600401610a7290614e4a565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115612c8957612c8761330b565b505b612c92846134e7565b9250612cc86001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130e0565b612cd0613848565b5060019055919050565b603754600090600160a01b900460ff1615612d295760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b6044820152606401610a72565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612d73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d979190614ef6565b90506000612da361443b565b905081600003612db65791506130719050565b600080612dc3848461448f565b90925090506000612dd48386614f47565b90508481111580612de457508381115b15612df3575091949350505050565b612e04826001600160401b03614662565b604f805477ffffffffffffffffffffffffffffffff000000000000000016600160c01b6001600160401b039384160267ffffffffffffffff19161742929092169190911790556042546001600160a01b031660008115612f405761271060435486612e6f9190614f95565b612e799190614f73565b90508015612f4057848110612edb5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b6064820152608401610a72565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612f0d9085908590600401614f5a565b600060405180830381600087803b158015612f2757600080fd5b505af1158015612f3b573d6000803e3d6000fd5b505050505b604080516001600160a01b0384168152602081018790529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a1603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fdd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130019190614ef6565b83111561306757603c546040516339a7919f60e01b8152600481018590526001600160a01b03909116906339a7919f90602401600060405180830381600087803b15801561304e57600080fd5b505af1158015613062573d6000803e3d6000fd5b505050505b5093955050505050505b90565b60006001600160401b038211156130dc5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610a72565b5090565b6110f28363a9059cbb60e01b84846040516024016130ff929190614f5a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614678565b600081116131865760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a72565b60006131b782601260ff7f0000000000000000000000000000000000000000000000000000000000000000166132a7565b90507f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516131ea929190614f5a565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132249033908590600401614f5a565b600060405180830381600087803b15801561323e57600080fd5b505af1158015613252573d6000803e3d6000fd5b5061328d9250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016905033308561474a565b61329561330b565b50603a548110610ce257610ce2613fec565b6000818311156132d7576132d06132be8385614ecd565b6132c990600a615093565b8590614788565b9350613301565b81831015613301576132fe6132ec8484614ecd565b6132f790600a615093565b8590614794565b93505b50825b9392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c548084169686019690965292909404166060830152600092839161335d9161509f565b6001600160801b03169050806000036133795760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156133e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134049190614ef6565b905060008360400151846020015161341c919061509f565b6001600160801b0316905080821161343957600094505050505090565b60006134458284614ecd565b90508084106134545780613456565b835b955060008686602001516001600160801b03166134739190614f47565b905061347e81613f83565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f463333906134d69083908a90918252602082015260400190565b60405180910390a150505050505090565b600080604e541161353a5760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a72565b6000828152604d6020908152604091829020825160a08101845281546001600160a01b038116825260ff600160a01b82041615158285015264ffffffffff600160a81b90910481168286019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915288519081018952604b548084168252849004831697810197909752604c54808316988801989098529190960490951694840194909452604e5491519093429261360192909116614f47565b11156136455760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b6044820152606401610a72565b80602001516001600160801b031682608001516001600160801b031611156136af5760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c69717569646974790000000000000000006044820152606401610a72565b81516001600160a01b031633146136f85760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b6044820152606401610a72565b60208201511561373c5760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b6044820152606401610a72565b6000848152604d60205260409020805460ff60a01b1916600160a01b179055606082015161379c906120fb906001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b81604001516137ab91906150be565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a361384082606001516001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b949350505050565b600061385261443b565b6041549091501561199c57600081116138ad5760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e672072657175657374730000006044820152606401610a72565b600061393082603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613906573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061392a9190614ef6565b906147a0565b9050604154670de0b6b3a7640000821161395b5761395682670de0b6b3a7640000614ecd565b61396d565b61396d670de0b6b3a764000083614ecd565b1115610ce25760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f7200006044820152606401610a72565b6001600160a01b03811660009081526035602052604090205460ff16613a235760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f72746564000000000000006044820152606401610a72565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a6357600080fd5b505af1158015613a77573d6000803e3d6000fd5b505050506110f261330b565b6001600160a01b038116613ad95760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610a72565b61199c816147c1565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614613b2557506000919050565b6040516370a0823160e01b815230600482015282906001600160a01b038216906370a0823190602401602060405180830381865afa158015613b6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b8f9190614ef6565b60365490925060005b81811015613cb457600060368281548110613bb557613bb5614ea1565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af690602401602060405180830381865afa158015613c0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c2f9190614f25565b15613cab57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f51522690602401602060405180830381865afa158015613c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c9e9190614ef6565b613ca89086614f47565b94505b50600101613b98565b5060408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529091613d029086614f47565b1015613d1357506000949350505050565b805160408201516001600160801b0391821691613d31911686614f47565b613d3b9190614ecd565b95945050505050565b6001600160a01b03851660009081526035602052604090205460ff16613da25760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b6044820152606401610a72565b600183148015613db25750600181145b8015613e1657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684846000818110613df657613df6614ea1565b9050602002016020810190613e0b9190614be6565b6001600160a01b0316145b613e625760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920617373657420697320737570706f727465640000000000000000006044820152606401610a72565b613e6a614828565b82826000818110613e7d57613e7d614ea1565b905060200201351115613ed25760405162461bcd60e51b815260206004820152601b60248201527f4e6f7420656e6f7567682061737365747320617661696c61626c6500000000006044820152606401610a72565b613f298583836000818110613ee957613ee9614ea1565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166130e09092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613f6457600080fd5b505af1158015613f78573d6000803e3d6000fd5b505050505050505050565b60006001600160801b038211156130dc5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610a72565b6050546001600160a01b0316806140005750565b600061400a614828565b905080600003614018575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015614062573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140869190614ef6565b905060006140cf7f000000000000000000000000000000000000000000000000000000000000000060ff1660126140c86039548661493690919063ffffffff16565b91906132a7565b90508083116140de5750505050565b60006140ea8285614ecd565b9050846141216001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682846130e0565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061416f907f0000000000000000000000000000000000000000000000000000000000000000908690600401614f5a565b600060405180830381600087803b15801561418957600080fd5b505af115801561419d573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b6001600160a01b03851660009081526035602052604090205460ff166142755760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b6044820152606401610a72565b8281146142c45760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d61746368000000000000006044820152606401610a72565b8260005b8181101561439357866001600160a01b031663d9caed12898888858181106142f2576142f2614ea1565b90506020020160208101906143079190614be6565b87878681811061431957614319614ea1565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561437057600080fd5b505af1158015614384573d6000803e3d6000fd5b505050508060010190506142c8565b5061439c61330b565b5050505050505050565b60365460005b8181101561443257603681815481106143c7576143c7614ea1565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b15801561440f57600080fd5b505af1158015614423573d6000803e3d6000fd5b505050508060010190506143ac565b50610ce261330b565b6000610c2360127f000000000000000000000000000000000000000000000000000000000000000060ff166140c87f0000000000000000000000000000000000000000000000000000000000000000613ae2565b6000806000603c60009054906101000a90046001600160a01b03166001600160a01b031663e696393a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156144e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061450b9190614ef6565b905060006145198287614ecd565b604f54909150600090614535906001600160401b031642614ecd565b604f54600160c01b90046001600160401b031694509050801580614557575081155b8061456157508587115b8061457357506001600160401b034210155b15614584576000945050505061465b565b61458e8787614ecd565b604f54909550600160401b90046001600160401b031660018111156145f3576145cb856145bc836002614f95565b6145c69089614f73565b61494b565b94506145e0856145db8389614f73565b614662565b94506145f0866145db8488614f95565b95505b604f54614634908790670de0b6b3a764000090600160801b90046001600160401b03166146208688614f95565b61462a9190614f95565b6145db9190614f73565b955061465486670de0b6b3a764000061462a66470de4df82000087614f95565b9550505050505b9250929050565b60008183106146715781613304565b5090919050565b60006146cd826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661495a9092919063ffffffff16565b8051909150156110f257808060200190518101906146eb9190614f25565b6110f25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a72565b6040516001600160a01b03808516602483015283166044820152606481018290526147829085906323b872dd60e01b906084016130ff565b50505050565b60006133048284614f95565b60006133048284614f73565b6000806147b584670de0b6b3a7640000614788565b90506138408184614794565b806001600160a01b03166147e16000805160206151718339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a360008051602061517183398151915255565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301526000928391614878919061509f565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156148ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149119190614ef6565b9050818111614924576000935050505090565b61492e8282614ecd565b935050505090565b60006133048383670de0b6b3a7640000614969565b60008183116146715781613304565b60606138408484600085614982565b6000806149768585614788565b9050613d3b8184614794565b6060824710156149e35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a72565b843b614a315760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a72565b600080866001600160a01b03168587604051614a4d9190615101565b60006040518083038185875af1925050503d8060008114614a8a576040519150601f19603f3d011682016040523d82523d6000602084013e614a8f565b606091505b5091509150614a9f828286614aaa565b979650505050505050565b60608315614ab9575081613304565b825115614ac95782518084602001fd5b8160405162461bcd60e51b8152600401610a72919061511d565b828054828255906000526020600020908101928215614b38579160200282015b82811115614b3857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614b03565b506130dc9291505b808211156130dc5760008155600101614b40565b600060208284031215614b6657600080fd5b5035919050565b80356001600160a01b0381168114614b8457600080fd5b919050565b60008060408385031215614b9c57600080fd5b614ba583614b6d565b946020939093013593505050565b600080600060608486031215614bc857600080fd5b614bd184614b6d565b95602085013595506040909401359392505050565b600060208284031215614bf857600080fd5b61330482614b6d565b602080825282518282018190526000918401906040840190835b81811015614c425783516001600160a01b0316835260209384019390920191600101614c1b565b509095945050505050565b60008083601f840112614c5f57600080fd5b5081356001600160401b03811115614c7657600080fd5b6020830191508360208260051b850101111561465b57600080fd5b60008060208385031215614ca457600080fd5b82356001600160401b03811115614cba57600080fd5b614cc685828601614c4d565b90969095509350505050565b6040808252835190820181905260009060208501906060840190835b81811015614d0c578351835260209384019390920191600101614cee565b5050602093909301939093525092915050565b600080600080600060608688031215614d3757600080fd5b614d4086614b6d565b945060208601356001600160401b03811115614d5b57600080fd5b614d6788828901614c4d565b90955093505060408601356001600160401b03811115614d8657600080fd5b614d9288828901614c4d565b969995985093965092949392505050565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60208082526015908201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115611a5057611a50614eb7565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614f0857600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215614f3757600080fd5b8151801515811461330457600080fd5b80820180821115611a5057611a50614eb7565b6001600160a01b03929092168252602082015260400190565b600082614f9057634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417611a5057611a50614eb7565b6001815b6001841115614fe757808504811115614fcb57614fcb614eb7565b6001841615614fd957908102905b60019390931c928002614fb0565b935093915050565b600082614ffe57506001611a50565b8161500b57506000611a50565b8160018114615021576002811461502b57615047565b6001915050611a50565b60ff84111561503c5761503c614eb7565b50506001821b611a50565b5060208310610133831016604e8410600b841016171561506a575081810a611a50565b6150776000198484614fac565b806000190482111561508b5761508b614eb7565b029392505050565b60006133048383614fef565b6001600160801b038281168282160390811115611a5057611a50614eb7565b6001600160801b038181168382160190811115611a5057611a50614eb7565b60005b838110156150f85781810151838201526020016150e0565b50506000910152565b600082516151138184602087016150dd565b9190910192915050565b602081526000825180602084015261513c8160408501602087016150dd565b601f01601f1916919091016040019291505056fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220a08c3a2bfd7441ee55fb0bc8c317eab6f9a4ec31b9a9340d9674dfe7d874a29864736f6c634300081c0033", "libraries": {}, "devdoc": { "author": "Origin Protocol Inc", @@ -1518,6 +1518,9 @@ "yield": "amount of expected yield" } }, + "rebase()": { + "details": "Restricted to the Operator, Strategist or Governor." + }, "removeStrategy(address)": { "params": { "_addr": "Address of the strategy to remove" @@ -1552,14 +1555,14 @@ "_dripDuration": "Time in seconds to target a constant yield rate" } }, - "setRebaseRateMax(uint256)": { + "setOperatorAddr(address)": { "params": { - "apr": "in 1e18 notation. 3 * 1e18 = 3% APR" + "_operator": "New operator address. May be set to the zero address to disable operator-initiated rebases." } }, - "setRebaseThreshold(uint256)": { + "setRebaseRateMax(uint256)": { "params": { - "_threshold": "OToken amount with 18 fixed decimals." + "apr": "in 1e18 notation. 3 * 1e18 = 3% APR" } }, "setStrategistAddr(address)": { @@ -1693,6 +1696,9 @@ "oUSD()": { "notice": "Deprecated: use `oToken()` instead." }, + "operatorAddr()": { + "notice": "Address authorized to call `rebase()` directly. The Governor and Strategist are always allowed in addition to this address." + }, "pauseCapital()": { "notice": "Set the deposit paused flag to true to prevent capital movement." }, @@ -1714,9 +1720,6 @@ "rebasePerSecondTarget()": { "notice": "target rebase rate limit, based on past rates and funds available." }, - "rebaseThreshold()": { - "notice": "OToken mints over this amount automatically rebase. 18 decimals." - }, "removeStrategy(address)": { "notice": "Remove a strategy from the Vault." }, @@ -1738,12 +1741,12 @@ "setMaxSupplyDiff(uint256)": { "notice": "Sets the maximum allowable difference between total supply and asset' value." }, + "setOperatorAddr(address)": { + "notice": "Set the address authorized to call `rebase()`." + }, "setRebaseRateMax(uint256)": { "notice": "Set a yield streaming max rate. This spreads yield over time if it is above the max rate. This is a per rebase APR which due to compounding differs from the yearly APR. Governance should consider this fact when picking a desired APR" }, - "setRebaseThreshold(uint256)": { - "notice": "Set a minimum amount of OTokens in a mint or redeem that triggers a rebase" - }, "setStrategistAddr(address)": { "notice": "Set address of Strategist" }, @@ -1810,7 +1813,7 @@ "storageLayout": { "storage": [ { - "astId": 39230, + "astId": 42033, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "initialized", "offset": 0, @@ -1818,7 +1821,7 @@ "type": "t_bool" }, { - "astId": 39233, + "astId": 42036, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "initializing", "offset": 1, @@ -1826,7 +1829,7 @@ "type": "t_bool" }, { - "astId": 39273, + "astId": 42076, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "______gap", "offset": 0, @@ -1834,7 +1837,7 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 42977, + "astId": 45777, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "_deprecated_assets", "offset": 0, @@ -1842,7 +1845,7 @@ "type": "t_uint256" }, { - "astId": 42981, + "astId": 45781, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "_deprecated_allAssets", "offset": 0, @@ -1850,15 +1853,15 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 42992, + "astId": 45792, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "strategies", "offset": 0, "slot": "53", - "type": "t_mapping(t_address,t_struct(Strategy)42986_storage)" + "type": "t_mapping(t_address,t_struct(Strategy)45786_storage)" }, { - "astId": 42996, + "astId": 45796, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "allStrategies", "offset": 0, @@ -1866,7 +1869,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 42999, + "astId": 45799, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "_deprecated_priceProvider", "offset": 0, @@ -1874,7 +1877,7 @@ "type": "t_address" }, { - "astId": 43002, + "astId": 45802, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "rebasePaused", "offset": 20, @@ -1882,7 +1885,7 @@ "type": "t_bool" }, { - "astId": 43005, + "astId": 45805, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "capitalPaused", "offset": 21, @@ -1890,7 +1893,7 @@ "type": "t_bool" }, { - "astId": 43008, + "astId": 45808, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "_deprecated_redeemFeeBps", "offset": 0, @@ -1898,7 +1901,7 @@ "type": "t_uint256" }, { - "astId": 43011, + "astId": 45811, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "vaultBuffer", "offset": 0, @@ -1906,7 +1909,7 @@ "type": "t_uint256" }, { - "astId": 43014, + "astId": 45814, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "autoAllocateThreshold", "offset": 0, @@ -1914,23 +1917,23 @@ "type": "t_uint256" }, { - "astId": 43017, + "astId": 45817, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", - "label": "rebaseThreshold", + "label": "__deprecatedRebaseThreshold", "offset": 0, "slot": "59", "type": "t_uint256" }, { - "astId": 43021, + "astId": 45821, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "oToken", "offset": 0, "slot": "60", - "type": "t_contract(OUSD)38551" + "type": "t_contract(OUSD)41354" }, { - "astId": 43028, + "astId": 45828, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "_deprecated_rebaseHooksAddr", "offset": 0, @@ -1938,7 +1941,7 @@ "type": "t_address" }, { - "astId": 43035, + "astId": 45835, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "_deprecated_uniswapAddr", "offset": 0, @@ -1946,7 +1949,7 @@ "type": "t_address" }, { - "astId": 43042, + "astId": 45842, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "strategistAddr", "offset": 0, @@ -1954,7 +1957,7 @@ "type": "t_address" }, { - "astId": 43045, + "astId": 45845, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "_deprecated_assetDefaultStrategies", "offset": 0, @@ -1962,7 +1965,7 @@ "type": "t_uint256" }, { - "astId": 43048, + "astId": 45848, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "maxSupplyDiff", "offset": 0, @@ -1970,7 +1973,7 @@ "type": "t_uint256" }, { - "astId": 43051, + "astId": 45851, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "trusteeAddress", "offset": 0, @@ -1978,7 +1981,7 @@ "type": "t_address" }, { - "astId": 43054, + "astId": 45854, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "trusteeFeeBps", "offset": 0, @@ -1986,7 +1989,7 @@ "type": "t_uint256" }, { - "astId": 43058, + "astId": 45858, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "_deprecated_swapTokens", "offset": 0, @@ -1994,7 +1997,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 43061, + "astId": 45861, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "_deprecated_ousdMetaStrategy", "offset": 0, @@ -2002,7 +2005,7 @@ "type": "t_address" }, { - "astId": 43064, + "astId": 45864, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "_deprecated_netOusdMintedForStrategy", "offset": 0, @@ -2010,7 +2013,7 @@ "type": "t_int256" }, { - "astId": 43067, + "astId": 45867, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "_deprecated_netOusdMintForStrategyThreshold", "offset": 0, @@ -2018,7 +2021,7 @@ "type": "t_uint256" }, { - "astId": 43069, + "astId": 45869, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "_deprecated_swapConfig", "offset": 0, @@ -2026,7 +2029,7 @@ "type": "t_uint256" }, { - "astId": 43073, + "astId": 45873, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "isMintWhitelistedStrategy", "offset": 0, @@ -2034,7 +2037,7 @@ "type": "t_mapping(t_address,t_bool)" }, { - "astId": 43076, + "astId": 45876, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "_deprecated_dripper", "offset": 0, @@ -2042,23 +2045,23 @@ "type": "t_address" }, { - "astId": 43090, + "astId": 45890, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "withdrawalQueueMetadata", "offset": 0, "slot": "75", - "type": "t_struct(WithdrawalQueueMetadata)43086_storage" + "type": "t_struct(WithdrawalQueueMetadata)45886_storage" }, { - "astId": 43107, + "astId": 45907, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "withdrawalRequests", "offset": 0, "slot": "77", - "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)43101_storage)" + "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)45901_storage)" }, { - "astId": 43110, + "astId": 45910, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "withdrawalClaimDelay", "offset": 0, @@ -2066,7 +2069,7 @@ "type": "t_uint256" }, { - "astId": 43113, + "astId": 45913, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "lastRebase", "offset": 0, @@ -2074,7 +2077,7 @@ "type": "t_uint64" }, { - "astId": 43116, + "astId": 45916, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "dripDuration", "offset": 8, @@ -2082,7 +2085,7 @@ "type": "t_uint64" }, { - "astId": 43119, + "astId": 45919, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "rebasePerSecondMax", "offset": 16, @@ -2090,7 +2093,7 @@ "type": "t_uint64" }, { - "astId": 43122, + "astId": 45922, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "rebasePerSecondTarget", "offset": 24, @@ -2098,7 +2101,7 @@ "type": "t_uint64" }, { - "astId": 43136, + "astId": 45936, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "defaultStrategy", "offset": 0, @@ -2106,15 +2109,23 @@ "type": "t_address" }, { - "astId": 43140, + "astId": 45939, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", - "label": "__gap", + "label": "operatorAddr", "offset": 0, "slot": "81", - "type": "t_array(t_uint256)42_storage" + "type": "t_address" + }, + { + "astId": 45943, + "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", + "label": "__gap", + "offset": 0, + "slot": "82", + "type": "t_array(t_uint256)41_storage" }, { - "astId": 43143, + "astId": 45946, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "_deprecated_wethAssetIndex", "offset": 0, @@ -2134,11 +2145,11 @@ "label": "address[]", "numberOfBytes": "32" }, - "t_array(t_uint256)42_storage": { + "t_array(t_uint256)41_storage": { "base": "t_uint256", "encoding": "inplace", - "label": "uint256[42]", - "numberOfBytes": "1344" + "label": "uint256[41]", + "numberOfBytes": "1312" }, "t_array(t_uint256)50_storage": { "base": "t_uint256", @@ -2151,7 +2162,7 @@ "label": "bool", "numberOfBytes": "1" }, - "t_contract(OUSD)38551": { + "t_contract(OUSD)41354": { "encoding": "inplace", "label": "contract OUSD", "numberOfBytes": "20" @@ -2168,26 +2179,26 @@ "numberOfBytes": "32", "value": "t_bool" }, - "t_mapping(t_address,t_struct(Strategy)42986_storage)": { + "t_mapping(t_address,t_struct(Strategy)45786_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct VaultStorage.Strategy)", "numberOfBytes": "32", - "value": "t_struct(Strategy)42986_storage" + "value": "t_struct(Strategy)45786_storage" }, - "t_mapping(t_uint256,t_struct(WithdrawalRequest)43101_storage)": { + "t_mapping(t_uint256,t_struct(WithdrawalRequest)45901_storage)": { "encoding": "mapping", "key": "t_uint256", "label": "mapping(uint256 => struct VaultStorage.WithdrawalRequest)", "numberOfBytes": "32", - "value": "t_struct(WithdrawalRequest)43101_storage" + "value": "t_struct(WithdrawalRequest)45901_storage" }, - "t_struct(Strategy)42986_storage": { + "t_struct(Strategy)45786_storage": { "encoding": "inplace", "label": "struct VaultStorage.Strategy", "members": [ { - "astId": 42983, + "astId": 45783, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "isSupported", "offset": 0, @@ -2195,7 +2206,7 @@ "type": "t_bool" }, { - "astId": 42985, + "astId": 45785, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "_deprecated", "offset": 0, @@ -2205,12 +2216,12 @@ ], "numberOfBytes": "64" }, - "t_struct(WithdrawalQueueMetadata)43086_storage": { + "t_struct(WithdrawalQueueMetadata)45886_storage": { "encoding": "inplace", "label": "struct VaultStorage.WithdrawalQueueMetadata", "members": [ { - "astId": 43079, + "astId": 45879, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "queued", "offset": 0, @@ -2218,7 +2229,7 @@ "type": "t_uint128" }, { - "astId": 43081, + "astId": 45881, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "claimable", "offset": 16, @@ -2226,7 +2237,7 @@ "type": "t_uint128" }, { - "astId": 43083, + "astId": 45883, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "claimed", "offset": 0, @@ -2234,7 +2245,7 @@ "type": "t_uint128" }, { - "astId": 43085, + "astId": 45885, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "nextWithdrawalIndex", "offset": 16, @@ -2244,12 +2255,12 @@ ], "numberOfBytes": "64" }, - "t_struct(WithdrawalRequest)43101_storage": { + "t_struct(WithdrawalRequest)45901_storage": { "encoding": "inplace", "label": "struct VaultStorage.WithdrawalRequest", "members": [ { - "astId": 43092, + "astId": 45892, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "withdrawer", "offset": 0, @@ -2257,7 +2268,7 @@ "type": "t_address" }, { - "astId": 43094, + "astId": 45894, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "claimed", "offset": 20, @@ -2265,7 +2276,7 @@ "type": "t_bool" }, { - "astId": 43096, + "astId": 45896, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "timestamp", "offset": 21, @@ -2273,7 +2284,7 @@ "type": "t_uint40" }, { - "astId": 43098, + "astId": 45898, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "amount", "offset": 0, @@ -2281,7 +2292,7 @@ "type": "t_uint128" }, { - "astId": 43100, + "astId": 45900, "contract": "contracts/vault/OETHBaseVault.sol:OETHBaseVault", "label": "queued", "offset": 16, diff --git a/contracts/deployments/base/operations/050_vault_permissioned_rebase.execute.json b/contracts/deployments/base/operations/050_vault_permissioned_rebase.execute.json new file mode 100644 index 0000000000..fddd8556c2 --- /dev/null +++ b/contracts/deployments/base/operations/050_vault_permissioned_rebase.execute.json @@ -0,0 +1,52 @@ +{ + "version": "1.0", + "chainId": "8453", + "createdAt": 1778496613, + "meta": { + "name": "Transaction Batch", + "description": "", + "txBuilderVersion": "1.16.1", + "createdFromSafeAddress": "0x92A19381444A001d62cE67BaFF066fA1111d7202", + "createdFromOwnerAddress": "" + }, + "transactions": [ + { + "to": "0xf817cb3092179083c48c014688D98B72fB61464f", + "value": "0", + "data": null, + "contractMethod": { + "inputs": [ + { + "type": "address[]", + "name": "targets" + }, + { + "type": "uint256[]", + "name": "values" + }, + { + "type": "bytes[]", + "name": "payloads" + }, + { + "type": "bytes32", + "name": "predecessor" + }, + { + "type": "bytes32", + "name": "salt" + } + ], + "name": "executeBatch", + "payable": true + }, + "contractInputsValues": { + "targets": "[\"0x98a0CbeF61bD2D21435f433bE4CD42B56B38CC93\",\"0x98a0CbeF61bD2D21435f433bE4CD42B56B38CC93\"]", + "values": "[\"0\",\"0\"]", + "payloads": "[\"0x3659cfe6000000000000000000000000fdbe6a80e1d22ff652cbff44fead2e52287393e8\",\"0x9e4285520000000000000000000000000abcda6fa7d500cf69b0ea5de9a607cd9941221c\"]", + "predecessor": "0x0000000000000000000000000000000000000000000000000000000000000000", + "salt": "0x0bd702311b1c2059690ab3de76df60f5a16fea5d0904e96a749666ef2d98e866" + } + } + ] +} \ No newline at end of file diff --git a/contracts/deployments/base/operations/050_vault_permissioned_rebase.schedule.json b/contracts/deployments/base/operations/050_vault_permissioned_rebase.schedule.json new file mode 100644 index 0000000000..92f10cef5f --- /dev/null +++ b/contracts/deployments/base/operations/050_vault_permissioned_rebase.schedule.json @@ -0,0 +1,57 @@ +{ + "version": "1.0", + "chainId": "8453", + "createdAt": 1778496613, + "meta": { + "name": "Transaction Batch", + "description": "", + "txBuilderVersion": "1.16.1", + "createdFromSafeAddress": "0x92A19381444A001d62cE67BaFF066fA1111d7202", + "createdFromOwnerAddress": "" + }, + "transactions": [ + { + "to": "0xf817cb3092179083c48c014688D98B72fB61464f", + "value": "0", + "data": null, + "contractMethod": { + "inputs": [ + { + "type": "address[]", + "name": "targets" + }, + { + "type": "uint256[]", + "name": "values" + }, + { + "type": "bytes[]", + "name": "payloads" + }, + { + "type": "bytes32", + "name": "predecessor" + }, + { + "type": "bytes32", + "name": "salt" + }, + { + "type": "uint256", + "name": "delay" + } + ], + "name": "scheduleBatch", + "payable": false + }, + "contractInputsValues": { + "targets": "[\"0x98a0CbeF61bD2D21435f433bE4CD42B56B38CC93\",\"0x98a0CbeF61bD2D21435f433bE4CD42B56B38CC93\"]", + "values": "[\"0\",\"0\"]", + "payloads": "[\"0x3659cfe6000000000000000000000000fdbe6a80e1d22ff652cbff44fead2e52287393e8\",\"0x9e4285520000000000000000000000000abcda6fa7d500cf69b0ea5de9a607cd9941221c\"]", + "predecessor": "0x0000000000000000000000000000000000000000000000000000000000000000", + "salt": "0x0bd702311b1c2059690ab3de76df60f5a16fea5d0904e96a749666ef2d98e866", + "delay": "172800" + } + } + ] +} \ No newline at end of file diff --git a/contracts/deployments/base/solcInputs/f4384e86fd2a870879603d18d53c5b16.json b/contracts/deployments/base/solcInputs/f4384e86fd2a870879603d18d53c5b16.json new file mode 100644 index 0000000000..0a3f9df551 --- /dev/null +++ b/contracts/deployments/base/solcInputs/f4384e86fd2a870879603d18d53c5b16.json @@ -0,0 +1,537 @@ +{ + "language": "Solidity", + "sources": { + "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {Client} from \"../libraries/Client.sol\";\n\ninterface IRouterClient {\n error UnsupportedDestinationChain(uint64 destChainSelector);\n error InsufficientFeeTokenAmount();\n error InvalidMsgValue();\n\n /// @notice Checks if the given chain ID is supported for sending/receiving.\n /// @param chainSelector The chain to check.\n /// @return supported is true if it is supported, false if not.\n function isChainSupported(uint64 chainSelector) external view returns (bool supported);\n\n /// @notice Gets a list of all supported tokens which can be sent or received\n /// to/from a given chain id.\n /// @param chainSelector The chainSelector.\n /// @return tokens The addresses of all tokens that are supported.\n function getSupportedTokens(uint64 chainSelector) external view returns (address[] memory tokens);\n\n /// @param destinationChainSelector The destination chainSelector\n /// @param message The cross-chain CCIP message including data and/or tokens\n /// @return fee returns execution fee for the message\n /// delivery to destination chain, denominated in the feeToken specified in the message.\n /// @dev Reverts with appropriate reason upon invalid message.\n function getFee(\n uint64 destinationChainSelector,\n Client.EVM2AnyMessage memory message\n ) external view returns (uint256 fee);\n\n /// @notice Request a message to be sent to the destination chain\n /// @param destinationChainSelector The destination chain ID\n /// @param message The cross-chain CCIP message including data and/or tokens\n /// @return messageId The message ID\n /// @dev Note if msg.value is larger than the required fee (from getFee) we accept\n /// the overpayment with no refund.\n /// @dev Reverts with appropriate reason upon invalid message.\n function ccipSend(\n uint64 destinationChainSelector,\n Client.EVM2AnyMessage calldata message\n ) external payable returns (bytes32);\n}\n" + }, + "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// End consumer library.\nlibrary Client {\n /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.\n struct EVMTokenAmount {\n address token; // token address on the local chain.\n uint256 amount; // Amount of tokens.\n }\n\n struct Any2EVMMessage {\n bytes32 messageId; // MessageId corresponding to ccipSend on source.\n uint64 sourceChainSelector; // Source chain selector.\n bytes sender; // abi.decode(sender) if coming from an EVM chain.\n bytes data; // payload sent in original message.\n EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation.\n }\n\n // If extraArgs is empty bytes, the default is 200k gas limit.\n struct EVM2AnyMessage {\n bytes receiver; // abi.encode(receiver address) for dest EVM chains\n bytes data; // Data payload\n EVMTokenAmount[] tokenAmounts; // Token transfers\n address feeToken; // Address of feeToken. address(0) means you will send msg.value.\n bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV1)\n }\n\n // bytes4(keccak256(\"CCIP EVMExtraArgsV1\"));\n bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9;\n struct EVMExtraArgsV1 {\n uint256 gasLimit;\n }\n\n function _argsToBytes(EVMExtraArgsV1 memory extraArgs) internal pure returns (bytes memory bts) {\n return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs);\n }\n}\n" + }, + "@layerzerolabs/lz-evm-messagelib-v2/contracts/libs/ExecutorOptions.sol": { + "content": "// SPDX-License-Identifier: LZBL-1.2\n\npragma solidity ^0.8.20;\n\nimport \"@layerzerolabs/lz-evm-protocol-v2/contracts/libs/CalldataBytesLib.sol\";\n\nlibrary ExecutorOptions {\n using CalldataBytesLib for bytes;\n\n uint8 internal constant WORKER_ID = 1;\n\n uint8 internal constant OPTION_TYPE_LZRECEIVE = 1;\n uint8 internal constant OPTION_TYPE_NATIVE_DROP = 2;\n uint8 internal constant OPTION_TYPE_LZCOMPOSE = 3;\n uint8 internal constant OPTION_TYPE_ORDERED_EXECUTION = 4;\n uint8 internal constant OPTION_TYPE_LZREAD = 5;\n\n error Executor_InvalidLzReceiveOption();\n error Executor_InvalidNativeDropOption();\n error Executor_InvalidLzComposeOption();\n error Executor_InvalidLzReadOption();\n\n /// @dev decode the next executor option from the options starting from the specified cursor\n /// @param _options [executor_id][executor_option][executor_id][executor_option]...\n /// executor_option = [option_size][option_type][option]\n /// option_size = len(option_type) + len(option)\n /// executor_id: uint8, option_size: uint16, option_type: uint8, option: bytes\n /// @param _cursor the cursor to start decoding from\n /// @return optionType the type of the option\n /// @return option the option of the executor\n /// @return cursor the cursor to start decoding the next executor option\n function nextExecutorOption(\n bytes calldata _options,\n uint256 _cursor\n ) internal pure returns (uint8 optionType, bytes calldata option, uint256 cursor) {\n unchecked {\n // skip worker id\n cursor = _cursor + 1;\n\n // read option size\n uint16 size = _options.toU16(cursor);\n cursor += 2;\n\n // read option type\n optionType = _options.toU8(cursor);\n\n // startCursor and endCursor are used to slice the option from _options\n uint256 startCursor = cursor + 1; // skip option type\n uint256 endCursor = cursor + size;\n option = _options[startCursor:endCursor];\n cursor += size;\n }\n }\n\n function decodeLzReceiveOption(bytes calldata _option) internal pure returns (uint128 gas, uint128 value) {\n if (_option.length != 16 && _option.length != 32) revert Executor_InvalidLzReceiveOption();\n gas = _option.toU128(0);\n value = _option.length == 32 ? _option.toU128(16) : 0;\n }\n\n function decodeNativeDropOption(bytes calldata _option) internal pure returns (uint128 amount, bytes32 receiver) {\n if (_option.length != 48) revert Executor_InvalidNativeDropOption();\n amount = _option.toU128(0);\n receiver = _option.toB32(16);\n }\n\n function decodeLzComposeOption(\n bytes calldata _option\n ) internal pure returns (uint16 index, uint128 gas, uint128 value) {\n if (_option.length != 18 && _option.length != 34) revert Executor_InvalidLzComposeOption();\n index = _option.toU16(0);\n gas = _option.toU128(2);\n value = _option.length == 34 ? _option.toU128(18) : 0;\n }\n\n function decodeLzReadOption(\n bytes calldata _option\n ) internal pure returns (uint128 gas, uint32 calldataSize, uint128 value) {\n if (_option.length != 20 && _option.length != 36) revert Executor_InvalidLzReadOption();\n gas = _option.toU128(0);\n calldataSize = _option.toU32(16);\n value = _option.length == 36 ? _option.toU128(20) : 0;\n }\n\n function encodeLzReceiveOption(uint128 _gas, uint128 _value) internal pure returns (bytes memory) {\n return _value == 0 ? abi.encodePacked(_gas) : abi.encodePacked(_gas, _value);\n }\n\n function encodeNativeDropOption(uint128 _amount, bytes32 _receiver) internal pure returns (bytes memory) {\n return abi.encodePacked(_amount, _receiver);\n }\n\n function encodeLzComposeOption(uint16 _index, uint128 _gas, uint128 _value) internal pure returns (bytes memory) {\n return _value == 0 ? abi.encodePacked(_index, _gas) : abi.encodePacked(_index, _gas, _value);\n }\n\n function encodeLzReadOption(\n uint128 _gas,\n uint32 _calldataSize,\n uint128 _value\n ) internal pure returns (bytes memory) {\n return _value == 0 ? abi.encodePacked(_gas, _calldataSize) : abi.encodePacked(_gas, _calldataSize, _value);\n }\n}\n" + }, + "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/libs/DVNOptions.sol": { + "content": "// SPDX-License-Identifier: LZBL-1.2\n\npragma solidity ^0.8.20;\n\nimport { BytesLib } from \"solidity-bytes-utils/contracts/BytesLib.sol\";\n\nimport { BitMap256 } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/BitMaps.sol\";\nimport { CalldataBytesLib } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/libs/CalldataBytesLib.sol\";\n\nlibrary DVNOptions {\n using CalldataBytesLib for bytes;\n using BytesLib for bytes;\n\n uint8 internal constant WORKER_ID = 2;\n uint8 internal constant OPTION_TYPE_PRECRIME = 1;\n\n error DVN_InvalidDVNIdx();\n error DVN_InvalidDVNOptions(uint256 cursor);\n\n /// @dev group dvn options by its idx\n /// @param _options [dvn_id][dvn_option][dvn_id][dvn_option]...\n /// dvn_option = [option_size][dvn_idx][option_type][option]\n /// option_size = len(dvn_idx) + len(option_type) + len(option)\n /// dvn_id: uint8, dvn_idx: uint8, option_size: uint16, option_type: uint8, option: bytes\n /// @return dvnOptions the grouped options, still share the same format of _options\n /// @return dvnIndices the dvn indices\n function groupDVNOptionsByIdx(\n bytes memory _options\n ) internal pure returns (bytes[] memory dvnOptions, uint8[] memory dvnIndices) {\n if (_options.length == 0) return (dvnOptions, dvnIndices);\n\n uint8 numDVNs = getNumDVNs(_options);\n\n // if there is only 1 dvn, we can just return the whole options\n if (numDVNs == 1) {\n dvnOptions = new bytes[](1);\n dvnOptions[0] = _options;\n\n dvnIndices = new uint8[](1);\n dvnIndices[0] = _options.toUint8(3); // dvn idx\n return (dvnOptions, dvnIndices);\n }\n\n // otherwise, we need to group the options by dvn_idx\n dvnIndices = new uint8[](numDVNs);\n dvnOptions = new bytes[](numDVNs);\n unchecked {\n uint256 cursor = 0;\n uint256 start = 0;\n uint8 lastDVNIdx = 255; // 255 is an invalid dvn_idx\n\n while (cursor < _options.length) {\n ++cursor; // skip worker_id\n\n // optionLength asserted in getNumDVNs (skip check)\n uint16 optionLength = _options.toUint16(cursor);\n cursor += 2;\n\n // dvnIdx asserted in getNumDVNs (skip check)\n uint8 dvnIdx = _options.toUint8(cursor);\n\n // dvnIdx must equal to the lastDVNIdx for the first option\n // so it is always skipped in the first option\n // this operation slices out options whenever the scan finds a different lastDVNIdx\n if (lastDVNIdx == 255) {\n lastDVNIdx = dvnIdx;\n } else if (dvnIdx != lastDVNIdx) {\n uint256 len = cursor - start - 3; // 3 is for worker_id and option_length\n bytes memory opt = _options.slice(start, len);\n _insertDVNOptions(dvnOptions, dvnIndices, lastDVNIdx, opt);\n\n // reset the start and lastDVNIdx\n start += len;\n lastDVNIdx = dvnIdx;\n }\n\n cursor += optionLength;\n }\n\n // skip check the cursor here because the cursor is asserted in getNumDVNs\n // if we have reached the end of the options, we need to process the last dvn\n uint256 size = cursor - start;\n bytes memory op = _options.slice(start, size);\n _insertDVNOptions(dvnOptions, dvnIndices, lastDVNIdx, op);\n\n // revert dvnIndices to start from 0\n for (uint8 i = 0; i < numDVNs; ++i) {\n --dvnIndices[i];\n }\n }\n }\n\n function _insertDVNOptions(\n bytes[] memory _dvnOptions,\n uint8[] memory _dvnIndices,\n uint8 _dvnIdx,\n bytes memory _newOptions\n ) internal pure {\n // dvnIdx starts from 0 but default value of dvnIndices is 0,\n // so we tell if the slot is empty by adding 1 to dvnIdx\n if (_dvnIdx == 255) revert DVN_InvalidDVNIdx();\n uint8 dvnIdxAdj = _dvnIdx + 1;\n\n for (uint256 j = 0; j < _dvnIndices.length; ++j) {\n uint8 index = _dvnIndices[j];\n if (dvnIdxAdj == index) {\n _dvnOptions[j] = abi.encodePacked(_dvnOptions[j], _newOptions);\n break;\n } else if (index == 0) {\n // empty slot, that means it is the first time we see this dvn\n _dvnIndices[j] = dvnIdxAdj;\n _dvnOptions[j] = _newOptions;\n break;\n }\n }\n }\n\n /// @dev get the number of unique dvns\n /// @param _options the format is the same as groupDVNOptionsByIdx\n function getNumDVNs(bytes memory _options) internal pure returns (uint8 numDVNs) {\n uint256 cursor = 0;\n BitMap256 bitmap;\n\n // find number of unique dvn_idx\n unchecked {\n while (cursor < _options.length) {\n ++cursor; // skip worker_id\n\n uint16 optionLength = _options.toUint16(cursor);\n cursor += 2;\n if (optionLength < 2) revert DVN_InvalidDVNOptions(cursor); // at least 1 byte for dvn_idx and 1 byte for option_type\n\n uint8 dvnIdx = _options.toUint8(cursor);\n\n // if dvnIdx is not set, increment numDVNs\n // max num of dvns is 255, 255 is an invalid dvn_idx\n // The order of the dvnIdx is not required to be sequential, as enforcing the order may weaken\n // the composability of the options. e.g. if we refrain from enforcing the order, an OApp that has\n // already enforced certain options can append additional options to the end of the enforced\n // ones without restrictions.\n if (dvnIdx == 255) revert DVN_InvalidDVNIdx();\n if (!bitmap.get(dvnIdx)) {\n ++numDVNs;\n bitmap = bitmap.set(dvnIdx);\n }\n\n cursor += optionLength;\n }\n }\n if (cursor != _options.length) revert DVN_InvalidDVNOptions(cursor);\n }\n\n /// @dev decode the next dvn option from _options starting from the specified cursor\n /// @param _options the format is the same as groupDVNOptionsByIdx\n /// @param _cursor the cursor to start decoding\n /// @return optionType the type of the option\n /// @return option the option\n /// @return cursor the cursor to start decoding the next option\n function nextDVNOption(\n bytes calldata _options,\n uint256 _cursor\n ) internal pure returns (uint8 optionType, bytes calldata option, uint256 cursor) {\n unchecked {\n // skip worker id\n cursor = _cursor + 1;\n\n // read option size\n uint16 size = _options.toU16(cursor);\n cursor += 2;\n\n // read option type\n optionType = _options.toU8(cursor + 1); // skip dvn_idx\n\n // startCursor and endCursor are used to slice the option from _options\n uint256 startCursor = cursor + 2; // skip option type and dvn_idx\n uint256 endCursor = cursor + size;\n option = _options[startCursor:endCursor];\n cursor += size;\n }\n }\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\nimport { IMessageLibManager } from \"./IMessageLibManager.sol\";\nimport { IMessagingComposer } from \"./IMessagingComposer.sol\";\nimport { IMessagingChannel } from \"./IMessagingChannel.sol\";\nimport { IMessagingContext } from \"./IMessagingContext.sol\";\n\nstruct MessagingParams {\n uint32 dstEid;\n bytes32 receiver;\n bytes message;\n bytes options;\n bool payInLzToken;\n}\n\nstruct MessagingReceipt {\n bytes32 guid;\n uint64 nonce;\n MessagingFee fee;\n}\n\nstruct MessagingFee {\n uint256 nativeFee;\n uint256 lzTokenFee;\n}\n\nstruct Origin {\n uint32 srcEid;\n bytes32 sender;\n uint64 nonce;\n}\n\ninterface ILayerZeroEndpointV2 is IMessageLibManager, IMessagingComposer, IMessagingChannel, IMessagingContext {\n event PacketSent(bytes encodedPayload, bytes options, address sendLibrary);\n\n event PacketVerified(Origin origin, address receiver, bytes32 payloadHash);\n\n event PacketDelivered(Origin origin, address receiver);\n\n event LzReceiveAlert(\n address indexed receiver,\n address indexed executor,\n Origin origin,\n bytes32 guid,\n uint256 gas,\n uint256 value,\n bytes message,\n bytes extraData,\n bytes reason\n );\n\n event LzTokenSet(address token);\n\n event DelegateSet(address sender, address delegate);\n\n function quote(MessagingParams calldata _params, address _sender) external view returns (MessagingFee memory);\n\n function send(\n MessagingParams calldata _params,\n address _refundAddress\n ) external payable returns (MessagingReceipt memory);\n\n function verify(Origin calldata _origin, address _receiver, bytes32 _payloadHash) external;\n\n function verifiable(Origin calldata _origin, address _receiver) external view returns (bool);\n\n function initializable(Origin calldata _origin, address _receiver) external view returns (bool);\n\n function lzReceive(\n Origin calldata _origin,\n address _receiver,\n bytes32 _guid,\n bytes calldata _message,\n bytes calldata _extraData\n ) external payable;\n\n // oapp can burn messages partially by calling this function with its own business logic if messages are verified in order\n function clear(address _oapp, Origin calldata _origin, bytes32 _guid, bytes calldata _message) external;\n\n function setLzToken(address _lzToken) external;\n\n function lzToken() external view returns (address);\n\n function nativeToken() external view returns (address);\n\n function setDelegate(address _delegate) external;\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLibManager.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\nstruct SetConfigParam {\n uint32 eid;\n uint32 configType;\n bytes config;\n}\n\ninterface IMessageLibManager {\n struct Timeout {\n address lib;\n uint256 expiry;\n }\n\n event LibraryRegistered(address newLib);\n event DefaultSendLibrarySet(uint32 eid, address newLib);\n event DefaultReceiveLibrarySet(uint32 eid, address newLib);\n event DefaultReceiveLibraryTimeoutSet(uint32 eid, address oldLib, uint256 expiry);\n event SendLibrarySet(address sender, uint32 eid, address newLib);\n event ReceiveLibrarySet(address receiver, uint32 eid, address newLib);\n event ReceiveLibraryTimeoutSet(address receiver, uint32 eid, address oldLib, uint256 timeout);\n\n function registerLibrary(address _lib) external;\n\n function isRegisteredLibrary(address _lib) external view returns (bool);\n\n function getRegisteredLibraries() external view returns (address[] memory);\n\n function setDefaultSendLibrary(uint32 _eid, address _newLib) external;\n\n function defaultSendLibrary(uint32 _eid) external view returns (address);\n\n function setDefaultReceiveLibrary(uint32 _eid, address _newLib, uint256 _gracePeriod) external;\n\n function defaultReceiveLibrary(uint32 _eid) external view returns (address);\n\n function setDefaultReceiveLibraryTimeout(uint32 _eid, address _lib, uint256 _expiry) external;\n\n function defaultReceiveLibraryTimeout(uint32 _eid) external view returns (address lib, uint256 expiry);\n\n function isSupportedEid(uint32 _eid) external view returns (bool);\n\n function isValidReceiveLibrary(address _receiver, uint32 _eid, address _lib) external view returns (bool);\n\n /// ------------------- OApp interfaces -------------------\n function setSendLibrary(address _oapp, uint32 _eid, address _newLib) external;\n\n function getSendLibrary(address _sender, uint32 _eid) external view returns (address lib);\n\n function isDefaultSendLibrary(address _sender, uint32 _eid) external view returns (bool);\n\n function setReceiveLibrary(address _oapp, uint32 _eid, address _newLib, uint256 _gracePeriod) external;\n\n function getReceiveLibrary(address _receiver, uint32 _eid) external view returns (address lib, bool isDefault);\n\n function setReceiveLibraryTimeout(address _oapp, uint32 _eid, address _lib, uint256 _expiry) external;\n\n function receiveLibraryTimeout(address _receiver, uint32 _eid) external view returns (address lib, uint256 expiry);\n\n function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external;\n\n function getConfig(\n address _oapp,\n address _lib,\n uint32 _eid,\n uint32 _configType\n ) external view returns (bytes memory config);\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessagingChannel.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\ninterface IMessagingChannel {\n event InboundNonceSkipped(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce);\n event PacketNilified(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash);\n event PacketBurnt(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash);\n\n function eid() external view returns (uint32);\n\n // this is an emergency function if a message cannot be verified for some reasons\n // required to provide _nextNonce to avoid race condition\n function skip(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce) external;\n\n function nilify(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external;\n\n function burn(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external;\n\n function nextGuid(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (bytes32);\n\n function inboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64);\n\n function outboundNonce(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (uint64);\n\n function inboundPayloadHash(\n address _receiver,\n uint32 _srcEid,\n bytes32 _sender,\n uint64 _nonce\n ) external view returns (bytes32);\n\n function lazyInboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64);\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessagingComposer.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\ninterface IMessagingComposer {\n event ComposeSent(address from, address to, bytes32 guid, uint16 index, bytes message);\n event ComposeDelivered(address from, address to, bytes32 guid, uint16 index);\n event LzComposeAlert(\n address indexed from,\n address indexed to,\n address indexed executor,\n bytes32 guid,\n uint16 index,\n uint256 gas,\n uint256 value,\n bytes message,\n bytes extraData,\n bytes reason\n );\n\n function composeQueue(\n address _from,\n address _to,\n bytes32 _guid,\n uint16 _index\n ) external view returns (bytes32 messageHash);\n\n function sendCompose(address _to, bytes32 _guid, uint16 _index, bytes calldata _message) external;\n\n function lzCompose(\n address _from,\n address _to,\n bytes32 _guid,\n uint16 _index,\n bytes calldata _message,\n bytes calldata _extraData\n ) external payable;\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessagingContext.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\ninterface IMessagingContext {\n function isSendingMessage() external view returns (bool);\n\n function getSendContext() external view returns (uint32 dstEid, address sender);\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/CalldataBytesLib.sol": { + "content": "// SPDX-License-Identifier: LZBL-1.2\n\npragma solidity ^0.8.20;\n\nlibrary CalldataBytesLib {\n function toU8(bytes calldata _bytes, uint256 _start) internal pure returns (uint8) {\n return uint8(_bytes[_start]);\n }\n\n function toU16(bytes calldata _bytes, uint256 _start) internal pure returns (uint16) {\n unchecked {\n uint256 end = _start + 2;\n return uint16(bytes2(_bytes[_start:end]));\n }\n }\n\n function toU32(bytes calldata _bytes, uint256 _start) internal pure returns (uint32) {\n unchecked {\n uint256 end = _start + 4;\n return uint32(bytes4(_bytes[_start:end]));\n }\n }\n\n function toU64(bytes calldata _bytes, uint256 _start) internal pure returns (uint64) {\n unchecked {\n uint256 end = _start + 8;\n return uint64(bytes8(_bytes[_start:end]));\n }\n }\n\n function toU128(bytes calldata _bytes, uint256 _start) internal pure returns (uint128) {\n unchecked {\n uint256 end = _start + 16;\n return uint128(bytes16(_bytes[_start:end]));\n }\n }\n\n function toU256(bytes calldata _bytes, uint256 _start) internal pure returns (uint256) {\n unchecked {\n uint256 end = _start + 32;\n return uint256(bytes32(_bytes[_start:end]));\n }\n }\n\n function toAddr(bytes calldata _bytes, uint256 _start) internal pure returns (address) {\n unchecked {\n uint256 end = _start + 20;\n return address(bytes20(_bytes[_start:end]));\n }\n }\n\n function toB32(bytes calldata _bytes, uint256 _start) internal pure returns (bytes32) {\n unchecked {\n uint256 end = _start + 32;\n return bytes32(_bytes[_start:end]);\n }\n }\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/BitMaps.sol": { + "content": "// SPDX-License-Identifier: MIT\n\n// modified from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/structs/BitMaps.sol\npragma solidity ^0.8.20;\n\ntype BitMap256 is uint256;\n\nusing BitMaps for BitMap256 global;\n\nlibrary BitMaps {\n /**\n * @dev Returns whether the bit at `index` is set.\n */\n function get(BitMap256 bitmap, uint8 index) internal pure returns (bool) {\n uint256 mask = 1 << index;\n return BitMap256.unwrap(bitmap) & mask != 0;\n }\n\n /**\n * @dev Sets the bit at `index`.\n */\n function set(BitMap256 bitmap, uint8 index) internal pure returns (BitMap256) {\n uint256 mask = 1 << index;\n return BitMap256.wrap(BitMap256.unwrap(bitmap) | mask);\n }\n}\n" + }, + "@layerzerolabs/oapp-evm/contracts/oapp/interfaces/IOAppCore.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { ILayerZeroEndpointV2 } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol\";\n\n/**\n * @title IOAppCore\n */\ninterface IOAppCore {\n // Custom error messages\n error OnlyPeer(uint32 eid, bytes32 sender);\n error NoPeer(uint32 eid);\n error InvalidEndpointCall();\n error InvalidDelegate();\n\n // Event emitted when a peer (OApp) is set for a corresponding endpoint\n event PeerSet(uint32 eid, bytes32 peer);\n\n /**\n * @notice Retrieves the OApp version information.\n * @return senderVersion The version of the OAppSender.sol contract.\n * @return receiverVersion The version of the OAppReceiver.sol contract.\n */\n function oAppVersion() external view returns (uint64 senderVersion, uint64 receiverVersion);\n\n /**\n * @notice Retrieves the LayerZero endpoint associated with the OApp.\n * @return iEndpoint The LayerZero endpoint as an interface.\n */\n function endpoint() external view returns (ILayerZeroEndpointV2 iEndpoint);\n\n /**\n * @notice Retrieves the peer (OApp) associated with a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @return peer The peer address (OApp instance) associated with the corresponding endpoint.\n */\n function peers(uint32 _eid) external view returns (bytes32 peer);\n\n /**\n * @notice Sets the peer address (OApp instance) for a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @param _peer The address of the peer to be associated with the corresponding endpoint.\n */\n function setPeer(uint32 _eid, bytes32 _peer) external;\n\n /**\n * @notice Sets the delegate address for the OApp Core.\n * @param _delegate The address of the delegate to be set.\n */\n function setDelegate(address _delegate) external;\n}\n" + }, + "@layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { BytesLib } from \"solidity-bytes-utils/contracts/BytesLib.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { ExecutorOptions } from \"@layerzerolabs/lz-evm-messagelib-v2/contracts/libs/ExecutorOptions.sol\";\nimport { DVNOptions } from \"@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/libs/DVNOptions.sol\";\n\n/**\n * @title OptionsBuilder\n * @dev Library for building and encoding various message options.\n */\nlibrary OptionsBuilder {\n using SafeCast for uint256;\n using BytesLib for bytes;\n\n // Constants for options types\n uint16 internal constant TYPE_1 = 1; // legacy options type 1\n uint16 internal constant TYPE_2 = 2; // legacy options type 2\n uint16 internal constant TYPE_3 = 3;\n\n // Custom error message\n error InvalidSize(uint256 max, uint256 actual);\n error InvalidOptionType(uint16 optionType);\n\n // Modifier to ensure only options of type 3 are used\n modifier onlyType3(bytes memory _options) {\n if (_options.toUint16(0) != TYPE_3) revert InvalidOptionType(_options.toUint16(0));\n _;\n }\n\n /**\n * @dev Creates a new options container with type 3.\n * @return options The newly created options container.\n */\n function newOptions() internal pure returns (bytes memory) {\n return abi.encodePacked(TYPE_3);\n }\n\n /**\n * @dev Adds an executor LZ receive option to the existing options.\n * @param _options The existing options container.\n * @param _gas The gasLimit used on the lzReceive() function in the OApp.\n * @param _value The msg.value passed to the lzReceive() function in the OApp.\n * @return options The updated options container.\n *\n * @dev When multiples of this option are added, they are summed by the executor\n * eg. if (_gas: 200k, and _value: 1 ether) AND (_gas: 100k, _value: 0.5 ether) are sent in an option to the LayerZeroEndpoint,\n * that becomes (300k, 1.5 ether) when the message is executed on the remote lzReceive() function.\n */\n function addExecutorLzReceiveOption(\n bytes memory _options,\n uint128 _gas,\n uint128 _value\n ) internal pure onlyType3(_options) returns (bytes memory) {\n bytes memory option = ExecutorOptions.encodeLzReceiveOption(_gas, _value);\n return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZRECEIVE, option);\n }\n\n /**\n * @dev Adds an executor native drop option to the existing options.\n * @param _options The existing options container.\n * @param _amount The amount for the native value that is airdropped to the 'receiver'.\n * @param _receiver The receiver address for the native drop option.\n * @return options The updated options container.\n *\n * @dev When multiples of this option are added, they are summed by the executor on the remote chain.\n */\n function addExecutorNativeDropOption(\n bytes memory _options,\n uint128 _amount,\n bytes32 _receiver\n ) internal pure onlyType3(_options) returns (bytes memory) {\n bytes memory option = ExecutorOptions.encodeNativeDropOption(_amount, _receiver);\n return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_NATIVE_DROP, option);\n }\n\n // /**\n // * @dev Adds an executor native drop option to the existing options.\n // * @param _options The existing options container.\n // * @param _amount The amount for the native value that is airdropped to the 'receiver'.\n // * @param _receiver The receiver address for the native drop option.\n // * @return options The updated options container.\n // *\n // * @dev When multiples of this option are added, they are summed by the executor on the remote chain.\n // */\n function addExecutorLzReadOption(\n bytes memory _options,\n uint128 _gas,\n uint32 _size,\n uint128 _value\n ) internal pure onlyType3(_options) returns (bytes memory) {\n bytes memory option = ExecutorOptions.encodeLzReadOption(_gas, _size, _value);\n return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZREAD, option);\n }\n\n /**\n * @dev Adds an executor LZ compose option to the existing options.\n * @param _options The existing options container.\n * @param _index The index for the lzCompose() function call.\n * @param _gas The gasLimit for the lzCompose() function call.\n * @param _value The msg.value for the lzCompose() function call.\n * @return options The updated options container.\n *\n * @dev When multiples of this option are added, they are summed PER index by the executor on the remote chain.\n * @dev If the OApp sends N lzCompose calls on the remote, you must provide N incremented indexes starting with 0.\n * ie. When your remote OApp composes (N = 3) messages, you must set this option for index 0,1,2\n */\n function addExecutorLzComposeOption(\n bytes memory _options,\n uint16 _index,\n uint128 _gas,\n uint128 _value\n ) internal pure onlyType3(_options) returns (bytes memory) {\n bytes memory option = ExecutorOptions.encodeLzComposeOption(_index, _gas, _value);\n return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZCOMPOSE, option);\n }\n\n /**\n * @dev Adds an executor ordered execution option to the existing options.\n * @param _options The existing options container.\n * @return options The updated options container.\n */\n function addExecutorOrderedExecutionOption(\n bytes memory _options\n ) internal pure onlyType3(_options) returns (bytes memory) {\n return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_ORDERED_EXECUTION, bytes(\"\"));\n }\n\n /**\n * @dev Adds a DVN pre-crime option to the existing options.\n * @param _options The existing options container.\n * @param _dvnIdx The DVN index for the pre-crime option.\n * @return options The updated options container.\n */\n function addDVNPreCrimeOption(\n bytes memory _options,\n uint8 _dvnIdx\n ) internal pure onlyType3(_options) returns (bytes memory) {\n return addDVNOption(_options, _dvnIdx, DVNOptions.OPTION_TYPE_PRECRIME, bytes(\"\"));\n }\n\n /**\n * @dev Adds an executor option to the existing options.\n * @param _options The existing options container.\n * @param _optionType The type of the executor option.\n * @param _option The encoded data for the executor option.\n * @return options The updated options container.\n */\n function addExecutorOption(\n bytes memory _options,\n uint8 _optionType,\n bytes memory _option\n ) internal pure onlyType3(_options) returns (bytes memory) {\n return\n abi.encodePacked(\n _options,\n ExecutorOptions.WORKER_ID,\n _option.length.toUint16() + 1, // +1 for optionType\n _optionType,\n _option\n );\n }\n\n /**\n * @dev Adds a DVN option to the existing options.\n * @param _options The existing options container.\n * @param _dvnIdx The DVN index for the DVN option.\n * @param _optionType The type of the DVN option.\n * @param _option The encoded data for the DVN option.\n * @return options The updated options container.\n */\n function addDVNOption(\n bytes memory _options,\n uint8 _dvnIdx,\n uint8 _optionType,\n bytes memory _option\n ) internal pure onlyType3(_options) returns (bytes memory) {\n return\n abi.encodePacked(\n _options,\n DVNOptions.WORKER_ID,\n _option.length.toUint16() + 2, // +2 for optionType and dvnIdx\n _dvnIdx,\n _optionType,\n _option\n );\n }\n\n /**\n * @dev Encodes legacy options of type 1.\n * @param _executionGas The gasLimit value passed to lzReceive().\n * @return legacyOptions The encoded legacy options.\n */\n function encodeLegacyOptionsType1(uint256 _executionGas) internal pure returns (bytes memory) {\n if (_executionGas > type(uint128).max) revert InvalidSize(type(uint128).max, _executionGas);\n return abi.encodePacked(TYPE_1, _executionGas);\n }\n\n /**\n * @dev Encodes legacy options of type 2.\n * @param _executionGas The gasLimit value passed to lzReceive().\n * @param _nativeForDst The amount of native air dropped to the receiver.\n * @param _receiver The _nativeForDst receiver address.\n * @return legacyOptions The encoded legacy options of type 2.\n */\n function encodeLegacyOptionsType2(\n uint256 _executionGas,\n uint256 _nativeForDst,\n bytes memory _receiver // @dev Use bytes instead of bytes32 in legacy type 2 for _receiver.\n ) internal pure returns (bytes memory) {\n if (_executionGas > type(uint128).max) revert InvalidSize(type(uint128).max, _executionGas);\n if (_nativeForDst > type(uint128).max) revert InvalidSize(type(uint128).max, _nativeForDst);\n if (_receiver.length > 32) revert InvalidSize(32, _receiver.length);\n return abi.encodePacked(TYPE_2, _executionGas, _nativeForDst, _receiver);\n }\n}\n" + }, + "@layerzerolabs/oapp-evm/contracts/oapp/OAppCore.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { IOAppCore, ILayerZeroEndpointV2 } from \"./interfaces/IOAppCore.sol\";\n\n/**\n * @title OAppCore\n * @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations.\n */\nabstract contract OAppCore is IOAppCore, Ownable {\n // The LayerZero endpoint associated with the given OApp\n ILayerZeroEndpointV2 public immutable endpoint;\n\n // Mapping to store peers associated with corresponding endpoints\n mapping(uint32 eid => bytes32 peer) public peers;\n\n /**\n * @dev Constructor to initialize the OAppCore with the provided endpoint and delegate.\n * @param _endpoint The address of the LOCAL Layer Zero endpoint.\n * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.\n *\n * @dev The delegate typically should be set as the owner of the contract.\n */\n constructor(address _endpoint, address _delegate) {\n endpoint = ILayerZeroEndpointV2(_endpoint);\n\n if (_delegate == address(0)) revert InvalidDelegate();\n endpoint.setDelegate(_delegate);\n }\n\n /**\n * @notice Sets the peer address (OApp instance) for a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @param _peer The address of the peer to be associated with the corresponding endpoint.\n *\n * @dev Only the owner/admin of the OApp can call this function.\n * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.\n * @dev Set this to bytes32(0) to remove the peer address.\n * @dev Peer is a bytes32 to accommodate non-evm chains.\n */\n function setPeer(uint32 _eid, bytes32 _peer) public virtual onlyOwner {\n _setPeer(_eid, _peer);\n }\n\n /**\n * @notice Sets the peer address (OApp instance) for a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @param _peer The address of the peer to be associated with the corresponding endpoint.\n *\n * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.\n * @dev Set this to bytes32(0) to remove the peer address.\n * @dev Peer is a bytes32 to accommodate non-evm chains.\n */\n function _setPeer(uint32 _eid, bytes32 _peer) internal virtual {\n peers[_eid] = _peer;\n emit PeerSet(_eid, _peer);\n }\n\n /**\n * @notice Internal function to get the peer address associated with a specific endpoint; reverts if NOT set.\n * ie. the peer is set to bytes32(0).\n * @param _eid The endpoint ID.\n * @return peer The address of the peer associated with the specified endpoint.\n */\n function _getPeerOrRevert(uint32 _eid) internal view virtual returns (bytes32) {\n bytes32 peer = peers[_eid];\n if (peer == bytes32(0)) revert NoPeer(_eid);\n return peer;\n }\n\n /**\n * @notice Sets the delegate address for the OApp.\n * @param _delegate The address of the delegate to be set.\n *\n * @dev Only the owner/admin of the OApp can call this function.\n * @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract.\n */\n function setDelegate(address _delegate) public onlyOwner {\n endpoint.setDelegate(_delegate);\n }\n}\n" + }, + "@layerzerolabs/oapp-evm/contracts/oapp/OAppSender.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { SafeERC20, IERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { MessagingParams, MessagingFee, MessagingReceipt } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol\";\nimport { OAppCore } from \"./OAppCore.sol\";\n\n/**\n * @title OAppSender\n * @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint.\n */\nabstract contract OAppSender is OAppCore {\n using SafeERC20 for IERC20;\n\n // Custom error messages\n error NotEnoughNative(uint256 msgValue);\n error LzTokenUnavailable();\n\n // @dev The version of the OAppSender implementation.\n // @dev Version is bumped when changes are made to this contract.\n uint64 internal constant SENDER_VERSION = 1;\n\n /**\n * @notice Retrieves the OApp version information.\n * @return senderVersion The version of the OAppSender.sol contract.\n * @return receiverVersion The version of the OAppReceiver.sol contract.\n *\n * @dev Providing 0 as the default for OAppReceiver version. Indicates that the OAppReceiver is not implemented.\n * ie. this is a SEND only OApp.\n * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions\n */\n function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {\n return (SENDER_VERSION, 0);\n }\n\n /**\n * @dev Internal function to interact with the LayerZero EndpointV2.quote() for fee calculation.\n * @param _dstEid The destination endpoint ID.\n * @param _message The message payload.\n * @param _options Additional options for the message.\n * @param _payInLzToken Flag indicating whether to pay the fee in LZ tokens.\n * @return fee The calculated MessagingFee for the message.\n * - nativeFee: The native fee for the message.\n * - lzTokenFee: The LZ token fee for the message.\n */\n function _quote(\n uint32 _dstEid,\n bytes memory _message,\n bytes memory _options,\n bool _payInLzToken\n ) internal view virtual returns (MessagingFee memory fee) {\n return\n endpoint.quote(\n MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _payInLzToken),\n address(this)\n );\n }\n\n /**\n * @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message.\n * @param _dstEid The destination endpoint ID.\n * @param _message The message payload.\n * @param _options Additional options for the message.\n * @param _fee The calculated LayerZero fee for the message.\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n * @param _refundAddress The address to receive any excess fee values sent to the endpoint.\n * @return receipt The receipt for the sent message.\n * - guid: The unique identifier for the sent message.\n * - nonce: The nonce of the sent message.\n * - fee: The LayerZero fee incurred for the message.\n */\n function _lzSend(\n uint32 _dstEid,\n bytes memory _message,\n bytes memory _options,\n MessagingFee memory _fee,\n address _refundAddress\n ) internal virtual returns (MessagingReceipt memory receipt) {\n // @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint.\n uint256 messageValue = _payNative(_fee.nativeFee);\n if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee);\n\n return\n // solhint-disable-next-line check-send-result\n endpoint.send{ value: messageValue }(\n MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0),\n _refundAddress\n );\n }\n\n /**\n * @dev Internal function to pay the native fee associated with the message.\n * @param _nativeFee The native fee to be paid.\n * @return nativeFee The amount of native currency paid.\n *\n * @dev If the OApp needs to initiate MULTIPLE LayerZero messages in a single transaction,\n * this will need to be overridden because msg.value would contain multiple lzFees.\n * @dev Should be overridden in the event the LayerZero endpoint requires a different native currency.\n * @dev Some EVMs use an ERC20 as a method for paying transactions/gasFees.\n * @dev The endpoint is EITHER/OR, ie. it will NOT support both types of native payment at a time.\n */\n function _payNative(uint256 _nativeFee) internal virtual returns (uint256 nativeFee) {\n if (msg.value != _nativeFee) revert NotEnoughNative(msg.value);\n return _nativeFee;\n }\n\n /**\n * @dev Internal function to pay the LZ token fee associated with the message.\n * @param _lzTokenFee The LZ token fee to be paid.\n *\n * @dev If the caller is trying to pay in the specified lzToken, then the lzTokenFee is passed to the endpoint.\n * @dev Any excess sent, is passed back to the specified _refundAddress in the _lzSend().\n */\n function _payLzToken(uint256 _lzTokenFee) internal virtual {\n // @dev Cannot cache the token because it is not immutable in the endpoint.\n address lzToken = endpoint.lzToken();\n if (lzToken == address(0)) revert LzTokenUnavailable();\n\n // Pay LZ token fee by sending tokens to the endpoint.\n IERC20(lzToken).safeTransferFrom(msg.sender, address(endpoint), _lzTokenFee);\n }\n}\n" + }, + "@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { MessagingReceipt, MessagingFee } from \"@layerzerolabs/oapp-evm/contracts/oapp/OAppSender.sol\";\n\n/**\n * @dev Struct representing token parameters for the OFT send() operation.\n */\nstruct SendParam {\n uint32 dstEid; // Destination endpoint ID.\n bytes32 to; // Recipient address.\n uint256 amountLD; // Amount to send in local decimals.\n uint256 minAmountLD; // Minimum amount to send in local decimals.\n bytes extraOptions; // Additional options supplied by the caller to be used in the LayerZero message.\n bytes composeMsg; // The composed message for the send() operation.\n bytes oftCmd; // The OFT command to be executed, unused in default OFT implementations.\n}\n\n/**\n * @dev Struct representing OFT limit information.\n * @dev These amounts can change dynamically and are up the specific oft implementation.\n */\nstruct OFTLimit {\n uint256 minAmountLD; // Minimum amount in local decimals that can be sent to the recipient.\n uint256 maxAmountLD; // Maximum amount in local decimals that can be sent to the recipient.\n}\n\n/**\n * @dev Struct representing OFT receipt information.\n */\nstruct OFTReceipt {\n uint256 amountSentLD; // Amount of tokens ACTUALLY debited from the sender in local decimals.\n // @dev In non-default implementations, the amountReceivedLD COULD differ from this value.\n uint256 amountReceivedLD; // Amount of tokens to be received on the remote side.\n}\n\n/**\n * @dev Struct representing OFT fee details.\n * @dev Future proof mechanism to provide a standardized way to communicate fees to things like a UI.\n */\nstruct OFTFeeDetail {\n int256 feeAmountLD; // Amount of the fee in local decimals.\n string description; // Description of the fee.\n}\n\n/**\n * @title IOFT\n * @dev Interface for the OftChain (OFT) token.\n * @dev Does not inherit ERC20 to accommodate usage by OFTAdapter as well.\n * @dev This specific interface ID is '0x02e49c2c'.\n */\ninterface IOFT {\n // Custom error messages\n error InvalidLocalDecimals();\n error SlippageExceeded(uint256 amountLD, uint256 minAmountLD);\n\n // Events\n event OFTSent(\n bytes32 indexed guid, // GUID of the OFT message.\n uint32 dstEid, // Destination Endpoint ID.\n address indexed fromAddress, // Address of the sender on the src chain.\n uint256 amountSentLD, // Amount of tokens sent in local decimals.\n uint256 amountReceivedLD // Amount of tokens received in local decimals.\n );\n event OFTReceived(\n bytes32 indexed guid, // GUID of the OFT message.\n uint32 srcEid, // Source Endpoint ID.\n address indexed toAddress, // Address of the recipient on the dst chain.\n uint256 amountReceivedLD // Amount of tokens received in local decimals.\n );\n\n /**\n * @notice Retrieves interfaceID and the version of the OFT.\n * @return interfaceId The interface ID.\n * @return version The version.\n *\n * @dev interfaceId: This specific interface ID is '0x02e49c2c'.\n * @dev version: Indicates a cross-chain compatible msg encoding with other OFTs.\n * @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented.\n * ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1)\n */\n function oftVersion() external view returns (bytes4 interfaceId, uint64 version);\n\n /**\n * @notice Retrieves the address of the token associated with the OFT.\n * @return token The address of the ERC20 token implementation.\n */\n function token() external view returns (address);\n\n /**\n * @notice Indicates whether the OFT contract requires approval of the 'token()' to send.\n * @return requiresApproval Needs approval of the underlying token implementation.\n *\n * @dev Allows things like wallet implementers to determine integration requirements,\n * without understanding the underlying token implementation.\n */\n function approvalRequired() external view returns (bool);\n\n /**\n * @notice Retrieves the shared decimals of the OFT.\n * @return sharedDecimals The shared decimals of the OFT.\n */\n function sharedDecimals() external view returns (uint8);\n\n /**\n * @notice Provides the fee breakdown and settings data for an OFT. Unused in the default implementation.\n * @param _sendParam The parameters for the send operation.\n * @return limit The OFT limit information.\n * @return oftFeeDetails The details of OFT fees.\n * @return receipt The OFT receipt information.\n */\n function quoteOFT(\n SendParam calldata _sendParam\n ) external view returns (OFTLimit memory, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory);\n\n /**\n * @notice Provides a quote for the send() operation.\n * @param _sendParam The parameters for the send() operation.\n * @param _payInLzToken Flag indicating whether the caller is paying in the LZ token.\n * @return fee The calculated LayerZero messaging fee from the send() operation.\n *\n * @dev MessagingFee: LayerZero msg fee\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n */\n function quoteSend(SendParam calldata _sendParam, bool _payInLzToken) external view returns (MessagingFee memory);\n\n /**\n * @notice Executes the send() operation.\n * @param _sendParam The parameters for the send operation.\n * @param _fee The fee information supplied by the caller.\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n * @param _refundAddress The address to receive any excess funds from fees etc. on the src.\n * @return receipt The LayerZero messaging receipt from the send() operation.\n * @return oftReceipt The OFT receipt information.\n *\n * @dev MessagingReceipt: LayerZero msg receipt\n * - guid: The unique identifier for the sent message.\n * - nonce: The nonce of the sent message.\n * - fee: The LayerZero fee incurred for the message.\n */\n function send(\n SendParam calldata _sendParam,\n MessagingFee calldata _fee,\n address _refundAddress\n ) external payable returns (MessagingReceipt memory, OFTReceipt memory);\n}\n" + }, + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role, _msgSender());\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(uint160(account), 20),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/AccessControlEnumerable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/AccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlEnumerable.sol\";\nimport \"./AccessControl.sol\";\nimport \"../utils/structs/EnumerableSet.sol\";\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view override returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view override returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override {\n super._grantRole(role, account);\n _roleMembers[role].add(account);\n }\n\n /**\n * @dev Overload {_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override {\n super._revokeRole(role, account);\n _roleMembers[role].remove(account);\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControlEnumerable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n" + }, + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "@openzeppelin/contracts/security/Pausable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract Pausable is Context {\n /**\n * @dev Emitted when the pause is triggered by `account`.\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by `account`.\n */\n event Unpaused(address account);\n\n bool private _paused;\n\n /**\n * @dev Initializes the contract in unpaused state.\n */\n constructor() {\n _paused = false;\n }\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view virtual returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n modifier whenNotPaused() {\n require(!paused(), \"Pausable: paused\");\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n modifier whenPaused() {\n require(paused(), \"Pausable: not paused\");\n _;\n }\n\n /**\n * @dev Triggers stopped state.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n function _pause() internal virtual whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Returns to normal state.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n function _unpause() internal virtual whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public virtual override returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * Requirements:\n *\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for ``sender``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public virtual override returns (bool) {\n _transfer(sender, recipient, amount);\n\n uint256 currentAllowance = _allowances[sender][_msgSender()];\n require(currentAllowance >= amount, \"ERC20: transfer amount exceeds allowance\");\n unchecked {\n _approve(sender, _msgSender(), currentAllowance - amount);\n }\n\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n uint256 currentAllowance = _allowances[_msgSender()][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(_msgSender(), spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal virtual {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(sender, recipient, amount);\n\n uint256 senderBalance = _balances[sender];\n require(senderBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[sender] = senderBalance - amount;\n }\n _balances[recipient] += amount;\n\n emit Transfer(sender, recipient, amount);\n\n _afterTokenTransfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize, which returns 0 for contracts in\n // construction, since the code is only stored at the end of the\n // constructor execution.\n\n uint256 size;\n assembly {\n size := extcodesize(account)\n }\n return size > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a >= b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a / b + (a % b == 0 ? 0 : 1);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeCast.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n require(value >= 0, \"SafeCast: value must be positive\");\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v3.1._\n */\n function toInt128(int256 value) internal pure returns (int128) {\n require(value >= type(int128).min && value <= type(int128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return int128(value);\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v3.1._\n */\n function toInt64(int256 value) internal pure returns (int64) {\n require(value >= type(int64).min && value <= type(int64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return int64(value);\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v3.1._\n */\n function toInt32(int256 value) internal pure returns (int32) {\n require(value >= type(int32).min && value <= type(int32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return int32(value);\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v3.1._\n */\n function toInt16(int256 value) internal pure returns (int16) {\n require(value >= type(int16).min && value <= type(int16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return int16(value);\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n *\n * _Available since v3.1._\n */\n function toInt8(int256 value) internal pure returns (int8) {\n require(value >= type(int8).min && value <= type(int8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return int8(value);\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n return int256(value);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeMath.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/structs/EnumerableSet.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(bytes32 => uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value's index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (lastIndex != toDeleteIndex) {\n bytes32 lastvalue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastvalue;\n // Update the index for the moved value\n set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n return _values(set._inner);\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n assembly {\n result := store\n }\n\n return result;\n }\n}\n" + }, + "contracts/automation/AbstractCCIPBridgeHelperModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractSafeModule } from \"./AbstractSafeModule.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IRouterClient } from \"@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol\";\nimport { Client } from \"@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol\";\n\nabstract contract AbstractCCIPBridgeHelperModule is AbstractSafeModule {\n /**\n * @notice Bridges a token from the source chain to the destination chain using CCIP\n * @param ccipRouter The CCIP router contract\n * @param destinationChainSelector The selector for the destination chain\n * @param token The token to bridge\n * @param amount The amount of token to bridge\n */\n function _bridgeTokenWithCCIP(\n IRouterClient ccipRouter,\n uint64 destinationChainSelector,\n IERC20 token,\n uint256 amount\n ) internal {\n bool success;\n\n // Approve CCIP Router to move the token\n success = safeContract.execTransactionFromModule(\n address(token),\n 0, // Value\n abi.encodeWithSelector(token.approve.selector, ccipRouter, amount),\n 0 // Call\n );\n require(success, \"Failed to approve token\");\n\n Client.EVMTokenAmount[]\n memory tokenAmounts = new Client.EVMTokenAmount[](1);\n Client.EVMTokenAmount memory tokenAmount = Client.EVMTokenAmount({\n token: address(token),\n amount: amount\n });\n tokenAmounts[0] = tokenAmount;\n\n Client.EVM2AnyMessage memory ccipMessage = Client.EVM2AnyMessage({\n receiver: abi.encode(address(safeContract)), // ABI-encoded receiver address\n data: abi.encode(\"\"),\n tokenAmounts: tokenAmounts,\n extraArgs: Client._argsToBytes(\n Client.EVMExtraArgsV1({ gasLimit: 0 })\n ),\n feeToken: address(0)\n });\n\n // Get CCIP fee\n uint256 ccipFee = ccipRouter.getFee(\n destinationChainSelector,\n ccipMessage\n );\n\n // Send CCIP message\n success = safeContract.execTransactionFromModule(\n address(ccipRouter),\n ccipFee, // Value\n abi.encodeWithSelector(\n ccipRouter.ccipSend.selector,\n destinationChainSelector,\n ccipMessage\n ),\n 0 // Call\n );\n require(success, \"Failed to send CCIP message\");\n }\n}\n" + }, + "contracts/automation/AbstractLZBridgeHelperModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractSafeModule } from \"./AbstractSafeModule.sol\";\n\nimport { IOFT, SendParam } from \"@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol\";\nimport { MessagingFee } from \"@layerzerolabs/oapp-evm/contracts/oapp/OAppSender.sol\";\nimport { OptionsBuilder } from \"@layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol\";\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nabstract contract AbstractLZBridgeHelperModule is AbstractSafeModule {\n using OptionsBuilder for bytes;\n\n /**\n * @dev Bridges token using LayerZero.\n * @param lzEndpointId LayerZero endpoint id.\n * @param token Token to bridge.\n * @param lzAdapter LZ Adapter to use.\n * @param amount Amount of token to bridge.\n * @param slippageBps Slippage in 10^4 basis points.\n * @param isNativeToken Whether the token is native token.\n */\n function _bridgeTokenWithLz(\n uint32 lzEndpointId,\n IERC20 token,\n IOFT lzAdapter,\n uint256 amount,\n uint256 slippageBps,\n bool isNativeToken\n ) internal {\n bool success;\n\n if (!isNativeToken) {\n // Approve LZ Adapter to move the token\n success = safeContract.execTransactionFromModule(\n address(token),\n 0, // Value\n abi.encodeWithSelector(\n token.approve.selector,\n address(lzAdapter),\n amount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve token\");\n }\n\n // Calculate minimum amount to receive\n uint256 minAmount = (amount * (10000 - slippageBps)) / 10000;\n\n // Hardcoded gaslimit of 400k\n bytes memory options = OptionsBuilder\n .newOptions()\n .addExecutorLzReceiveOption(400000, 0);\n\n // Build send param\n SendParam memory sendParam = SendParam({\n dstEid: lzEndpointId,\n to: bytes32(uint256(uint160(address(safeContract)))),\n amountLD: amount,\n minAmountLD: minAmount,\n extraOptions: options,\n composeMsg: bytes(\"\"),\n oftCmd: bytes(\"\")\n });\n\n // Compute fees\n MessagingFee memory msgFee = lzAdapter.quoteSend(sendParam, false);\n\n uint256 value = isNativeToken\n ? amount + msgFee.nativeFee\n : msgFee.nativeFee;\n\n // Execute transaction\n success = safeContract.execTransactionFromModule(\n address(lzAdapter),\n value,\n abi.encodeWithSelector(\n lzAdapter.send.selector,\n sendParam,\n msgFee,\n address(safeContract)\n ),\n 0\n );\n require(success, \"Failed to bridge token\");\n }\n}\n" + }, + "contracts/automation/AbstractSafeModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AccessControlEnumerable } from \"@openzeppelin/contracts/access/AccessControlEnumerable.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { ISafe } from \"../interfaces/ISafe.sol\";\n\nabstract contract AbstractSafeModule is AccessControlEnumerable {\n ISafe public immutable safeContract;\n\n bytes32 public constant OPERATOR_ROLE = keccak256(\"OPERATOR_ROLE\");\n\n modifier onlySafe() {\n require(\n msg.sender == address(safeContract),\n \"Caller is not the safe contract\"\n );\n _;\n }\n\n modifier onlyOperator() {\n require(\n hasRole(OPERATOR_ROLE, msg.sender),\n \"Caller is not an operator\"\n );\n _;\n }\n\n constructor(address _safeContract) {\n safeContract = ISafe(_safeContract);\n _grantRole(DEFAULT_ADMIN_ROLE, address(safeContract));\n _grantRole(OPERATOR_ROLE, address(safeContract));\n }\n\n /**\n * @dev Helps recovering any tokens accidentally sent to this module.\n * @param token Token to transfer. 0x0 to transfer Native token.\n * @param amount Amount to transfer. 0 to transfer all balance.\n */\n function transferTokens(address token, uint256 amount) external onlySafe {\n if (address(token) == address(0)) {\n // Move ETH\n amount = amount > 0 ? amount : address(this).balance;\n payable(address(safeContract)).transfer(amount);\n return;\n }\n\n // Move all balance if amount set to 0\n amount = amount > 0 ? amount : IERC20(token).balanceOf(address(this));\n\n // Transfer to Safe contract\n // slither-disable-next-line unchecked-transfer unused-return\n IERC20(token).transfer(address(safeContract), amount);\n }\n\n receive() external payable {\n // Accept ETH to pay for bridge fees\n }\n}\n" + }, + "contracts/automation/AutoWithdrawalModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractSafeModule } from \"./AbstractSafeModule.sol\";\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { VaultStorage } from \"../vault/VaultStorage.sol\";\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\n\n/**\n * @title Auto Withdrawal Module\n * @notice A Gnosis Safe module that automates funding the OUSD (or OETH) vault's\n * withdrawal queue by pulling liquidity from a configured strategy.\n *\n * @dev The Safe (Guardian multisig) must:\n * 1. Deploy this module\n * 2. Call `safe.enableModule(address(this))` to authorize it\n *\n * An off-chain operator (e.g. Defender Relayer) calls `fundWithdrawals()`\n * periodically. The module:\n * - First tries to satisfy the queue from idle vault funds\n * - If there's still a shortfall, withdraws the exact shortfall amount\n * from the configured strategy (up to what the strategy holds)\n *\n * The Safe retains full override control via `setStrategy`.\n */\ncontract AutoWithdrawalModule is AbstractSafeModule {\n // ───────────────────────────────────────────────────────── Immutables ──\n\n /// @notice The vault whose withdrawal queue is being funded.\n IVault public immutable vault;\n\n /// @notice The vault's base asset (e.g. USDC for OUSD, WETH for OETH).\n /// Stored as an address to match IStrategy.checkBalance() signature.\n address public immutable asset;\n\n // ────────────────────────────────────────────────────── Mutable config ──\n\n /// @notice The strategy from which liquidity is pulled to fill the queue.\n address public strategy;\n\n // ─────────────────────────────────────────────────────────── Events ──\n\n /// @notice Emitted when liquidity is successfully moved from strategy to vault.\n event LiquidityWithdrawn(\n address indexed strategy,\n uint256 amount,\n uint256 remainingShortfall\n );\n\n /// @notice Emitted when the strategy does not hold enough funds to cover the shortfall.\n /// No withdrawal is attempted; an operator alert should fire on this event.\n event InsufficientStrategyLiquidity(\n address indexed strategy,\n uint256 shortfall,\n uint256 available\n );\n\n /// @notice Emitted when the Safe exec call to withdrawFromStrategy fails.\n event WithdrawalFailed(address indexed strategy, uint256 attemptedAmount);\n\n /// @notice Emitted when the strategy address is updated.\n event StrategyUpdated(address oldStrategy, address newStrategy);\n\n // ─────────────────────────────────────────────────────── Constructor ──\n\n /**\n * @param _safeContract Address of the Gnosis Safe (Guardian multisig).\n * @param _operator Address of the off-chain operator (e.g. Defender relayer).\n * @param _vault Address of the OUSD/OETH vault.\n * @param _strategy Initial strategy to pull liquidity from.\n */\n constructor(\n address _safeContract,\n address _operator,\n address _vault,\n address _strategy\n ) AbstractSafeModule(_safeContract) {\n require(_vault != address(0), \"Invalid vault\");\n require(_strategy != address(0), \"Invalid strategy\");\n\n vault = IVault(_vault);\n asset = IVault(_vault).asset();\n\n _setStrategy(_strategy);\n\n _grantRole(OPERATOR_ROLE, _operator);\n }\n\n // ──────────────────────────────────────────────────── Core automation ──\n\n /**\n * @notice Fund the vault's withdrawal queue from the configured strategy.\n * Called periodically by an off-chain operator (Defender Actions).\n *\n * Steps:\n * 1. Ask the vault to absorb any idle asset it already holds.\n * 2. Compute the remaining shortfall.\n * 3. Pull up to that amount from the strategy via the Safe.\n *\n * This function never reverts on \"soft\" failures (strategy underfunded,\n * Safe exec failure). It emits a descriptive event instead so off-chain\n * monitoring can alert the team without breaking the Defender action.\n */\n function fundWithdrawals() external onlyOperator {\n // Step 1: Let the vault absorb any asset it already holds idle.\n // This is a permissionless call; no Safe exec needed.\n vault.addWithdrawalQueueLiquidity();\n\n // Step 2: Read the current shortfall.\n uint256 shortfall = pendingShortfall();\n\n if (shortfall == 0) {\n // Queue is fully funded — nothing to do.\n return;\n }\n\n // Step 3: Read available balance from the strategy.\n uint256 strategyBalance = IStrategy(strategy).checkBalance(asset);\n\n // Withdraw the lesser of the shortfall and what the strategy holds.\n uint256 toWithdraw = shortfall < strategyBalance\n ? shortfall\n : strategyBalance;\n\n if (toWithdraw == 0) {\n emit InsufficientStrategyLiquidity(\n strategy,\n shortfall,\n strategyBalance\n );\n return;\n }\n\n // Step 4: Execute withdrawal via the Safe (which holds the Strategist role).\n address[] memory assets = new address[](1);\n assets[0] = asset;\n uint256[] memory amounts = new uint256[](1);\n amounts[0] = toWithdraw;\n\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0,\n abi.encodeWithSelector(\n IVault.withdrawFromStrategy.selector,\n strategy,\n assets,\n amounts\n ),\n 0 // Call (not delegatecall)\n );\n\n if (!success) {\n emit WithdrawalFailed(strategy, toWithdraw);\n return;\n }\n\n emit LiquidityWithdrawn(strategy, toWithdraw, shortfall - toWithdraw);\n }\n\n // ─────────────────────────────────────────────────────── Guardian controls ──\n\n /**\n * @notice Change the strategy from which liquidity is pulled.\n * @param _strategy New strategy address. Must not be zero.\n */\n function setStrategy(address _strategy) external onlySafe {\n _setStrategy(_strategy);\n }\n\n function _setStrategy(address _strategy) internal {\n require(_strategy != address(0), \"Invalid strategy\");\n emit StrategyUpdated(strategy, _strategy);\n strategy = _strategy;\n }\n\n // ──────────────────────────────────────────────────────── View helpers ──\n\n /**\n * @notice The current unmet shortfall in the vault's withdrawal queue.\n * @dev This is a raw read of `queued - claimable`. It does NOT account for\n * idle vault asset that `addWithdrawalQueueLiquidity()` would absorb.\n * For a fully up-to-date figure, call `vault.addWithdrawalQueueLiquidity()`\n * first (which is what `fundWithdrawals()` does).\n * @return shortfall Queue shortfall in asset units (vault asset decimals).\n */\n function pendingShortfall() public view returns (uint256 shortfall) {\n VaultStorage.WithdrawalQueueMetadata memory meta = vault\n .withdrawalQueueMetadata();\n shortfall = meta.queued - meta.claimable;\n }\n}\n" + }, + "contracts/automation/BaseBridgeHelperModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// solhint-disable-next-line max-line-length\nimport { AbstractCCIPBridgeHelperModule, AbstractSafeModule, IRouterClient } from \"./AbstractCCIPBridgeHelperModule.sol\";\n\nimport { AccessControlEnumerable } from \"@openzeppelin/contracts/access/AccessControlEnumerable.sol\";\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nimport { BridgedWOETHStrategy } from \"../strategies/BridgedWOETHStrategy.sol\";\n\ncontract BaseBridgeHelperModule is\n AccessControlEnumerable,\n AbstractCCIPBridgeHelperModule\n{\n IVault public constant vault =\n IVault(0x98a0CbeF61bD2D21435f433bE4CD42B56B38CC93);\n IWETH9 public constant weth =\n IWETH9(0x4200000000000000000000000000000000000006);\n IERC20 public constant oethb =\n IERC20(0xDBFeFD2e8460a6Ee4955A68582F85708BAEA60A3);\n IERC4626 public constant bridgedWOETH =\n IERC4626(0xD8724322f44E5c58D7A815F542036fb17DbbF839);\n\n BridgedWOETHStrategy public constant bridgedWOETHStrategy =\n BridgedWOETHStrategy(0x80c864704DD06C3693ed5179190786EE38ACf835);\n\n IRouterClient public constant CCIP_ROUTER =\n IRouterClient(0x881e3A65B4d4a04dD529061dd0071cf975F58bCD);\n\n uint64 public constant CCIP_ETHEREUM_CHAIN_SELECTOR = 5009297550715157269;\n\n constructor(address _safeContract) AbstractSafeModule(_safeContract) {}\n\n /**\n * @dev Bridges wOETH to Ethereum.\n * @param woethAmount Amount of wOETH to bridge.\n */\n function bridgeWOETHToEthereum(uint256 woethAmount)\n public\n payable\n onlyOperator\n {\n _bridgeTokenWithCCIP(\n CCIP_ROUTER,\n CCIP_ETHEREUM_CHAIN_SELECTOR,\n IERC20(address(bridgedWOETH)),\n woethAmount\n );\n }\n\n /**\n * @dev Bridges WETH to Ethereum.\n * @param wethAmount Amount of WETH to bridge.\n */\n function bridgeWETHToEthereum(uint256 wethAmount)\n public\n payable\n onlyOperator\n {\n _bridgeTokenWithCCIP(\n CCIP_ROUTER,\n CCIP_ETHEREUM_CHAIN_SELECTOR,\n IERC20(address(weth)),\n wethAmount\n );\n }\n\n /**\n * @dev Deposits wOETH into the bridgedWOETH strategy.\n * @param woethAmount Amount of wOETH to deposit.\n * @param requestWithdrawal Whether to request an async withdrawal of the\n * resulting OETHb from the Vault.\n * @return requestId The withdrawal request ID (0 if not requested).\n * @return oethbAmount Amount of OETHb received or queued for withdrawal.\n */\n function depositWOETH(uint256 woethAmount, bool requestWithdrawal)\n external\n onlyOperator\n returns (uint256 requestId, uint256 oethbAmount)\n {\n oethbAmount = _depositWOETH(woethAmount);\n if (requestWithdrawal) {\n requestId = _requestWithdrawal(oethbAmount);\n }\n }\n\n /**\n * @dev Claims a previously requested withdrawal and bridges WETH to Ethereum.\n * @param requestId The withdrawal request ID to claim.\n */\n function claimAndBridgeWETH(uint256 requestId)\n external\n payable\n onlyOperator\n {\n uint256 wethAmount = _claimWithdrawal(requestId);\n bridgeWETHToEthereum(wethAmount);\n }\n\n /**\n * @dev Claims a previously requested withdrawal.\n * @param requestId The withdrawal request ID to claim.\n * @return wethAmount Amount of WETH received.\n */\n function claimWithdrawal(uint256 requestId)\n external\n onlyOperator\n returns (uint256 wethAmount)\n {\n return _claimWithdrawal(requestId);\n }\n\n /**\n * @dev Deposits wOETH into the bridgedWOETH strategy.\n * @param woethAmount Amount of wOETH to deposit.\n * @return oethbAmount Amount of OETHb received.\n */\n function _depositWOETH(uint256 woethAmount)\n internal\n returns (uint256 oethbAmount)\n {\n // Update oracle price\n bridgedWOETHStrategy.updateWOETHOraclePrice();\n\n // Rebase to account for any yields from price update\n vault.rebase();\n\n oethbAmount = oethb.balanceOf(address(safeContract));\n\n // Approve bridgedWOETH strategy to move wOETH\n bool success = safeContract.execTransactionFromModule(\n address(bridgedWOETH),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETH.approve.selector,\n address(bridgedWOETHStrategy),\n woethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve wOETH\");\n\n // Deposit to bridgedWOETH strategy\n success = safeContract.execTransactionFromModule(\n address(bridgedWOETHStrategy),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETHStrategy.depositBridgedWOETH.selector,\n woethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to deposit bridged WOETH\");\n\n oethbAmount = oethb.balanceOf(address(safeContract)) - oethbAmount;\n\n // Rebase to account for any yields from price update\n // and backing asset change from deposit\n vault.rebase();\n }\n\n /**\n * @dev Requests an async withdrawal from the Vault.\n * @param oethbAmount Amount of OETHb to withdraw.\n * @return requestId The withdrawal request ID.\n */\n function _requestWithdrawal(uint256 oethbAmount)\n internal\n returns (uint256 requestId)\n {\n // Read the next withdrawal index before requesting\n // (safe because requestWithdrawal is nonReentrant)\n requestId = vault.withdrawalQueueMetadata().nextWithdrawalIndex;\n\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(\n vault.requestWithdrawal.selector,\n oethbAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to request withdrawal\");\n }\n\n /**\n * @dev Claims a previously requested withdrawal from the Vault.\n * @param requestId The withdrawal request ID to claim.\n * @return wethAmount Amount of WETH received.\n */\n function _claimWithdrawal(uint256 requestId)\n internal\n returns (uint256 wethAmount)\n {\n wethAmount = weth.balanceOf(address(safeContract));\n\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(vault.claimWithdrawal.selector, requestId),\n 0 // Call\n );\n require(success, \"Failed to claim withdrawal\");\n\n wethAmount = weth.balanceOf(address(safeContract)) - wethAmount;\n }\n\n /**\n * @dev Deposits WETH into the Vault and redeems wOETH from the bridgedWOETH strategy.\n * @param wethAmount Amount of WETH to deposit.\n * @return Amount of wOETH received.\n */\n function depositWETHAndRedeemWOETH(uint256 wethAmount)\n external\n onlyOperator\n returns (uint256)\n {\n return _withdrawWOETH(wethAmount);\n }\n\n function depositWETHAndBridgeWOETH(uint256 wethAmount)\n external\n onlyOperator\n returns (uint256)\n {\n uint256 woethAmount = _withdrawWOETH(wethAmount);\n bridgeWOETHToEthereum(woethAmount);\n return woethAmount;\n }\n\n /**\n * @dev Withdraws wOETH from the bridgedWOETH strategy.\n * @param wethAmount Amount of WETH to use to withdraw.\n * @return Amount of wOETH received.\n */\n function _withdrawWOETH(uint256 wethAmount) internal returns (uint256) {\n // Approve Vault to move WETH\n bool success = safeContract.execTransactionFromModule(\n address(weth),\n 0, // Value\n abi.encodeWithSelector(\n weth.approve.selector,\n address(vault),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve WETH\");\n\n // Mint OETHb with WETH\n success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(vault.mint.selector, wethAmount),\n 0 // Call\n );\n require(success, \"Failed to mint OETHb\");\n\n // Approve bridgedWOETH strategy to move OETHb\n success = safeContract.execTransactionFromModule(\n address(oethb),\n 0, // Value\n abi.encodeWithSelector(\n oethb.approve.selector,\n address(bridgedWOETHStrategy),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve OETHb\");\n\n uint256 woethAmount = bridgedWOETH.balanceOf(address(safeContract));\n\n // Withdraw from bridgedWOETH strategy\n success = safeContract.execTransactionFromModule(\n address(bridgedWOETHStrategy),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETHStrategy.withdrawBridgedWOETH.selector,\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to withdraw bridged WOETH\");\n\n woethAmount =\n bridgedWOETH.balanceOf(address(safeContract)) -\n woethAmount;\n\n return woethAmount;\n }\n}\n" + }, + "contracts/automation/EthereumBridgeHelperModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// solhint-disable-next-line max-line-length\nimport { AbstractCCIPBridgeHelperModule, AbstractSafeModule, IRouterClient } from \"./AbstractCCIPBridgeHelperModule.sol\";\n\nimport { AccessControlEnumerable } from \"@openzeppelin/contracts/access/AccessControlEnumerable.sol\";\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract EthereumBridgeHelperModule is\n AccessControlEnumerable,\n AbstractCCIPBridgeHelperModule\n{\n IVault public constant vault =\n IVault(0x39254033945AA2E4809Cc2977E7087BEE48bd7Ab);\n IWETH9 public constant weth =\n IWETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);\n IERC20 public constant oeth =\n IERC20(0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3);\n IERC4626 public constant woeth =\n IERC4626(0xDcEe70654261AF21C44c093C300eD3Bb97b78192);\n\n IRouterClient public constant CCIP_ROUTER =\n IRouterClient(0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D);\n\n uint64 public constant CCIP_BASE_CHAIN_SELECTOR = 15971525489660198786;\n\n constructor(address _safeContract) AbstractSafeModule(_safeContract) {}\n\n /**\n * @dev Bridges wOETH to Base using CCIP.\n * @param woethAmount Amount of wOETH to bridge.\n */\n function bridgeWOETHToBase(uint256 woethAmount)\n public\n payable\n onlyOperator\n {\n _bridgeTokenWithCCIP(\n CCIP_ROUTER,\n CCIP_BASE_CHAIN_SELECTOR,\n woeth,\n woethAmount\n );\n }\n\n /**\n * @dev Bridges wETH to Base using CCIP.\n * @param wethAmount Amount of wETH to bridge.\n */\n function bridgeWETHToBase(uint256 wethAmount) public payable onlyOperator {\n _bridgeTokenWithCCIP(\n CCIP_ROUTER,\n CCIP_BASE_CHAIN_SELECTOR,\n IERC20(address(weth)),\n wethAmount\n );\n }\n\n /**\n * @dev Mints OETH and wraps it into wOETH.\n * @param wethAmount Amount of WETH to mint.\n * @param useNativeToken Whether to use native token to mint.\n * @return Amount of wOETH minted.\n */\n function mintAndWrap(uint256 wethAmount, bool useNativeToken)\n external\n onlyOperator\n returns (uint256)\n {\n if (useNativeToken) {\n wrapETH(wethAmount);\n }\n\n return _mintAndWrap(wethAmount);\n }\n\n function wrapETH(uint256 ethAmount) public payable onlyOperator {\n // Deposit ETH into WETH\n safeContract.execTransactionFromModule(\n address(weth),\n ethAmount, // Value\n abi.encodeWithSelector(weth.deposit.selector),\n 0 // Call\n );\n }\n\n /**\n * @dev Mints OETH and wraps it into wOETH.\n * @param wethAmount Amount of WETH to mint.\n * @return Amount of wOETH minted.\n */\n function _mintAndWrap(uint256 wethAmount) internal returns (uint256) {\n // Approve Vault to move WETH\n bool success = safeContract.execTransactionFromModule(\n address(weth),\n 0, // Value\n abi.encodeWithSelector(\n weth.approve.selector,\n address(vault),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve WETH\");\n\n // Mint OETH\n success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(vault.mint.selector, wethAmount),\n 0 // Call\n );\n require(success, \"Failed to mint OETH\");\n\n // Approve wOETH to move OETH\n success = safeContract.execTransactionFromModule(\n address(oeth),\n 0, // Value\n abi.encodeWithSelector(\n oeth.approve.selector,\n address(woeth),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve OETH\");\n\n uint256 woethAmount = woeth.balanceOf(address(safeContract));\n\n // Wrap OETH into wOETH\n success = safeContract.execTransactionFromModule(\n address(woeth),\n 0, // Value\n abi.encodeWithSelector(\n woeth.deposit.selector,\n wethAmount,\n address(safeContract)\n ),\n 0 // Call\n );\n require(success, \"Failed to wrap OETH\");\n\n // Compute amount of wOETH minted\n return woeth.balanceOf(address(safeContract)) - woethAmount;\n }\n\n /**\n * @dev Mints OETH and wraps it into wOETH, then bridges it to Base using CCIP.\n * @param wethAmount Amount of WETH to mint.\n * @param useNativeToken Whether to use native token to mint.\n */\n function mintWrapAndBridgeToBase(uint256 wethAmount, bool useNativeToken)\n external\n payable\n onlyOperator\n {\n if (useNativeToken) {\n wrapETH(wethAmount);\n }\n\n uint256 woethAmount = _mintAndWrap(wethAmount);\n bridgeWOETHToBase(woethAmount);\n }\n\n /**\n * @dev Unwraps wOETH and requests an async withdrawal from the Vault.\n * @param woethAmount Amount of wOETH to unwrap.\n * @return requestId The withdrawal request ID.\n * @return oethAmount Amount of OETH queued for withdrawal.\n */\n function unwrapAndRequestWithdrawal(uint256 woethAmount)\n external\n onlyOperator\n returns (uint256 requestId, uint256 oethAmount)\n {\n return _unwrapAndRequestWithdrawal(woethAmount);\n }\n\n /**\n * @dev Claims a previously requested withdrawal and bridges WETH to Base.\n * @param requestId The withdrawal request ID to claim.\n */\n function claimAndBridgeToBase(uint256 requestId)\n external\n payable\n onlyOperator\n {\n uint256 wethAmount = _claimWithdrawal(requestId);\n bridgeWETHToBase(wethAmount);\n }\n\n /**\n * @dev Claims a previously requested withdrawal.\n * @param requestId The withdrawal request ID to claim.\n * @return wethAmount Amount of WETH received.\n */\n function claimWithdrawal(uint256 requestId)\n external\n onlyOperator\n returns (uint256 wethAmount)\n {\n return _claimWithdrawal(requestId);\n }\n\n /**\n * @dev Unwraps wOETH and requests an async withdrawal from the Vault.\n * @param woethAmount Amount of wOETH to unwrap.\n * @return requestId The withdrawal request ID.\n * @return oethAmount Amount of OETH queued for withdrawal.\n */\n function _unwrapAndRequestWithdrawal(uint256 woethAmount)\n internal\n returns (uint256 requestId, uint256 oethAmount)\n {\n // Read the next withdrawal index before requesting\n // (safe because requestWithdrawal is nonReentrant)\n requestId = vault.withdrawalQueueMetadata().nextWithdrawalIndex;\n\n oethAmount = oeth.balanceOf(address(safeContract));\n\n // Unwrap wOETH\n bool success = safeContract.execTransactionFromModule(\n address(woeth),\n 0, // Value\n abi.encodeWithSelector(\n woeth.redeem.selector,\n woethAmount,\n address(safeContract),\n address(safeContract)\n ),\n 0 // Call\n );\n require(success, \"Failed to unwrap wOETH\");\n\n oethAmount = oeth.balanceOf(address(safeContract)) - oethAmount;\n\n // Request async withdrawal from Vault\n success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(\n vault.requestWithdrawal.selector,\n oethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to request withdrawal\");\n }\n\n /**\n * @dev Claims a previously requested withdrawal from the Vault.\n * @param requestId The withdrawal request ID to claim.\n * @return wethAmount Amount of WETH received.\n */\n function _claimWithdrawal(uint256 requestId)\n internal\n returns (uint256 wethAmount)\n {\n wethAmount = weth.balanceOf(address(safeContract));\n\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(vault.claimWithdrawal.selector, requestId),\n 0 // Call\n );\n require(success, \"Failed to claim withdrawal\");\n\n wethAmount = weth.balanceOf(address(safeContract)) - wethAmount;\n }\n}\n" + }, + "contracts/automation/PlumeBridgeHelperModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractSafeModule } from \"./AbstractSafeModule.sol\";\nimport { AbstractLZBridgeHelperModule } from \"./AbstractLZBridgeHelperModule.sol\";\n\nimport { AccessControlEnumerable } from \"@openzeppelin/contracts/access/AccessControlEnumerable.sol\";\n\nimport { IOFT } from \"@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol\";\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nimport { BridgedWOETHStrategy } from \"../strategies/BridgedWOETHStrategy.sol\";\n\ncontract PlumeBridgeHelperModule is\n AccessControlEnumerable,\n AbstractLZBridgeHelperModule\n{\n IVault public constant vault =\n IVault(0xc8c8F8bEA5631A8AF26440AF32a55002138cB76a);\n IWETH9 public constant weth =\n IWETH9(0xca59cA09E5602fAe8B629DeE83FfA819741f14be);\n IERC20 public constant oethp =\n IERC20(0xFCbe50DbE43bF7E5C88C6F6Fb9ef432D4165406E);\n IERC4626 public constant bridgedWOETH =\n IERC4626(0xD8724322f44E5c58D7A815F542036fb17DbbF839);\n\n uint32 public constant LZ_ETHEREUM_ENDPOINT_ID = 30101;\n IOFT public constant LZ_WOETH_OMNICHAIN_ADAPTER =\n IOFT(0x592CB6A596E7919930bF49a27AdAeCA7C055e4DB);\n IOFT public constant LZ_ETH_OMNICHAIN_ADAPTER =\n IOFT(0x4683CE822272CD66CEa73F5F1f9f5cBcaEF4F066);\n\n BridgedWOETHStrategy public constant bridgedWOETHStrategy =\n BridgedWOETHStrategy(0x1E3EdD5e019207D6355Ea77F724b1F1BF639B569);\n\n constructor(address _safeContract) AbstractSafeModule(_safeContract) {}\n\n /**\n * @dev Bridges wOETH to Ethereum.\n * @param woethAmount Amount of wOETH to bridge.\n * @param slippageBps Slippage in 10^4 basis points.\n */\n function bridgeWOETHToEthereum(uint256 woethAmount, uint256 slippageBps)\n public\n payable\n onlyOperator\n {\n _bridgeTokenWithLz(\n LZ_ETHEREUM_ENDPOINT_ID,\n IERC20(address(bridgedWOETH)),\n LZ_WOETH_OMNICHAIN_ADAPTER,\n woethAmount,\n slippageBps,\n false\n );\n }\n\n /**\n * @dev Bridges wETH to Ethereum.\n * @param wethAmount Amount of wETH to bridge.\n * @param slippageBps Slippage in 10^4 basis points.\n */\n function bridgeWETHToEthereum(uint256 wethAmount, uint256 slippageBps)\n public\n payable\n onlyOperator\n {\n _bridgeTokenWithLz(\n LZ_ETHEREUM_ENDPOINT_ID,\n IERC20(address(weth)),\n LZ_ETH_OMNICHAIN_ADAPTER,\n wethAmount,\n slippageBps,\n false\n );\n }\n\n /**\n * @dev Deposits wOETH into the bridgedWOETH strategy.\n * @param woethAmount Amount of wOETH to deposit.\n * @param redeemWithVault Whether to redeem with Vault.\n * @return Amount of OETHp received.\n */\n function depositWOETH(uint256 woethAmount, bool redeemWithVault)\n external\n onlyOperator\n returns (uint256)\n {\n return _depositWOETH(woethAmount, redeemWithVault);\n }\n\n /**\n * @dev Deposits wOETH into the bridgedWOETH strategy and bridges it to Ethereum.\n * @param woethAmount Amount of wOETH to deposit.\n * @param slippageBps Slippage in 10^4 basis points.\n * @return Amount of WETH received.\n */\n function depositWOETHAndBridgeWETH(uint256 woethAmount, uint256 slippageBps)\n external\n payable\n onlyOperator\n returns (uint256)\n {\n uint256 wethAmount = _depositWOETH(woethAmount, true);\n bridgeWETHToEthereum(wethAmount, slippageBps);\n return wethAmount;\n }\n\n /**\n * @dev Deposits wOETH into the bridgedWOETH strategy.\n * @param woethAmount Amount of wOETH to deposit.\n * @param redeemWithVault Whether to redeem with Vault.\n * @return Amount of OETHp received.\n */\n function _depositWOETH(uint256 woethAmount, bool redeemWithVault)\n internal\n returns (uint256)\n {\n // Update oracle price\n bridgedWOETHStrategy.updateWOETHOraclePrice();\n\n // Rebase to account for any yields from price update\n vault.rebase();\n\n uint256 oethpAmount = oethp.balanceOf(address(safeContract));\n\n // Approve bridgedWOETH strategy to move wOETH\n bool success = safeContract.execTransactionFromModule(\n address(bridgedWOETH),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETH.approve.selector,\n address(bridgedWOETHStrategy),\n woethAmount\n ),\n 0 // Call\n );\n\n // Deposit to bridgedWOETH strategy\n success = safeContract.execTransactionFromModule(\n address(bridgedWOETHStrategy),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETHStrategy.depositBridgedWOETH.selector,\n woethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to deposit bridged WOETH\");\n\n oethpAmount = oethp.balanceOf(address(safeContract)) - oethpAmount;\n\n // Rebase to account for any yields from price update\n // and backing asset change from deposit\n vault.rebase();\n\n if (!redeemWithVault) {\n return oethpAmount;\n }\n\n // Redeem for WETH using Vault\n // redeem(uint256,uint256) was removed from VaultCore; use hardcoded selector\n success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(\n bytes4(keccak256(\"redeem(uint256,uint256)\")),\n oethpAmount,\n oethpAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to redeem OETHp\");\n\n return oethpAmount;\n }\n\n /**\n * @dev Deposits wETH into the vault.\n * @param wethAmount Amount of wETH to deposit.\n * @return Amount of OETHp received.\n */\n function depositWETHAndRedeemWOETH(uint256 wethAmount)\n external\n onlyOperator\n returns (uint256)\n {\n return _withdrawWOETH(wethAmount);\n }\n\n /**\n * @dev Deposits wETH into the vault and bridges it to Ethereum.\n * @param wethAmount Amount of wETH to deposit.\n * @param slippageBps Slippage in 10^4 basis points.\n * @return Amount of WOETH received.\n */\n function depositWETHAndBridgeWOETH(uint256 wethAmount, uint256 slippageBps)\n external\n payable\n onlyOperator\n returns (uint256)\n {\n uint256 woethAmount = _withdrawWOETH(wethAmount);\n bridgeWOETHToEthereum(woethAmount, slippageBps);\n return woethAmount;\n }\n\n /**\n * @dev Withdraws wOETH from the bridgedWOETH strategy.\n * @param wethAmount Amount of WETH to use to withdraw.\n * @return Amount of wOETH received.\n */\n function _withdrawWOETH(uint256 wethAmount) internal returns (uint256) {\n // Approve Vault to move WETH\n bool success = safeContract.execTransactionFromModule(\n address(weth),\n 0, // Value\n abi.encodeWithSelector(\n weth.approve.selector,\n address(vault),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve WETH\");\n\n // Mint OETHp with WETH\n // mint(address,uint256,uint256) was removed from IVault; use hardcoded selector\n success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(\n bytes4(keccak256(\"mint(address,uint256,uint256)\")),\n address(weth),\n wethAmount,\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to mint OETHp\");\n\n // Approve bridgedWOETH strategy to move OETHp\n success = safeContract.execTransactionFromModule(\n address(oethp),\n 0, // Value\n abi.encodeWithSelector(\n oethp.approve.selector,\n address(bridgedWOETHStrategy),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve OETHp\");\n\n uint256 woethAmount = bridgedWOETH.balanceOf(address(safeContract));\n\n // Withdraw from bridgedWOETH strategy\n success = safeContract.execTransactionFromModule(\n address(bridgedWOETHStrategy),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETHStrategy.withdrawBridgedWOETH.selector,\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to withdraw bridged WOETH\");\n\n woethAmount =\n bridgedWOETH.balanceOf(address(safeContract)) -\n woethAmount;\n\n return woethAmount;\n }\n}\n" + }, + "contracts/automation/RebalancerModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractSafeModule } from \"./AbstractSafeModule.sol\";\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { VaultStorage } from \"../vault/VaultStorage.sol\";\n\n/**\n * @title Rebalancer Module\n * @notice A Gnosis Safe module that automates OUSD vault rebalancing by\n * withdrawing from overallocated strategies and depositing to\n * underallocated strategies.\n *\n * @dev The Safe (Guardian multisig) must:\n * 1. Deploy this module\n * 2. Call `safe.enableModule(address(this))` to authorize it\n *\n * An off-chain operator (e.g. Defender Action) calls\n * `processWithdrawalsAndDeposits` periodically with computed strategy/amount\n * arrays. Either array may be empty. All intelligence (APY fetching, target\n * allocation, constraint enforcement) lives off-chain. This contract is a\n * dumb executor.\n *\n * The function uses soft failures: if a single strategy call fails via the\n * Safe, the module emits an event and continues to the next strategy rather\n * than reverting the entire batch.\n *\n * The Safe retains full control via `setPaused`.\n */\ncontract RebalancerModule is AbstractSafeModule {\n // ───────────────────────────────────────────────────────── Immutables ──\n\n /// @notice The vault whose strategies are being rebalanced.\n IVault public immutable vault;\n\n /// @notice The vault's base asset (e.g. USDC for OUSD).\n address public immutable asset;\n\n // ────────────────────────────────────────────────────── Mutable config ──\n\n /// @notice When true, processWithdrawalsAndDeposits is blocked.\n bool public paused;\n\n /// @notice Strategies that this module is permitted to withdraw from or deposit into.\n mapping(address => bool) public isAllowedStrategy;\n\n /// @notice Cumulative amount moved (withdrawals + deposits) per calendar day.\n /// Day key = block.timestamp / 1 days (i.e. days since Unix epoch).\n mapping(uint256 => uint256) public amountMovedPerDay;\n\n /// @notice Max percentage of vault TVL that can be moved in a single day.\n /// In basis points (e.g. 20000 = 200%).\n uint256 public maxDailyMovementBps;\n\n // ─────────────────────────────────────────────────────────── Events ──\n\n /// @notice Emitted after processWithdrawals completes (even if some failed).\n event WithdrawalsProcessed(\n address[] strategies,\n uint256[] amounts,\n uint256 remainingShortfall\n );\n\n /// @notice Emitted after processDeposits completes (even if some failed).\n event DepositsProcessed(address[] strategies, uint256[] amounts);\n\n /// @notice Emitted when a single withdrawFromStrategy call fails via the Safe.\n event WithdrawalFailed(address indexed strategy, uint256 attemptedAmount);\n\n /// @notice Emitted when a single depositToStrategy call fails via the Safe.\n event DepositFailed(address indexed strategy, uint256 attemptedAmount);\n\n /// @notice Emitted when the paused state changes.\n event PausedStateChanged(bool paused);\n\n /// @notice Emitted when a strategy is added to the whitelist.\n event StrategyAllowed(address indexed strategy);\n\n /// @notice Emitted when a strategy is removed from the whitelist.\n event StrategyRevoked(address indexed strategy);\n\n /// @notice Emitted when the daily movement limit is updated.\n event MaxDailyMovementBpsSet(uint256 maxDailyMovementBps);\n\n // ─────────────────────────────────────────────────────── Constructor ──\n\n /**\n * @param _safeContract Address of the Gnosis Safe (Guardian multisig).\n * @param _operator Address of the off-chain operator (e.g. Defender relayer).\n * @param _vault Address of the OUSD vault.\n */\n constructor(\n address _safeContract,\n address _operator,\n address _vault\n ) AbstractSafeModule(_safeContract) {\n require(_vault != address(0), \"Invalid vault\");\n\n vault = IVault(_vault);\n asset = IVault(_vault).asset();\n maxDailyMovementBps = 20000; // 200%\n\n _grantRole(OPERATOR_ROLE, _operator);\n }\n\n // ──────────────────────────────────────────────────────── Modifiers ──\n\n modifier whenNotPaused() {\n require(!paused, \"Module is paused\");\n _;\n }\n\n // ──────────────────────────────────────────────── Core automation ──\n\n // slither-disable-start reentrancy-no-eth\n /**\n * @notice Withdraw from overallocated strategies then deposit to underallocated\n * ones. Either array may be empty — the contract loops over zero entries\n * without reverting.\n *\n * @param _withdrawStrategies Strategies to withdraw from.\n * @param _withdrawAmounts Amounts to withdraw from each strategy.\n * @param _depositStrategies Strategies to deposit into.\n * @param _depositAmounts Amounts to deposit into each strategy.\n */\n function processWithdrawalsAndDeposits(\n address[] calldata _withdrawStrategies,\n uint256[] calldata _withdrawAmounts,\n address[] calldata _depositStrategies,\n uint256[] calldata _depositAmounts\n ) external onlyOperator whenNotPaused {\n require(\n _withdrawStrategies.length == _withdrawAmounts.length,\n \"Withdraw array length mismatch\"\n );\n require(\n _depositStrategies.length == _depositAmounts.length,\n \"Deposit array length mismatch\"\n );\n // This is a permissionless call; no Safe exec needed.\n vault.addWithdrawalQueueLiquidity();\n uint256 _limit = dailyLimit();\n _executeWithdrawals(_withdrawStrategies, _withdrawAmounts, _limit);\n _executeDeposits(_depositStrategies, _depositAmounts, _limit);\n emit WithdrawalsProcessed(\n _withdrawStrategies,\n _withdrawAmounts,\n pendingShortfall()\n );\n emit DepositsProcessed(_depositStrategies, _depositAmounts);\n }\n\n // ─────────────────────────────────────── Guardian controls ──\n\n /**\n * @notice Pause or unpause the module.\n * @param _paused True to pause, false to unpause.\n */\n function setPaused(bool _paused) external onlySafe {\n paused = _paused;\n emit PausedStateChanged(_paused);\n }\n\n /**\n * @notice Add a strategy to the whitelist, allowing the operator to move\n * funds into or out of it.\n * @param _strategy Strategy address to allow.\n */\n function allowStrategy(address _strategy) external onlySafe {\n require(_strategy != address(0), \"Invalid strategy\");\n isAllowedStrategy[_strategy] = true;\n emit StrategyAllowed(_strategy);\n }\n\n /**\n * @notice Remove a strategy from the whitelist.\n * @param _strategy Strategy address to revoke.\n */\n function revokeStrategy(address _strategy) external onlySafe {\n isAllowedStrategy[_strategy] = false;\n emit StrategyRevoked(_strategy);\n }\n\n /**\n * @notice Set the maximum percentage of vault TVL that can be moved per day.\n * @param _maxDailyMovementBps Limit in basis points (e.g. 20000 = 200%).\n * Set to 0 for unlimited daily movement.\n */\n function setMaxDailyMovementBps(uint256 _maxDailyMovementBps)\n external\n onlySafe\n {\n maxDailyMovementBps = _maxDailyMovementBps;\n emit MaxDailyMovementBpsSet(_maxDailyMovementBps);\n }\n\n // ──────────────────────────────────────────────────────── View helpers ──\n\n /**\n * @notice The current unmet shortfall in the vault's withdrawal queue.\n * @dev This is a raw read of `queued - claimable`. It does NOT account for\n * idle vault asset that `addWithdrawalQueueLiquidity()` would absorb.\n * For a fully up-to-date figure, call `vault.addWithdrawalQueueLiquidity()`\n * first (which is what `processWithdrawals` does).\n * @return shortfall Queue shortfall in asset units (vault asset decimals).\n */\n function pendingShortfall() public view returns (uint256 shortfall) {\n VaultStorage.WithdrawalQueueMetadata memory meta = vault\n .withdrawalQueueMetadata();\n shortfall = meta.queued - meta.claimable;\n }\n\n /**\n * @notice The daily movement limit based on current vault TVL.\n * @dev vault.totalValue() includes AMO (Automated Market Operations)\n * value. Excluding AMO would add significant complexity for minimal\n * accuracy gain, so the limit is slightly more generous than intended.\n * Additionally, if the vault's TVL changes significantly mid-day (e.g.\n * large mint/redeem), the limit will reflect the TVL at call time —\n * this is acceptable since the limit is a safety backstop, not a\n * precise cap.\n * If maxDailyMovementBps is set to 0, this returns type(uint256).max\n * as a sentinel value to represent an unlimited cap.\n * @return limit Amount in asset units (vault asset decimals).\n */\n function dailyLimit() public view returns (uint256 limit) {\n if (maxDailyMovementBps == 0) {\n return type(uint256).max;\n }\n limit = (vault.totalValue() * maxDailyMovementBps) / 10000;\n }\n\n /**\n * @notice The remaining amount that can be moved today before hitting the\n * daily movement limit.\n * @return remaining Amount in asset units (vault asset decimals).\n */\n function remainingDailyLimit() public view returns (uint256 remaining) {\n uint256 limit = dailyLimit();\n uint256 used = amountMovedPerDay[block.timestamp / 1 days];\n remaining = used >= limit ? 0 : limit - used;\n }\n\n // ──────────────────────────────────────────────── Internal helpers ──\n\n /// @dev Track cumulative daily movement and revert if the limit is exceeded.\n function _trackMovement(uint256 _amount, uint256 _dailyLimit) internal {\n uint256 dayKey = block.timestamp / 1 days;\n amountMovedPerDay[dayKey] += _amount;\n\n require(\n amountMovedPerDay[dayKey] <= _dailyLimit,\n \"Daily movement limit exceeded\"\n );\n }\n\n /// @dev Execute withdrawFromStrategy for each (strategy, amount) pair via the Safe.\n function _executeWithdrawals(\n address[] calldata _strategies,\n uint256[] calldata _amounts,\n uint256 _dailyLimit\n ) internal {\n address[] memory assets = _toAddressArray(asset);\n for (uint256 i = 0; i < _strategies.length; i++) {\n if (_amounts[i] == 0) continue;\n require(isAllowedStrategy[_strategies[i]], \"Strategy not allowed\");\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0,\n abi.encodeWithSelector(\n IVault.withdrawFromStrategy.selector,\n _strategies[i],\n assets,\n _toUint256Array(_amounts[i])\n ),\n 0\n );\n if (success) {\n _trackMovement(_amounts[i], _dailyLimit);\n } else {\n emit WithdrawalFailed(_strategies[i], _amounts[i]);\n }\n }\n }\n\n /// @dev Execute depositToStrategy for each (strategy, amount) pair via the Safe.\n function _executeDeposits(\n address[] calldata _strategies,\n uint256[] calldata _amounts,\n uint256 _dailyLimit\n ) internal {\n address[] memory assets = _toAddressArray(asset);\n for (uint256 i = 0; i < _strategies.length; i++) {\n if (_amounts[i] == 0) continue;\n require(isAllowedStrategy[_strategies[i]], \"Strategy not allowed\");\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0,\n abi.encodeWithSelector(\n IVault.depositToStrategy.selector,\n _strategies[i],\n assets,\n _toUint256Array(_amounts[i])\n ),\n 0\n );\n if (success) {\n _trackMovement(_amounts[i], _dailyLimit);\n } else {\n emit DepositFailed(_strategies[i], _amounts[i]);\n }\n }\n }\n\n // slither-disable-end reentrancy-no-eth\n\n function _toAddressArray(address _addr)\n internal\n pure\n returns (address[] memory arr)\n {\n arr = new address[](1);\n arr[0] = _addr;\n }\n\n function _toUint256Array(uint256 _val)\n internal\n pure\n returns (uint256[] memory arr)\n {\n arr = new uint256[](1);\n arr[0] = _val;\n }\n}\n" + }, + "contracts/beacon/BeaconConsolidation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library to request validator consolidation on the beacon chain.\n * @author Origin Protocol Inc\n */\nlibrary BeaconConsolidation {\n /// @notice The address the validator consolidation requests are sent\n /// See https://eips.ethereum.org/EIPS/eip-7251\n address internal constant CONSOLIDATION_REQUEST_ADDRESS =\n 0x0000BBdDc7CE488642fb579F8B00f3a590007251;\n\n function request(bytes calldata source, bytes calldata target)\n internal\n returns (uint256 fee_)\n {\n require(source.length == 48, \"Invalid source byte length\");\n require(target.length == 48, \"Invalid target byte length\");\n\n fee_ = fee();\n\n // Call the Consolidation Request contract with the public keys of the source and target\n // validators packed together.\n // This does not have a function signature, so we use a call\n (bool success, ) = CONSOLIDATION_REQUEST_ADDRESS.call{ value: fee_ }(\n abi.encodePacked(source, target)\n );\n\n require(success, \"Consolidation request failed\");\n }\n\n function fee() internal view returns (uint256) {\n // Get fee from the consolidation request contract\n (bool success, bytes memory result) = CONSOLIDATION_REQUEST_ADDRESS\n .staticcall(\"\");\n\n require(success && result.length > 0, \"Failed to get fee\");\n return abi.decode(result, (uint256));\n }\n}\n" + }, + "contracts/beacon/BeaconRoots.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library to retrieve beacon block roots.\n * @author Origin Protocol Inc\n */\nlibrary BeaconRoots {\n /// @notice The address of beacon block roots oracle\n /// See https://eips.ethereum.org/EIPS/eip-4788\n address internal constant BEACON_ROOTS_ADDRESS =\n 0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02;\n\n /// @notice Returns the beacon block root for the previous block.\n /// This comes from the Beacon Roots contract defined in EIP-4788.\n /// This will revert if the block is more than 8,191 blocks old as\n /// that is the size of the beacon root's ring buffer.\n /// @param timestamp The timestamp of the block for which to get the parent root.\n /// @return parentRoot The parent block root for the given timestamp.\n function parentBlockRoot(uint64 timestamp)\n internal\n view\n returns (bytes32 parentRoot)\n {\n // Call the Beacon Roots contract to get the parent block root.\n // This does not have a function signature, so we use a staticcall.\n (bool success, bytes memory result) = BEACON_ROOTS_ADDRESS.staticcall(\n abi.encode(timestamp)\n );\n\n require(success && result.length > 0, \"Invalid beacon timestamp\");\n parentRoot = abi.decode(result, (bytes32));\n }\n}\n" + }, + "contracts/beacon/PartialWithdrawal.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library to request full or partial withdrawals from validators on the beacon chain.\n * @author Origin Protocol Inc\n */\nlibrary PartialWithdrawal {\n /// @notice The address where the withdrawal request is sent to\n /// See https://eips.ethereum.org/EIPS/eip-7002\n address internal constant WITHDRAWAL_REQUEST_ADDRESS =\n 0x00000961Ef480Eb55e80D19ad83579A64c007002;\n\n /// @notice Requests a partial withdrawal for a given validator public key and amount.\n /// @param validatorPubKey The public key of the validator to withdraw from\n /// @param amount The amount of ETH to withdraw\n function request(bytes calldata validatorPubKey, uint64 amount)\n internal\n returns (uint256 fee_)\n {\n require(validatorPubKey.length == 48, \"Invalid validator byte length\");\n fee_ = fee();\n\n // Call the Withdrawal Request contract with the validator public key\n // and amount to be withdrawn packed together\n\n // This is a general purpose EL to CL request:\n // https://eips.ethereum.org/EIPS/eip-7685\n (bool success, ) = WITHDRAWAL_REQUEST_ADDRESS.call{ value: fee_ }(\n abi.encodePacked(validatorPubKey, amount)\n );\n\n require(success, \"Withdrawal request failed\");\n }\n\n /// @notice Gets fee for withdrawal requests contract on Beacon chain\n function fee() internal view returns (uint256) {\n // Get fee from the withdrawal request contract\n (bool success, bytes memory result) = WITHDRAWAL_REQUEST_ADDRESS\n .staticcall(\"\");\n\n require(success && result.length > 0, \"Failed to get fee\");\n return abi.decode(result, (uint256));\n }\n}\n" + }, + "contracts/echidna/Debugger.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Debugger {\n event Debug(string debugString);\n event Debug(string description, string data);\n event Debug(string prefix, string description, string data);\n event Debug(string description, bytes32 data);\n event Debug(string prefix, string description, bytes32 data);\n event Debug(string description, uint256 data);\n event Debug(string prefix, string description, uint256 data);\n event Debug(string description, int256 data);\n event Debug(string prefix, string description, int256 data);\n event Debug(string description, address data);\n event Debug(string prefix, string description, address data);\n event Debug(string description, bool data);\n event Debug(string prefix, string description, bool data);\n\n function log(string memory debugString) internal {\n emit Debug(debugString);\n }\n\n function log(string memory description, string memory data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n string memory data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, bytes32 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n bytes32 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, uint256 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n uint256 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, int256 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n int256 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, address data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n address data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, bool data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n bool data\n ) internal {\n emit Debug(prefix, description, data);\n }\n}\n" + }, + "contracts/echidna/Echidna.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaTestApproval.sol\";\n\n/**\n * @title Echidna test contract for OUSD\n * @notice Target contract to be tested, containing all mixins\n * @author Rappie\n */\ncontract Echidna is EchidnaTestApproval {\n\n}\n" + }, + "contracts/echidna/EchidnaConfig.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Top-level mixin for configuring the desired fuzzing setup\n * @author Rappie\n */\ncontract EchidnaConfig {\n address internal constant ADDRESS_VAULT = address(0x10000);\n address internal constant ADDRESS_OUTSIDER_USER = address(0x20000);\n\n address internal constant ADDRESS_USER0 = address(0x30000);\n address internal constant ADDRESS_USER1 = address(0x40000);\n\n // Will be set in EchidnaSetup constructor\n address internal ADDRESS_OUTSIDER_CONTRACT;\n address internal ADDRESS_CONTRACT0;\n address internal ADDRESS_CONTRACT1;\n\n // Toggle known issues\n //\n // This can be used to skip tests that are known to fail. This is useful\n // when debugging a specific issue, but should be disabled when running\n // the full test suite.\n //\n // True => skip tests that are known to fail\n // False => run all tests\n //\n bool internal constant TOGGLE_KNOWN_ISSUES = false;\n\n // Toggle known issues within limits\n //\n // Same as TOGGLE_KNOWN_ISSUES, but also skip tests that are known to fail\n // within limits set by the variables below.\n //\n bool internal constant TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS = true;\n\n // Starting balance\n //\n // Gives OUSD a non-zero starting supply, which can be useful to ignore\n // certain edge cases.\n //\n // The starting balance is given to outsider accounts that are not used as\n // accounts while fuzzing.\n //\n bool internal constant TOGGLE_STARTING_BALANCE = true;\n uint256 internal constant STARTING_BALANCE = 1_000_000e18;\n\n // Change supply\n //\n // Set a limit to the amount of change per rebase, which can be useful to\n // ignore certain edge cases.\n //\n // True => limit the amount of change to a percentage of total supply\n // False => no limit\n //\n bool internal constant TOGGLE_CHANGESUPPLY_LIMIT = true;\n uint256 internal constant CHANGESUPPLY_DIVISOR = 10; // 10% of total supply\n\n // Mint limit\n //\n // Set a limit the amount minted per mint, which can be useful to\n // ignore certain edge cases.\n //\n // True => limit the amount of minted tokens\n // False => no limit\n //\n bool internal constant TOGGLE_MINT_LIMIT = true;\n uint256 internal constant MINT_MODULO = 1_000_000_000_000e18;\n\n // Known rounding errors\n uint256 internal constant TRANSFER_ROUNDING_ERROR = 1e18 - 1;\n uint256 internal constant OPT_IN_ROUNDING_ERROR = 1e18 - 1;\n uint256 internal constant MINT_ROUNDING_ERROR = 1e18 - 1;\n\n /**\n * @notice Modifier to skip tests that are known to fail\n * @dev see TOGGLE_KNOWN_ISSUES for more information\n */\n modifier hasKnownIssue() {\n if (TOGGLE_KNOWN_ISSUES) return;\n _;\n }\n\n /**\n * @notice Modifier to skip tests that are known to fail within limits\n * @dev see TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS for more information\n */\n modifier hasKnownIssueWithinLimits() {\n if (TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS) return;\n _;\n }\n\n /**\n * @notice Translate an account ID to an address\n * @param accountId The ID of the account\n * @return account The address of the account\n */\n function getAccount(uint8 accountId)\n internal\n view\n returns (address account)\n {\n accountId = accountId / 64;\n if (accountId == 0) return account = ADDRESS_USER0;\n if (accountId == 1) return account = ADDRESS_USER1;\n if (accountId == 2) return account = ADDRESS_CONTRACT0;\n if (accountId == 3) return account = ADDRESS_CONTRACT1;\n require(false, \"Unknown account ID\");\n }\n}\n" + }, + "contracts/echidna/EchidnaDebug.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"./EchidnaHelper.sol\";\nimport \"./Debugger.sol\";\n\nimport \"../token/OUSD.sol\";\n\n/**\n * @title Room for random debugging functions\n * @author Rappie\n */\ncontract EchidnaDebug is EchidnaHelper {\n function debugOUSD() public pure {\n // assert(ousd.balanceOf(ADDRESS_USER0) == 1000);\n // assert(ousd.rebaseState(ADDRESS_USER0) != OUSD.RebaseOptions.OptIn);\n // assert(Address.isContract(ADDRESS_CONTRACT0));\n // Debugger.log(\"nonRebasingSupply\", ousd.nonRebasingSupply());\n // assert(false);\n }\n}\n" + }, + "contracts/echidna/EchidnaHelper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaSetup.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin containing helper functions\n * @author Rappie\n */\ncontract EchidnaHelper is EchidnaSetup {\n /**\n * @notice Mint tokens to an account\n * @param toAcc Account to mint to\n * @param amount Amount to mint\n * @return Amount minted (in case of capped mint with modulo)\n */\n function mint(uint8 toAcc, uint256 amount) public returns (uint256) {\n address to = getAccount(toAcc);\n\n if (TOGGLE_MINT_LIMIT) {\n amount = amount % MINT_MODULO;\n }\n\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(to, amount);\n\n return amount;\n }\n\n /**\n * @notice Burn tokens from an account\n * @param fromAcc Account to burn from\n * @param amount Amount to burn\n */\n function burn(uint8 fromAcc, uint256 amount) public {\n address from = getAccount(fromAcc);\n hevm.prank(ADDRESS_VAULT);\n ousd.burn(from, amount);\n }\n\n /**\n * @notice Change the total supply of OUSD (rebase)\n * @param amount New total supply\n */\n function changeSupply(uint256 amount) public {\n if (TOGGLE_CHANGESUPPLY_LIMIT) {\n amount =\n ousd.totalSupply() +\n (amount % (ousd.totalSupply() / CHANGESUPPLY_DIVISOR));\n }\n\n hevm.prank(ADDRESS_VAULT);\n ousd.changeSupply(amount);\n }\n\n /**\n * @notice Transfer tokens between accounts\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function transfer(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n ousd.transfer(to, amount);\n }\n\n /**\n * @notice Transfer approved tokens between accounts\n * @param authorizedAcc Account that is authorized to transfer\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function transferFrom(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n ousd.transferFrom(from, to, amount);\n }\n\n /**\n * @notice Opt in to rebasing\n * @param targetAcc Account to opt in\n */\n function optIn(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n hevm.prank(target);\n ousd.rebaseOptIn();\n }\n\n /**\n * @notice Opt out of rebasing\n * @param targetAcc Account to opt out\n */\n function optOut(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n hevm.prank(target);\n ousd.rebaseOptOut();\n }\n\n /**\n * @notice Approve an account to spend OUSD\n * @param ownerAcc Account that owns the OUSD\n * @param spenderAcc Account that is approved to spend the OUSD\n * @param amount Amount to approve\n */\n function approve(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n hevm.prank(owner);\n // slither-disable-next-line unused-return\n ousd.approve(spender, amount);\n }\n\n /**\n * @notice Get the sum of all OUSD balances\n * @return total Total balance\n */\n function getTotalBalance() public view returns (uint256 total) {\n total += ousd.balanceOf(ADDRESS_VAULT);\n total += ousd.balanceOf(ADDRESS_OUTSIDER_USER);\n total += ousd.balanceOf(ADDRESS_OUTSIDER_CONTRACT);\n total += ousd.balanceOf(ADDRESS_USER0);\n total += ousd.balanceOf(ADDRESS_USER1);\n total += ousd.balanceOf(ADDRESS_CONTRACT0);\n total += ousd.balanceOf(ADDRESS_CONTRACT1);\n }\n\n /**\n * @notice Get the sum of all non-rebasing OUSD balances\n * @return total Total balance\n */\n function getTotalNonRebasingBalance() public returns (uint256 total) {\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_VAULT)\n ? ousd.balanceOf(ADDRESS_VAULT)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_OUTSIDER_USER)\n ? ousd.balanceOf(ADDRESS_OUTSIDER_USER)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_OUTSIDER_CONTRACT)\n ? ousd.balanceOf(ADDRESS_OUTSIDER_CONTRACT)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_USER0)\n ? ousd.balanceOf(ADDRESS_USER0)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_USER1)\n ? ousd.balanceOf(ADDRESS_USER1)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_CONTRACT0)\n ? ousd.balanceOf(ADDRESS_CONTRACT0)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_CONTRACT1)\n ? ousd.balanceOf(ADDRESS_CONTRACT1)\n : 0;\n }\n}\n" + }, + "contracts/echidna/EchidnaSetup.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./IHevm.sol\";\nimport \"./EchidnaConfig.sol\";\nimport \"./OUSDEchidna.sol\";\n\ncontract Dummy {}\n\n/**\n * @title Mixin for setup and deployment\n * @author Rappie\n */\ncontract EchidnaSetup is EchidnaConfig {\n IHevm hevm = IHevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);\n OUSDEchidna ousd = new OUSDEchidna();\n\n /**\n * @notice Deploy the OUSD contract and set up initial state\n */\n constructor() {\n ousd.initialize(ADDRESS_VAULT, 1e18);\n\n // Deploy dummny contracts as users\n Dummy outsider = new Dummy();\n ADDRESS_OUTSIDER_CONTRACT = address(outsider);\n Dummy dummy0 = new Dummy();\n ADDRESS_CONTRACT0 = address(dummy0);\n Dummy dummy1 = new Dummy();\n ADDRESS_CONTRACT1 = address(dummy1);\n\n // Start out with a reasonable amount of OUSD\n if (TOGGLE_STARTING_BALANCE) {\n // Rebasing tokens\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(ADDRESS_OUTSIDER_USER, STARTING_BALANCE / 2);\n\n // Non-rebasing tokens\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(ADDRESS_OUTSIDER_CONTRACT, STARTING_BALANCE / 2);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestAccounting.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestSupply.sol\";\n\n/**\n * @title Mixin for testing accounting functions\n * @author Rappie\n */\ncontract EchidnaTestAccounting is EchidnaTestSupply {\n /**\n * @notice After opting in, balance should not increase. (Ok to lose rounding funds doing this)\n * @param targetAcc Account to opt in\n */\n function testOptInBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optIn(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter <= balanceBefore);\n }\n\n /**\n * @notice After opting out, balance should remain the same\n * @param targetAcc Account to opt out\n */\n function testOptOutBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optOut(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Account balance should remain the same after opting in minus rounding error\n * @param targetAcc Account to opt in\n */\n function testOptInBalanceRounding(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optIn(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n int256 delta = int256(balanceAfter) - int256(balanceBefore);\n Debugger.log(\"delta\", delta);\n\n // slither-disable-next-line tautology\n assert(-1 * delta >= 0);\n assert(-1 * delta <= int256(OPT_IN_ROUNDING_ERROR));\n }\n\n /**\n * @notice After opting in, total supply should remain the same\n * @param targetAcc Account to opt in\n */\n function testOptInTotalSupply(uint8 targetAcc) public {\n uint256 totalSupplyBefore = ousd.totalSupply();\n optIn(targetAcc);\n uint256 totalSupplyAfter = ousd.totalSupply();\n\n assert(totalSupplyAfter == totalSupplyBefore);\n }\n\n /**\n * @notice After opting out, total supply should remain the same\n * @param targetAcc Account to opt out\n */\n function testOptOutTotalSupply(uint8 targetAcc) public {\n uint256 totalSupplyBefore = ousd.totalSupply();\n optOut(targetAcc);\n uint256 totalSupplyAfter = ousd.totalSupply();\n\n assert(totalSupplyAfter == totalSupplyBefore);\n }\n\n /**\n * @notice Account balance should remain the same when a smart contract auto converts\n * @param targetAcc Account to auto convert\n */\n function testAutoConvertBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n // slither-disable-next-line unused-return\n ousd._isNonRebasingAccountEchidna(target);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice The `balanceOf` function should never revert\n * @param targetAcc Account to check balance of\n */\n function testBalanceOfShouldNotRevert(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n // slither-disable-next-line unused-return\n try ousd.balanceOf(target) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestApproval.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaTestMintBurn.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin for testing approval related functions\n * @author Rappie\n */\ncontract EchidnaTestApproval is EchidnaTestMintBurn {\n /**\n * @notice Performing `transferFrom` with an amount inside the allowance should not revert\n * @param authorizedAcc The account that is authorized to transfer\n * @param fromAcc The account that is transferring\n * @param toAcc The account that is receiving\n * @param amount The amount to transfer\n */\n function testTransferFromShouldNotRevert(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount <= ousd.balanceOf(from));\n require(amount <= ousd.allowance(from, authorized));\n\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n try ousd.transferFrom(from, to, amount) {\n // pass\n } catch {\n assert(false);\n }\n }\n\n /**\n * @notice Performing `transferFrom` with an amount outside the allowance should revert\n * @param authorizedAcc The account that is authorized to transfer\n * @param fromAcc The account that is transferring\n * @param toAcc The account that is receiving\n * @param amount The amount to transfer\n */\n function testTransferFromShouldRevert(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount > 0);\n require(\n !(amount <= ousd.balanceOf(from) &&\n amount <= ousd.allowance(from, authorized))\n );\n\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n try ousd.transferFrom(from, to, amount) {\n assert(false);\n } catch {\n // pass\n }\n }\n\n /**\n * @notice Approving an amount should update the allowance and overwrite any previous allowance\n * @param ownerAcc The account that is approving\n * @param spenderAcc The account that is being approved\n * @param amount The amount to approve\n */\n function testApprove(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n\n approve(ownerAcc, spenderAcc, amount);\n uint256 allowanceAfter1 = ousd.allowance(owner, spender);\n\n assert(allowanceAfter1 == amount);\n\n approve(ownerAcc, spenderAcc, amount / 2);\n uint256 allowanceAfter2 = ousd.allowance(owner, spender);\n\n assert(allowanceAfter2 == amount / 2);\n }\n}\n" + }, + "contracts/echidna/EchidnaTestMintBurn.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestAccounting.sol\";\n\n/**\n * @title Mixin for testing Mint and Burn functions\n * @author Rappie\n */\ncontract EchidnaTestMintBurn is EchidnaTestAccounting {\n /**\n * @notice Minting 0 tokens should not affect account balance\n * @param targetAcc Account to mint to\n */\n function testMintZeroBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n mint(targetAcc, 0);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Burning 0 tokens should not affect account balance\n * @param targetAcc Account to burn from\n */\n function testBurnZeroBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n burn(targetAcc, 0);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Minting tokens must increase the account balance by at least amount\n * @param targetAcc Account to mint to\n * @param amount Amount to mint\n * @custom:error testMintBalance(uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * testMintBalance(0,1)\n * Event sequence:\n * Debug(«balanceBefore», 0)\n * Debug(«balanceAfter», 0)\n */\n function testMintBalance(uint8 targetAcc, uint256 amount)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n uint256 amountMinted = mint(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n Debugger.log(\"amountMinted\", amountMinted);\n Debugger.log(\"balanceBefore\", balanceBefore);\n Debugger.log(\"balanceAfter\", balanceAfter);\n\n assert(balanceAfter >= balanceBefore + amountMinted);\n }\n\n /**\n * @notice Burning tokens must decrease the account balance by at least amount\n * @param targetAcc Account to burn from\n * @param amount Amount to burn\n * @custom:error testBurnBalance(uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * mint(0,3)\n * testBurnBalance(0,1)\n * Event sequence:\n * Debug(«balanceBefore», 2)\n * Debug(«balanceAfter», 2)\n */\n function testBurnBalance(uint8 targetAcc, uint256 amount)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n burn(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n Debugger.log(\"balanceBefore\", balanceBefore);\n Debugger.log(\"balanceAfter\", balanceAfter);\n\n assert(balanceAfter <= balanceBefore - amount);\n }\n\n /**\n * @notice Minting tokens should not increase the account balance by less than rounding error above amount\n * @param targetAcc Account to mint to\n * @param amount Amount to mint\n */\n function testMintBalanceRounding(uint8 targetAcc, uint256 amount) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n uint256 amountMinted = mint(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n int256 delta = int256(balanceAfter) - int256(balanceBefore);\n\n // delta == amount, if no error\n // delta < amount, if too little is minted\n // delta > amount, if too much is minted\n int256 error = int256(amountMinted) - delta;\n\n assert(error >= 0);\n assert(error <= int256(MINT_ROUNDING_ERROR));\n }\n\n /**\n * @notice A burn of an account balance must result in a zero balance\n * @param targetAcc Account to burn from\n */\n function testBurnAllBalanceToZero(uint8 targetAcc) public hasKnownIssue {\n address target = getAccount(targetAcc);\n\n burn(targetAcc, ousd.balanceOf(target));\n assert(ousd.balanceOf(target) == 0);\n }\n\n /**\n * @notice You should always be able to burn an account's balance\n * @param targetAcc Account to burn from\n */\n function testBurnAllBalanceShouldNotRevert(uint8 targetAcc)\n public\n hasKnownIssue\n {\n address target = getAccount(targetAcc);\n uint256 balance = ousd.balanceOf(target);\n\n hevm.prank(ADDRESS_VAULT);\n try ousd.burn(target, balance) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestSupply.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestTransfer.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n/**\n * @title Mixin for testing supply related functions\n * @author Rappie\n */\ncontract EchidnaTestSupply is EchidnaTestTransfer {\n using StableMath for uint256;\n\n uint256 prevRebasingCreditsPerToken = type(uint256).max;\n\n /**\n * @notice After a `changeSupply`, the total supply should exactly\n * match the target total supply. (This is needed to ensure successive\n * rebases are correct).\n * @param supply New total supply\n * @custom:error testChangeSupply(uint256): failed!💥\n * Call sequence:\n * testChangeSupply(1044505275072865171609)\n * Event sequence:\n * TotalSupplyUpdatedHighres(1044505275072865171610, 1000000000000000000000000, 957391048054055578595)\n */\n function testChangeSupply(uint256 supply)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n hevm.prank(ADDRESS_VAULT);\n ousd.changeSupply(supply);\n\n assert(ousd.totalSupply() == supply);\n }\n\n /**\n * @notice The total supply must not be less than the sum of account balances.\n * (The difference will go into future rebases)\n * @custom:error testTotalSupplyLessThanTotalBalance(): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(1)\n * optOut(64)\n * transfer(0,64,1)\n * testTotalSupplyLessThanTotalBalance()\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000001000001)\n * Debug(«totalBalance», 1000000000000000001000002)\n */\n function testTotalSupplyLessThanTotalBalance()\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n uint256 totalSupply = ousd.totalSupply();\n uint256 totalBalance = getTotalBalance();\n\n Debugger.log(\"totalSupply\", totalSupply);\n Debugger.log(\"totalBalance\", totalBalance);\n\n assert(totalSupply >= totalBalance);\n }\n\n /**\n * @notice Non-rebasing supply should not be larger than total supply\n * @custom:error testNonRebasingSupplyVsTotalSupply(): failed!💥\n * Call sequence:\n * mint(0,2)\n * changeSupply(3)\n * burn(0,1)\n * optOut(0)\n * testNonRebasingSupplyVsTotalSupply()\n */\n function testNonRebasingSupplyVsTotalSupply() public hasKnownIssue {\n uint256 nonRebasingSupply = ousd.nonRebasingSupply();\n uint256 totalSupply = ousd.totalSupply();\n\n assert(nonRebasingSupply <= totalSupply);\n }\n\n /**\n * @notice Global `rebasingCreditsPerToken` should never increase\n * @custom:error testRebasingCreditsPerTokenNotIncreased(): failed!💥\n * Call sequence:\n * testRebasingCreditsPerTokenNotIncreased()\n * changeSupply(1)\n * testRebasingCreditsPerTokenNotIncreased()\n */\n function testRebasingCreditsPerTokenNotIncreased() public hasKnownIssue {\n uint256 curRebasingCreditsPerToken = ousd\n .rebasingCreditsPerTokenHighres();\n\n Debugger.log(\n \"prevRebasingCreditsPerToken\",\n prevRebasingCreditsPerToken\n );\n Debugger.log(\"curRebasingCreditsPerToken\", curRebasingCreditsPerToken);\n\n assert(curRebasingCreditsPerToken <= prevRebasingCreditsPerToken);\n\n prevRebasingCreditsPerToken = curRebasingCreditsPerToken;\n }\n\n /**\n * @notice The rebasing credits per token ratio must greater than zero\n */\n function testRebasingCreditsPerTokenAboveZero() public {\n assert(ousd.rebasingCreditsPerTokenHighres() > 0);\n }\n\n /**\n * @notice The sum of all non-rebasing balances should not be larger than\n * non-rebasing supply\n * @custom:error testTotalNonRebasingSupplyLessThanTotalBalance(): failed!💥\n * Call sequence\n * mint(0,2)\n * changeSupply(1)\n * optOut(0)\n * burn(0,1)\n * testTotalNonRebasingSupplyLessThanTotalBalance()\n * Event sequence:\n * Debug(«totalNonRebasingSupply», 500000000000000000000001)\n * Debug(«totalNonRebasingBalance», 500000000000000000000002)\n */\n function testTotalNonRebasingSupplyLessThanTotalBalance()\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n uint256 totalNonRebasingSupply = ousd.nonRebasingSupply();\n uint256 totalNonRebasingBalance = getTotalNonRebasingBalance();\n\n Debugger.log(\"totalNonRebasingSupply\", totalNonRebasingSupply);\n Debugger.log(\"totalNonRebasingBalance\", totalNonRebasingBalance);\n\n assert(totalNonRebasingSupply >= totalNonRebasingBalance);\n }\n\n /**\n * @notice An accounts credits / credits per token should not be larger it's balance\n * @param targetAcc The account to check\n */\n function testCreditsPerTokenVsBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n (uint256 credits, uint256 creditsPerToken, ) = ousd\n .creditsBalanceOfHighres(target);\n uint256 expectedBalance = credits.divPrecisely(creditsPerToken);\n\n uint256 balance = ousd.balanceOf(target);\n\n Debugger.log(\"credits\", credits);\n Debugger.log(\"creditsPerToken\", creditsPerToken);\n Debugger.log(\"expectedBalance\", expectedBalance);\n Debugger.log(\"balance\", balance);\n\n assert(expectedBalance == balance);\n }\n}\n" + }, + "contracts/echidna/EchidnaTestTransfer.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin for testing transfer related functions\n * @author Rappie\n */\ncontract EchidnaTestTransfer is EchidnaDebug {\n /**\n * @notice The receiving account's balance after a transfer must not increase by\n * less than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferBalanceReceivedLess(uint8,uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * mint(64,2)\n * testTransferBalanceReceivedLess(64,0,1)\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000000500002)\n * Debug(«toBalBefore», 0)\n * Debug(«toBalAfter», 0)\n */\n function testTransferBalanceReceivedLess(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue hasKnownIssueWithinLimits {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n\n assert(toBalAfter >= toBalBefore + amount);\n }\n\n /**\n * @notice The receiving account's balance after a transfer must not\n * increase by more than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceReceivedMore(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n\n assert(toBalAfter <= toBalBefore + amount);\n }\n\n /**\n * @notice The sending account's balance after a transfer must not\n * decrease by less than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferBalanceSentLess(uint8,uint8,uint256): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(1)\n * testTransferBalanceSentLess(0,64,1)\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000000500001)\n * Debug(«fromBalBefore», 1)\n * Debug(«fromBalAfter», 1)\n */\n function testTransferBalanceSentLess(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue hasKnownIssueWithinLimits {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n\n assert(fromBalAfter <= fromBalBefore - amount);\n }\n\n /**\n * @notice The sending account's balance after a transfer must not\n * decrease by more than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceSentMore(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n\n assert(fromBalAfter >= fromBalBefore - amount);\n }\n\n /**\n * @notice The receiving account's balance after a transfer must not\n * increase by less than the amount transferred (minus rounding error)\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceReceivedLessRounding(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n int256 toDelta = int256(toBalAfter) - int256(toBalBefore);\n\n // delta == amount, if no error\n // delta < amount, if too little is sent\n // delta > amount, if too much is sent\n int256 error = int256(amount) - toDelta;\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n Debugger.log(\"toDelta\", toDelta);\n Debugger.log(\"error\", error);\n\n assert(error >= 0);\n assert(error <= int256(TRANSFER_ROUNDING_ERROR));\n }\n\n /**\n * @notice The sending account's balance after a transfer must\n * not decrease by less than the amount transferred (minus rounding error)\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceSentLessRounding(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n int256 fromDelta = int256(fromBalAfter) - int256(fromBalBefore);\n\n // delta == -amount, if no error\n // delta < -amount, if too much is sent\n // delta > -amount, if too little is sent\n int256 error = int256(amount) + fromDelta;\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n Debugger.log(\"fromDelta\", fromDelta);\n Debugger.log(\"error\", error);\n\n assert(error >= 0);\n assert(error <= int256(TRANSFER_ROUNDING_ERROR));\n }\n\n /**\n * @notice An account should always be able to successfully transfer\n * an amount within its balance.\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferWithinBalanceDoesNotRevert(uint8,uint8,uint8): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(3)\n * optOut(0)\n * testTransferWithinBalanceDoesNotRevert(0,128,2)\n * optIn(0)\n * testTransferWithinBalanceDoesNotRevert(128,0,1)\n * Event sequence:\n * error Revert Panic(17): SafeMath over-/under-flows\n */\n function testTransferWithinBalanceDoesNotRevert(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount > 0);\n amount = amount % ousd.balanceOf(from);\n\n Debugger.log(\"Total supply\", ousd.totalSupply());\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(to, amount) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n\n /**\n * @notice An account should never be able to successfully transfer\n * an amount greater than their balance.\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferExceedingBalanceReverts(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n amount = ousd.balanceOf(from) + 1 + amount;\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(to, amount) {\n assert(false);\n } catch {\n assert(true);\n }\n }\n\n /**\n * @notice A transfer to the same account should not change that account's balance\n * @param targetAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferSelf(uint8 targetAcc, uint256 amount) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n transfer(targetAcc, targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceBefore == balanceAfter);\n }\n\n /**\n * @notice Transfers to the zero account revert\n * @param fromAcc Account to transfer from\n * @param amount Amount to transfer\n */\n function testTransferToZeroAddress(uint8 fromAcc, uint256 amount) public {\n address from = getAccount(fromAcc);\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(address(0), amount) {\n assert(false);\n } catch {\n assert(true);\n }\n }\n}\n" + }, + "contracts/echidna/IHevm.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// https://github.com/ethereum/hevm/blob/main/doc/src/controlling-the-unit-testing-environment.md#cheat-codes\n\ninterface IHevm {\n function warp(uint256 x) external;\n\n function roll(uint256 x) external;\n\n function store(\n address c,\n bytes32 loc,\n bytes32 val\n ) external;\n\n function load(address c, bytes32 loc) external returns (bytes32 val);\n\n function sign(uint256 sk, bytes32 digest)\n external\n returns (\n uint8 v,\n bytes32 r,\n bytes32 s\n );\n\n function addr(uint256 sk) external returns (address addr);\n\n function ffi(string[] calldata) external returns (bytes memory);\n\n function prank(address sender) external;\n}\n" + }, + "contracts/echidna/OUSDEchidna.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../token/OUSD.sol\";\n\ncontract OUSDEchidna is OUSD {\n constructor() OUSD() {}\n\n function _isNonRebasingAccountEchidna(address _account)\n public\n returns (bool)\n {\n _autoMigrate(_account);\n return alternativeCreditsPerToken[_account] > 0;\n }\n}\n" + }, + "contracts/governance/Governable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\n * from owner to governor and renounce methods removed. Does not use\n * Context.sol like Ownable.sol does for simplification.\n * @author Origin Protocol Inc\n */\nabstract contract Governable {\n // Storage position of the owner and pendingOwner of the contract\n // keccak256(\"OUSD.governor\");\n bytes32 private constant governorPosition =\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\n\n // keccak256(\"OUSD.pending.governor\");\n bytes32 private constant pendingGovernorPosition =\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\n\n // keccak256(\"OUSD.reentry.status\");\n bytes32 private constant reentryStatusPosition =\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\n\n // See OpenZeppelin ReentrancyGuard implementation\n uint256 constant _NOT_ENTERED = 1;\n uint256 constant _ENTERED = 2;\n\n event PendingGovernorshipTransfer(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n\n event GovernorshipTransferred(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n\n /**\n * @notice Returns the address of the current Governor.\n */\n function governor() public view returns (address) {\n return _governor();\n }\n\n /**\n * @dev Returns the address of the current Governor.\n */\n function _governor() internal view returns (address governorOut) {\n bytes32 position = governorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n governorOut := sload(position)\n }\n }\n\n /**\n * @dev Returns the address of the pending Governor.\n */\n function _pendingGovernor()\n internal\n view\n returns (address pendingGovernor)\n {\n bytes32 position = pendingGovernorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n pendingGovernor := sload(position)\n }\n }\n\n /**\n * @dev Throws if called by any account other than the Governor.\n */\n modifier onlyGovernor() {\n require(isGovernor(), \"Caller is not the Governor\");\n _;\n }\n\n /**\n * @notice Returns true if the caller is the current Governor.\n */\n function isGovernor() public view returns (bool) {\n return msg.sender == _governor();\n }\n\n function _setGovernor(address newGovernor) internal {\n emit GovernorshipTransferred(_governor(), newGovernor);\n\n bytes32 position = governorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, newGovernor)\n }\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and make it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n bytes32 position = reentryStatusPosition;\n uint256 _reentry_status;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n _reentry_status := sload(position)\n }\n\n // On the first call to nonReentrant, _notEntered will be true\n require(_reentry_status != _ENTERED, \"Reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, _ENTERED)\n }\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, _NOT_ENTERED)\n }\n }\n\n function _setPendingGovernor(address newGovernor) internal {\n bytes32 position = pendingGovernorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, newGovernor)\n }\n }\n\n /**\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\n * Can only be called by the current Governor. Must be claimed for this to complete\n * @param _newGovernor Address of the new Governor\n */\n function transferGovernance(address _newGovernor) external onlyGovernor {\n _setPendingGovernor(_newGovernor);\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\n }\n\n /**\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\n * Can only be called by the new Governor.\n */\n function claimGovernance() external {\n require(\n msg.sender == _pendingGovernor(),\n \"Only the pending Governor can complete the claim\"\n );\n _changeGovernor(msg.sender);\n }\n\n /**\n * @dev Change Governance of the contract to a new account (`newGovernor`).\n * @param _newGovernor Address of the new Governor\n */\n function _changeGovernor(address _newGovernor) internal {\n require(_newGovernor != address(0), \"New Governor is address(0)\");\n _setGovernor(_newGovernor);\n }\n}\n" + }, + "contracts/governance/Strategizable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Governable } from \"./Governable.sol\";\n\ncontract Strategizable is Governable {\n event StrategistUpdated(address _address);\n\n // Address of strategist\n address public strategistAddr;\n\n // For future use\n uint256[50] private __gap;\n\n /**\n * @dev Verifies that the caller is either Governor or Strategist.\n */\n modifier onlyGovernorOrStrategist() virtual {\n require(\n msg.sender == strategistAddr || isGovernor(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n /**\n * @dev Set address of Strategist\n * @param _address Address of Strategist\n */\n function setStrategistAddr(address _address) external onlyGovernor {\n _setStrategistAddr(_address);\n }\n\n /**\n * @dev Set address of Strategist\n * @param _address Address of Strategist\n */\n function _setStrategistAddr(address _address) internal {\n strategistAddr = _address;\n emit StrategistUpdated(_address);\n }\n}\n" + }, + "contracts/harvest/AbstractHarvester.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { IUniswapV2Router } from \"../interfaces/uniswap/IUniswapV2Router02.sol\";\nimport { IUniswapV3Router } from \"../interfaces/uniswap/IUniswapV3Router.sol\";\nimport { IBalancerVault } from \"../interfaces/balancer/IBalancerVault.sol\";\nimport { ICurvePool } from \"../strategies/ICurvePool.sol\";\nimport \"../utils/Helpers.sol\";\n\nabstract contract AbstractHarvester is Governable {\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n using StableMath for uint256;\n\n enum SwapPlatform {\n UniswapV2Compatible,\n UniswapV3,\n Balancer,\n Curve\n }\n\n event SupportedStrategyUpdate(address strategyAddress, bool isSupported);\n event RewardTokenConfigUpdated(\n address tokenAddress,\n uint16 allowedSlippageBps,\n uint16 harvestRewardBps,\n SwapPlatform swapPlatform,\n address swapPlatformAddr,\n bytes swapData,\n uint256 liquidationLimit,\n bool doSwapRewardToken\n );\n event RewardTokenSwapped(\n address indexed rewardToken,\n address indexed swappedInto,\n SwapPlatform swapPlatform,\n uint256 amountIn,\n uint256 amountOut\n );\n event RewardProceedsTransferred(\n address indexed token,\n address farmer,\n uint256 protcolYield,\n uint256 farmerFee\n );\n event RewardProceedsAddressChanged(address newProceedsAddress);\n\n error EmptyAddress();\n error InvalidSlippageBps();\n error InvalidHarvestRewardBps();\n\n error InvalidSwapPlatform(SwapPlatform swapPlatform);\n\n error InvalidUniswapV2PathLength();\n error InvalidTokenInSwapPath(address token);\n error EmptyBalancerPoolId();\n error InvalidCurvePoolAssetIndex(address token);\n\n error UnsupportedStrategy(address strategyAddress);\n\n error SlippageError(uint256 actualBalance, uint256 minExpected);\n error BalanceMismatchAfterSwap(uint256 actualBalance, uint256 minExpected);\n\n // Configuration properties for harvesting logic of reward tokens\n struct RewardTokenConfig {\n // Max allowed slippage when swapping reward token for a stablecoin denominated in basis points.\n uint16 allowedSlippageBps;\n // Reward when calling a harvest function denominated in basis points.\n uint16 harvestRewardBps;\n // Address of compatible exchange protocol (Uniswap V2/V3, SushiSwap, Balancer and Curve).\n address swapPlatformAddr;\n /* When true the reward token is being swapped. In a need of (temporarily) disabling the swapping of\n * a reward token this needs to be set to false.\n */\n bool doSwapRewardToken;\n // Platform to use for Swapping\n SwapPlatform swapPlatform;\n /* How much token can be sold per one harvest call. If the balance of rewards tokens\n * exceeds that limit multiple harvest calls are required to harvest all of the tokens.\n * Set it to MAX_INT to effectively disable the limit.\n */\n uint256 liquidationLimit;\n }\n\n mapping(address => RewardTokenConfig) public rewardTokenConfigs;\n mapping(address => bool) public supportedStrategies;\n\n address public immutable vaultAddress;\n\n /**\n * Address receiving rewards proceeds. Initially the Vault contract later will possibly\n * be replaced by another contract that eases out rewards distribution.\n **/\n address public rewardProceedsAddress;\n\n /**\n * All tokens are swapped to this token before it gets transferred\n * to the `rewardProceedsAddress`. USDT for OUSD and WETH for OETH.\n **/\n address public immutable baseTokenAddress;\n // Cached decimals for `baseTokenAddress`\n uint256 public immutable baseTokenDecimals;\n\n // Uniswap V2 path for reward tokens using Uniswap V2 Router\n mapping(address => address[]) public uniswapV2Path;\n // Uniswap V3 path for reward tokens using Uniswap V3 Router\n mapping(address => bytes) public uniswapV3Path;\n // Pool ID to use for reward tokens on Balancer\n mapping(address => bytes32) public balancerPoolId;\n\n struct CurvePoolIndices {\n // Casted into uint128 and stored in a struct to save gas\n uint128 rewardTokenIndex;\n uint128 baseTokenIndex;\n }\n // Packed indices of assets on the Curve pool\n mapping(address => CurvePoolIndices) public curvePoolIndices;\n\n constructor(address _vaultAddress, address _baseTokenAddress) {\n require(_vaultAddress != address(0));\n require(_baseTokenAddress != address(0));\n\n vaultAddress = _vaultAddress;\n baseTokenAddress = _baseTokenAddress;\n\n // Cache decimals as well\n baseTokenDecimals = Helpers.getDecimals(_baseTokenAddress);\n }\n\n /***************************************\n Configuration\n ****************************************/\n\n /**\n * Set the Address receiving rewards proceeds.\n * @param _rewardProceedsAddress Address of the reward token\n */\n function setRewardProceedsAddress(address _rewardProceedsAddress)\n external\n onlyGovernor\n {\n if (_rewardProceedsAddress == address(0)) {\n revert EmptyAddress();\n }\n\n rewardProceedsAddress = _rewardProceedsAddress;\n emit RewardProceedsAddressChanged(_rewardProceedsAddress);\n }\n\n /**\n * @dev Add/update a reward token configuration that holds harvesting config variables\n * @param _tokenAddress Address of the reward token\n * @param tokenConfig.allowedSlippageBps uint16 maximum allowed slippage denominated in basis points.\n * Example: 300 == 3% slippage\n * @param tokenConfig.harvestRewardBps uint16 amount of reward tokens the caller of the function is rewarded.\n * Example: 100 == 1%\n * @param tokenConfig.swapPlatformAddr Address Address of a UniswapV2 compatible contract to perform\n * the exchange from reward tokens to stablecoin (currently hard-coded to USDT)\n * @param tokenConfig.liquidationLimit uint256 Maximum amount of token to be sold per one swap function call.\n * When value is 0 there is no limit.\n * @param tokenConfig.doSwapRewardToken bool Disables swapping of the token when set to true,\n * does not cause it to revert though.\n * @param tokenConfig.swapPlatform SwapPlatform to use for Swapping\n * @param swapData Additional data required for swapping\n */\n function setRewardTokenConfig(\n address _tokenAddress,\n RewardTokenConfig calldata tokenConfig,\n bytes calldata swapData\n ) external onlyGovernor {\n if (tokenConfig.allowedSlippageBps > 1000) {\n revert InvalidSlippageBps();\n }\n\n if (tokenConfig.harvestRewardBps > 1000) {\n revert InvalidHarvestRewardBps();\n }\n\n address newRouterAddress = tokenConfig.swapPlatformAddr;\n if (newRouterAddress == address(0)) {\n // Swap router address should be non zero address\n revert EmptyAddress();\n }\n\n address oldRouterAddress = rewardTokenConfigs[_tokenAddress]\n .swapPlatformAddr;\n rewardTokenConfigs[_tokenAddress] = tokenConfig;\n\n // Revert if feed does not exist\n // slither-disable-next-line unused-return\n\n IERC20 token = IERC20(_tokenAddress);\n // if changing token swap provider cancel existing allowance\n if (\n /* oldRouterAddress == address(0) when there is no pre-existing\n * configuration for said rewards token\n */\n oldRouterAddress != address(0) &&\n oldRouterAddress != newRouterAddress\n ) {\n token.safeApprove(oldRouterAddress, 0);\n }\n\n // Give SwapRouter infinite approval when needed\n if (oldRouterAddress != newRouterAddress) {\n token.safeApprove(newRouterAddress, 0);\n token.safeApprove(newRouterAddress, type(uint256).max);\n }\n\n SwapPlatform _platform = tokenConfig.swapPlatform;\n if (_platform == SwapPlatform.UniswapV2Compatible) {\n uniswapV2Path[_tokenAddress] = _decodeUniswapV2Path(\n swapData,\n _tokenAddress\n );\n } else if (_platform == SwapPlatform.UniswapV3) {\n uniswapV3Path[_tokenAddress] = _decodeUniswapV3Path(\n swapData,\n _tokenAddress\n );\n } else if (_platform == SwapPlatform.Balancer) {\n balancerPoolId[_tokenAddress] = _decodeBalancerPoolId(\n swapData,\n newRouterAddress,\n _tokenAddress\n );\n } else if (_platform == SwapPlatform.Curve) {\n curvePoolIndices[_tokenAddress] = _decodeCurvePoolIndices(\n swapData,\n newRouterAddress,\n _tokenAddress\n );\n } else {\n // Note: This code is unreachable since Solidity reverts when\n // the value is outside the range of defined values of the enum\n // (even if it's under the max length of the base type)\n revert InvalidSwapPlatform(_platform);\n }\n\n emit RewardTokenConfigUpdated(\n _tokenAddress,\n tokenConfig.allowedSlippageBps,\n tokenConfig.harvestRewardBps,\n _platform,\n newRouterAddress,\n swapData,\n tokenConfig.liquidationLimit,\n tokenConfig.doSwapRewardToken\n );\n }\n\n /**\n * @dev Decodes the data passed into Uniswap V2 path and validates\n * it to make sure the path is for `token` to `baseToken`\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @param token The address of the reward token\n * @return path The validated Uniswap V2 path\n */\n function _decodeUniswapV2Path(bytes calldata data, address token)\n internal\n view\n returns (address[] memory path)\n {\n (path) = abi.decode(data, (address[]));\n uint256 len = path.length;\n\n if (len < 2) {\n // Path should have at least two tokens\n revert InvalidUniswapV2PathLength();\n }\n\n // Do some validation\n if (path[0] != token) {\n revert InvalidTokenInSwapPath(path[0]);\n }\n\n if (path[len - 1] != baseTokenAddress) {\n revert InvalidTokenInSwapPath(path[len - 1]);\n }\n }\n\n /**\n * @dev Decodes the data passed into Uniswap V3 path and validates\n * it to make sure the path is for `token` to `baseToken`\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @param token The address of the reward token\n * @return path The validated Uniswap V3 path\n */\n function _decodeUniswapV3Path(bytes calldata data, address token)\n internal\n view\n returns (bytes calldata path)\n {\n path = data;\n\n address decodedAddress = address(uint160(bytes20(data[0:20])));\n\n if (decodedAddress != token) {\n // Invalid Reward Token in swap path\n revert InvalidTokenInSwapPath(decodedAddress);\n }\n\n decodedAddress = address(uint160(bytes20(data[path.length - 20:])));\n if (decodedAddress != baseTokenAddress) {\n // Invalid Base Token in swap path\n revert InvalidTokenInSwapPath(decodedAddress);\n }\n }\n\n /**\n * @dev Decodes the data passed to Balancer Pool ID\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @return poolId The pool ID\n */\n function _decodeBalancerPoolId(\n bytes calldata data,\n address balancerVault,\n address token\n ) internal view returns (bytes32 poolId) {\n (poolId) = abi.decode(data, (bytes32));\n\n if (poolId == bytes32(0)) {\n revert EmptyBalancerPoolId();\n }\n\n IBalancerVault bVault = IBalancerVault(balancerVault);\n\n // Note: this reverts if token is not a pool asset\n // slither-disable-next-line unused-return\n bVault.getPoolTokenInfo(poolId, token);\n\n // slither-disable-next-line unused-return\n bVault.getPoolTokenInfo(poolId, baseTokenAddress);\n }\n\n /**\n * @dev Decodes the data passed to get the pool indices and\n * checks it against the Curve Pool to make sure it's\n * not misconfigured. The indices are packed into a single\n * uint256 for gas savings\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @param poolAddress Curve pool address\n * @param token The address of the reward token\n * @return indices Packed pool asset indices\n */\n function _decodeCurvePoolIndices(\n bytes calldata data,\n address poolAddress,\n address token\n ) internal view returns (CurvePoolIndices memory indices) {\n indices = abi.decode(data, (CurvePoolIndices));\n\n ICurvePool pool = ICurvePool(poolAddress);\n if (token != pool.coins(indices.rewardTokenIndex)) {\n revert InvalidCurvePoolAssetIndex(token);\n }\n if (baseTokenAddress != pool.coins(indices.baseTokenIndex)) {\n revert InvalidCurvePoolAssetIndex(baseTokenAddress);\n }\n }\n\n /**\n * @dev Flags a strategy as supported or not supported one\n * @param _strategyAddress Address of the strategy\n * @param _isSupported Bool marking strategy as supported or not supported\n */\n function setSupportedStrategy(address _strategyAddress, bool _isSupported)\n external\n onlyGovernor\n {\n supportedStrategies[_strategyAddress] = _isSupported;\n emit SupportedStrategyUpdate(_strategyAddress, _isSupported);\n }\n\n /***************************************\n Rewards\n ****************************************/\n\n /**\n * @dev Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform. Can be called by anyone.\n * Rewards incentivizing the caller are sent to the caller of this function.\n * @param _strategyAddr Address of the strategy to collect rewards from\n */\n function harvestAndSwap(address _strategyAddr) external nonReentrant {\n // Remember _harvest function checks for the validity of _strategyAddr\n _harvestAndSwap(_strategyAddr, msg.sender);\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform. Can be called by anyone\n * @param _strategyAddr Address of the strategy to collect rewards from\n * @param _rewardTo Address where to send a share of harvest rewards to as an incentive\n * for executing this function\n */\n function harvestAndSwap(address _strategyAddr, address _rewardTo)\n external\n nonReentrant\n {\n // Remember _harvest function checks for the validity of _strategyAddr\n _harvestAndSwap(_strategyAddr, _rewardTo);\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform\n * @param _strategyAddr Address of the strategy to collect rewards from\n * @param _rewardTo Address where to send a share of harvest rewards to as an incentive\n * for executing this function\n */\n function _harvestAndSwap(address _strategyAddr, address _rewardTo)\n internal\n {\n _harvest(_strategyAddr);\n IStrategy strategy = IStrategy(_strategyAddr);\n address[] memory rewardTokens = strategy.getRewardTokenAddresses();\n uint256 len = rewardTokens.length;\n for (uint256 i = 0; i < len; ++i) {\n // This harvester contract is not used anymore. Keeping the code\n // for passing test deployment. Safe to use address(0x1) as oracle.\n _swap(rewardTokens[i], _rewardTo, IOracle(address(0x1)));\n }\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform\n * @param _strategyAddr Address of the strategy to collect rewards from.\n */\n function _harvest(address _strategyAddr) internal virtual {\n if (!supportedStrategies[_strategyAddr]) {\n revert UnsupportedStrategy(_strategyAddr);\n }\n\n IStrategy strategy = IStrategy(_strategyAddr);\n strategy.collectRewardTokens();\n }\n\n /**\n * @dev Swap a reward token for the base token on the configured\n * swap platform. The token must have a registered price feed\n * with the price provider\n * @param _swapToken Address of the token to swap\n * @param _rewardTo Address where to send the share of harvest rewards to\n * @param _priceProvider Oracle to get prices of the swap token\n */\n // This function is called by the harvestAndSwap function, which is only called by\n // functions that have the nonReentrant modifier. Therefore, this function is also non-reentrant.\n // slither-disable-start reentrancy-eth,reentrancy-no-eth,reentrancy-benign\n // slither-disable-start reentrancy-events,reentrancy-unlimited-gas,reentrancy-balance\n function _swap(\n address _swapToken,\n address _rewardTo,\n IOracle _priceProvider\n ) internal virtual {\n uint256 balance = IERC20(_swapToken).balanceOf(address(this));\n\n // No need to swap if the reward token is the base token. eg USDT or WETH.\n // There is also no limit on the transfer. Everything in the harvester will be transferred\n // to the Dripper regardless of the liquidationLimit config.\n if (_swapToken == baseTokenAddress) {\n IERC20(_swapToken).safeTransfer(rewardProceedsAddress, balance);\n // currently not paying the farmer any rewards as there is no swap\n emit RewardProceedsTransferred(\n baseTokenAddress,\n address(0),\n balance,\n 0\n );\n return;\n }\n\n RewardTokenConfig memory tokenConfig = rewardTokenConfigs[_swapToken];\n\n /* This will trigger a return when reward token configuration has not yet been set\n * or we have temporarily disabled swapping of specific reward token via setting\n * doSwapRewardToken to false.\n */\n if (!tokenConfig.doSwapRewardToken) {\n return;\n }\n\n if (balance == 0) {\n return;\n }\n\n if (tokenConfig.liquidationLimit > 0) {\n balance = Math.min(balance, tokenConfig.liquidationLimit);\n }\n\n // This'll revert if there is no price feed\n uint256 oraclePrice = _priceProvider.price(_swapToken);\n\n // Oracle price is 1e18\n uint256 minExpected = (balance *\n (1e4 - tokenConfig.allowedSlippageBps) * // max allowed slippage\n oraclePrice).scaleBy(\n baseTokenDecimals,\n Helpers.getDecimals(_swapToken)\n ) /\n 1e4 / // fix the max slippage decimal position\n 1e18; // and oracle price decimals position\n\n // Do the swap\n uint256 amountReceived = _doSwap(\n tokenConfig.swapPlatform,\n tokenConfig.swapPlatformAddr,\n _swapToken,\n balance,\n minExpected\n );\n\n if (amountReceived < minExpected) {\n revert SlippageError(amountReceived, minExpected);\n }\n\n emit RewardTokenSwapped(\n _swapToken,\n baseTokenAddress,\n tokenConfig.swapPlatform,\n balance,\n amountReceived\n );\n\n IERC20 baseToken = IERC20(baseTokenAddress);\n uint256 baseTokenBalance = baseToken.balanceOf(address(this));\n if (baseTokenBalance < amountReceived) {\n // Note: It's possible to bypass this check by transferring `baseToken`\n // directly to Harvester before calling the `harvestAndSwap`. However,\n // there's no incentive for an attacker to do that. Doing a balance diff\n // will increase the gas cost significantly\n revert BalanceMismatchAfterSwap(baseTokenBalance, amountReceived);\n }\n\n // Farmer only gets fee from the base amount they helped farm,\n // They do not get anything from anything that already was there\n // on the Harvester\n uint256 farmerFee = amountReceived.mulTruncateScale(\n tokenConfig.harvestRewardBps,\n 1e4\n );\n uint256 protocolYield = baseTokenBalance - farmerFee;\n\n baseToken.safeTransfer(rewardProceedsAddress, protocolYield);\n baseToken.safeTransfer(_rewardTo, farmerFee);\n emit RewardProceedsTransferred(\n baseTokenAddress,\n _rewardTo,\n protocolYield,\n farmerFee\n );\n }\n\n // slither-disable-end reentrancy-events,reentrancy-unlimited-gas,reentrancy-balance\n // slither-disable-end reentrancy-eth,reentrancy-no-eth,reentrancy-benign\n\n function _doSwap(\n SwapPlatform swapPlatform,\n address routerAddress,\n address rewardTokenAddress,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n if (swapPlatform == SwapPlatform.UniswapV2Compatible) {\n return\n _swapWithUniswapV2(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else if (swapPlatform == SwapPlatform.UniswapV3) {\n return\n _swapWithUniswapV3(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else if (swapPlatform == SwapPlatform.Balancer) {\n return\n _swapWithBalancer(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else if (swapPlatform == SwapPlatform.Curve) {\n return\n _swapWithCurve(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else {\n // Should never be invoked since we catch invalid values\n // in the `setRewardTokenConfig` function before it's set\n revert InvalidSwapPlatform(swapPlatform);\n }\n }\n\n /**\n * @dev Swaps the token to `baseToken` with Uniswap V2\n *\n * @param routerAddress Uniswap V2 Router address\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithUniswapV2(\n address routerAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n address[] memory path = uniswapV2Path[swapToken];\n\n uint256[] memory amounts = IUniswapV2Router(routerAddress)\n .swapExactTokensForTokens(\n amountIn,\n minAmountOut,\n path,\n address(this),\n block.timestamp\n );\n\n amountOut = amounts[amounts.length - 1];\n }\n\n /**\n * @dev Swaps the token to `baseToken` with Uniswap V3\n *\n * @param routerAddress Uniswap V3 Router address\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithUniswapV3(\n address routerAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n bytes memory path = uniswapV3Path[swapToken];\n\n IUniswapV3Router.ExactInputParams memory params = IUniswapV3Router\n .ExactInputParams({\n path: path,\n recipient: address(this),\n deadline: block.timestamp,\n amountIn: amountIn,\n amountOutMinimum: minAmountOut\n });\n amountOut = IUniswapV3Router(routerAddress).exactInput(params);\n }\n\n /**\n * @dev Swaps the token to `baseToken` on Balancer\n *\n * @param balancerVaultAddress BalancerVaultAddress\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithBalancer(\n address balancerVaultAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n bytes32 poolId = balancerPoolId[swapToken];\n\n IBalancerVault.SingleSwap memory singleSwap = IBalancerVault\n .SingleSwap({\n poolId: poolId,\n kind: IBalancerVault.SwapKind.GIVEN_IN,\n assetIn: swapToken,\n assetOut: baseTokenAddress,\n amount: amountIn,\n userData: hex\"\"\n });\n\n IBalancerVault.FundManagement memory fundMgmt = IBalancerVault\n .FundManagement({\n sender: address(this),\n fromInternalBalance: false,\n recipient: payable(address(this)),\n toInternalBalance: false\n });\n\n amountOut = IBalancerVault(balancerVaultAddress).swap(\n singleSwap,\n fundMgmt,\n minAmountOut,\n block.timestamp\n );\n }\n\n /**\n * @dev Swaps the token to `baseToken` on Curve\n *\n * @param poolAddress Curve Pool Address\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithCurve(\n address poolAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n CurvePoolIndices memory indices = curvePoolIndices[swapToken];\n\n // Note: Not all CurvePools return the `amountOut`, make sure\n // to use only pool that do. Otherwise the swap would revert\n // always\n amountOut = ICurvePool(poolAddress).exchange(\n uint256(indices.rewardTokenIndex),\n uint256(indices.baseTokenIndex),\n amountIn,\n minAmountOut\n );\n }\n}\n" + }, + "contracts/harvest/Dripper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\n/**\n * @title OUSD Dripper\n *\n * The dripper contract smooths out the yield from point-in-time yield events\n * and spreads the yield out over a configurable time period. This ensures a\n * continuous per block yield to makes users happy as their next rebase\n * amount is always moving up. Also, this makes historical day to day yields\n * smooth, rather than going from a near zero day, to a large APY day, then\n * back to a near zero day again.\n *\n *\n * Design notes\n * - USDT has a smaller resolution than the number of seconds\n * in a week, which can make per second payouts have a rounding error. However\n * the total effect is not large - cents per day, and this money is\n * not lost, just distributed in the future. While we could use a higher\n * decimal precision for the drip perSecond, we chose simpler code.\n * - By calculating the changing drip rates on collects only, harvests and yield\n * events don't have to call anything on this contract or pay any extra gas.\n * Collect() is already be paying for a single write, since it has to reset\n * the lastCollect time.\n * - By having a collectAndRebase method, and having our external systems call\n * that, the OUSD vault does not need any changes, not even to know the address\n * of the dripper.\n * - A rejected design was to retro-calculate the drip rate on each collect,\n * based on the balance at the time of the collect. While this would have\n * required less state, and would also have made the contract respond more quickly\n * to new income, it would break the predictability that is this contract's entire\n * purpose. If we did this, the amount of fundsAvailable() would make sharp increases\n * when funds were deposited.\n * - When the dripper recalculates the rate, it targets spending the balance over\n * the duration. This means that every time that collect is called, if no\n * new funds have been deposited the duration is being pushed back and the\n * rate decreases. This is expected, and ends up following a smoother but\n * longer curve the more collect() is called without incoming yield.\n *\n */\n\ncontract Dripper is Governable {\n using SafeERC20 for IERC20;\n\n struct Drip {\n uint64 lastCollect; // overflows 262 billion years after the sun dies\n uint192 perSecond; // drip rate per second\n }\n\n address immutable vault; // OUSD vault\n address immutable token; // token to drip out\n uint256 public dripDuration; // in seconds\n Drip public drip; // active drip parameters\n\n constructor(address _vault, address _token) {\n vault = _vault;\n token = _token;\n }\n\n /// @notice How much funds have dripped out already and are currently\n // available to be sent to the vault.\n /// @return The amount that would be sent if a collect was called\n function availableFunds() external view returns (uint256) {\n uint256 balance = IERC20(token).balanceOf(address(this));\n return _availableFunds(balance, drip);\n }\n\n /// @notice Collect all dripped funds and send to vault.\n /// Recalculate new drip rate.\n function collect() external {\n _collect();\n }\n\n /// @notice Collect all dripped funds, send to vault, recalculate new drip\n /// rate, and rebase OUSD.\n function collectAndRebase() external {\n _collect();\n IVault(vault).rebase();\n }\n\n /// @dev Change the drip duration. Governor only.\n /// @param _durationSeconds the number of seconds to drip out the entire\n /// balance over if no collects were called during that time.\n function setDripDuration(uint256 _durationSeconds)\n external\n virtual\n onlyGovernor\n {\n require(_durationSeconds > 0, \"duration must be non-zero\");\n dripDuration = _durationSeconds;\n _collect(); // duration change take immediate effect\n }\n\n /// @dev Transfer out ERC20 tokens held by the contract. Governor only.\n /// @param _asset ERC20 token address\n /// @param _amount amount to transfer\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /// @dev Calculate available funds by taking the lower of either the\n /// currently dripped out funds or the balance available.\n /// Uses passed in parameters to calculate with for gas savings.\n /// @param _balance current balance in contract\n /// @param _drip current drip parameters\n function _availableFunds(uint256 _balance, Drip memory _drip)\n internal\n view\n returns (uint256)\n {\n uint256 elapsed = block.timestamp - _drip.lastCollect;\n uint256 allowed = (elapsed * _drip.perSecond);\n return (allowed > _balance) ? _balance : allowed;\n }\n\n /// @dev Sends the currently dripped funds to be vault, and sets\n /// the new drip rate based on the new balance.\n function _collect() internal virtual {\n // Calculate send\n uint256 balance = IERC20(token).balanceOf(address(this));\n uint256 amountToSend = _availableFunds(balance, drip);\n uint256 remaining = balance - amountToSend;\n // Calculate new drip perSecond\n // Gas savings by setting entire struct at one time\n drip = Drip({\n perSecond: uint192(remaining / dripDuration),\n lastCollect: uint64(block.timestamp)\n });\n // Send funds\n IERC20(token).safeTransfer(vault, amountToSend);\n }\n\n /// @dev Transfer out all ERC20 held by the contract. Governor only.\n /// @param _asset ERC20 token address\n function transferAllToken(address _asset, address _receiver)\n external\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(\n _receiver,\n IERC20(_asset).balanceOf(address(this))\n );\n }\n}\n" + }, + "contracts/harvest/FixedRateDripper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { Dripper } from \"./Dripper.sol\";\n\n/**\n * @title Fixed Rate Dripper\n *\n * Similar to the Dripper, Fixed Rate Dripper drips out yield per second.\n * However the Strategist decides the rate and it doesn't change after\n * a drip.\n *\n */\n\ncontract FixedRateDripper is Dripper {\n using SafeERC20 for IERC20;\n\n event DripRateUpdated(uint192 oldDripRate, uint192 newDripRate);\n\n /**\n * @dev Verifies that the caller is the Governor or Strategist.\n */\n modifier onlyGovernorOrStrategist() {\n require(\n isGovernor() || msg.sender == IVault(vault).strategistAddr(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n constructor(address _vault, address _token) Dripper(_vault, _token) {}\n\n /// @inheritdoc Dripper\n function setDripDuration(uint256) external virtual override {\n // Not used in FixedRateDripper\n revert(\"Drip duration disabled\");\n }\n\n /// @inheritdoc Dripper\n function _collect() internal virtual override {\n // Calculate amount to send\n uint256 balance = IERC20(token).balanceOf(address(this));\n uint256 amountToSend = _availableFunds(balance, drip);\n\n // Update timestamp\n drip.lastCollect = uint64(block.timestamp);\n\n // Send funds\n IERC20(token).safeTransfer(vault, amountToSend);\n }\n\n /**\n * @dev Sets the drip rate. Callable by Strategist or Governor.\n * Can be set to zero to stop dripper.\n * @param _perSecond Rate of WETH to drip per second\n */\n function setDripRate(uint192 _perSecond) external onlyGovernorOrStrategist {\n emit DripRateUpdated(_perSecond, drip.perSecond);\n\n /**\n * Note: It's important to call `_collect` before updating\n * the drip rate especially on a new proxy contract.\n * When `lastCollect` is not set/initialized, the elapsed\n * time would be calculated as `block.number` seconds,\n * resulting in a huge yield, if `collect` isn't called first.\n */\n // Collect at existing rate\n _collect();\n\n // Update rate\n drip.perSecond = _perSecond;\n }\n}\n" + }, + "contracts/harvest/OETHFixedRateDripper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { FixedRateDripper } from \"./FixedRateDripper.sol\";\n\n/**\n * @title OETH FixedRateDripper Contract\n * @author Origin Protocol Inc\n */\ncontract OETHFixedRateDripper is FixedRateDripper {\n constructor(address _vault, address _token)\n FixedRateDripper(_vault, _token)\n {}\n}\n" + }, + "contracts/interfaces/aerodrome/ICLGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\ninterface ICLGauge {\n /// @notice Returns the claimable rewards for a given account and tokenId\n /// @dev Throws if account is not the position owner\n /// @dev pool.updateRewardsGrowthGlobal() needs to be called first, to return the correct claimable rewards\n /// @param account The address of the user\n /// @param tokenId The tokenId of the position\n /// @return The amount of claimable reward\n function earned(address account, uint256 tokenId)\n external\n view\n returns (uint256);\n\n /// @notice Retrieve rewards for all tokens owned by an account\n /// @dev Throws if not called by the voter\n /// @param account The account of the user\n function getReward(address account) external;\n\n /// @notice Retrieve rewards for a tokenId\n /// @dev Throws if not called by the position owner\n /// @param tokenId The tokenId of the position\n function getReward(uint256 tokenId) external;\n\n /// @notice Notifies gauge of gauge rewards.\n /// @param amount Amount of gauge rewards (emissions) to notify. Must be greater than 604_800.\n function notifyRewardAmount(uint256 amount) external;\n\n /// @dev Notifies gauge of gauge rewards without distributing its fees.\n /// Assumes gauge reward tokens is 18 decimals.\n /// If not 18 decimals, rewardRate may have rounding issues.\n /// @param amount Amount of gauge rewards (emissions) to notify. Must be greater than 604_800.\n function notifyRewardWithoutClaim(uint256 amount) external;\n\n /// @notice Used to deposit a CL position into the gauge\n /// @notice Allows the user to receive emissions instead of fees\n /// @param tokenId The tokenId of the position\n function deposit(uint256 tokenId) external;\n\n /// @notice Used to withdraw a CL position from the gauge\n /// @notice Allows the user to receive fees instead of emissions\n /// @notice Outstanding emissions will be collected on withdrawal\n /// @param tokenId The tokenId of the position\n function withdraw(uint256 tokenId) external;\n\n // /// @notice Fetch all tokenIds staked by a given account\n // /// @param depositor The address of the user\n // /// @return The tokenIds of the staked positions\n // function stakedValues(address depositor) external view returns (uint256[] memory);\n\n // /// @notice Fetch a staked tokenId by index\n // /// @param depositor The address of the user\n // /// @param index The index of the staked tokenId\n // /// @return The tokenId of the staked position\n // function stakedByIndex(address depositor, uint256 index) external view returns (uint256);\n\n // /// @notice Check whether a position is staked in the gauge by a certain user\n // /// @param depositor The address of the user\n // /// @param tokenId The tokenId of the position\n // /// @return Whether the position is staked in the gauge\n // function stakedContains(address depositor, uint256 tokenId) external view returns (bool);\n\n // /// @notice The amount of positions staked in the gauge by a certain user\n // /// @param depositor The address of the user\n // /// @return The amount of positions staked in the gauge\n // function stakedLength(address depositor) external view returns (uint256);\n\n function feesVotingReward() external view returns (address);\n}\n" + }, + "contracts/interfaces/aerodrome/ICLPool.sol": { + "content": "pragma solidity >=0.5.0;\n\n/// @title The interface for a CL Pool\n/// @notice A CL pool facilitates swapping and automated market making between any two assets that strictly conform\n/// to the ERC20 specification\n/// @dev The pool interface is broken up into many smaller pieces\ninterface ICLPool {\n function slot0()\n external\n view\n returns (\n uint160 sqrtPriceX96,\n int24 tick,\n uint16 observationIndex,\n uint16 observationCardinality,\n uint16 observationCardinalityNext,\n bool unlocked\n );\n\n /// @notice The first of the two tokens of the pool, sorted by address\n /// @return The token contract address\n function token0() external view returns (address);\n\n /// @notice The second of the two tokens of the pool, sorted by address\n /// @return The token contract address\n function token1() external view returns (address);\n\n function tickSpacing() external view returns (int24);\n\n /// @notice The gauge corresponding to this pool\n /// @return The gauge contract address\n function gauge() external view returns (address);\n\n /// @notice The currently in range liquidity available to the pool\n /// @dev This value has no relationship to the total liquidity across all ticks\n /// @dev This value includes staked liquidity\n function liquidity() external view returns (uint128);\n\n /// @notice Look up information about a specific tick in the pool\n /// @param tick The tick to look up\n /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or\n /// tick upper,\n /// liquidityNet how much liquidity changes when the pool price crosses the tick,\n /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,\n /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,\n /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick\n /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from\n /// the current tick,\n /// secondsOutside the seconds spent on the other side of the tick from the current tick,\n /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise\n /// equal to false.\n /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.\n /// In addition, these values are only relative and must be used only in comparison to previous snapshots for\n /// a specific position.\n function ticks(int24 tick)\n external\n view\n returns (\n uint128 liquidityGross,\n int128 liquidityNet,\n uint256 feeGrowthOutside0X128,\n uint256 feeGrowthOutside1X128,\n int56 tickCumulativeOutside,\n uint160 secondsPerLiquidityOutsideX128,\n uint32 secondsOutside,\n bool initialized\n );\n}\n" + }, + "contracts/interfaces/aerodrome/INonfungiblePositionManager.sol": { + "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.7.5;\npragma abicoder v2;\n\n/// @title Non-fungible token for positions\n/// @notice Wraps CL positions in a non-fungible token interface which allows for them to be transferred\n/// and authorized.\n// slither-disable-start erc20-interface\ninterface INonfungiblePositionManager {\n /**\n * @dev See {IERC721-approve}.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev See {IERC721-getApproved}.\n */\n function getApproved(uint256 tokenId) external returns (address);\n\n /**\n * @dev See {IERC721-ownerOf}.\n */\n function ownerOf(uint256 tokenId) external view returns (address);\n\n /// @notice Returns the position information associated with a given token ID.\n /// @dev Throws if the token ID is not valid.\n /// @param tokenId The ID of the token that represents the position\n /// @return nonce The nonce for permits\n /// @return operator The address that is approved for spending\n /// @return token0 The address of the token0 for a specific pool\n /// @return token1 The address of the token1 for a specific pool\n /// @return tickSpacing The tick spacing associated with the pool\n /// @return tickLower The lower end of the tick range for the position\n /// @return tickUpper The higher end of the tick range for the position\n /// @return liquidity The liquidity of the position\n /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position\n /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position\n /// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation\n /// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation\n function positions(uint256 tokenId)\n external\n view\n returns (\n uint96 nonce,\n address operator,\n address token0,\n address token1,\n int24 tickSpacing,\n int24 tickLower,\n int24 tickUpper,\n uint128 liquidity,\n uint256 feeGrowthInside0LastX128,\n uint256 feeGrowthInside1LastX128,\n uint128 tokensOwed0,\n uint128 tokensOwed1\n );\n\n struct MintParams {\n address token0;\n address token1;\n int24 tickSpacing;\n int24 tickLower;\n int24 tickUpper;\n uint256 amount0Desired;\n uint256 amount1Desired;\n uint256 amount0Min;\n uint256 amount1Min;\n address recipient;\n uint256 deadline;\n uint160 sqrtPriceX96;\n }\n\n /// @notice Creates a new position wrapped in a NFT\n /// @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized\n /// a method does not exist, i.e. the pool is assumed to be initialized.\n /// @param params The params necessary to mint a position, encoded as `MintParams` in calldata\n /// @return tokenId The ID of the token that represents the minted position\n /// @return liquidity The amount of liquidity for this position\n /// @return amount0 The amount of token0\n /// @return amount1 The amount of token1\n function mint(MintParams calldata params)\n external\n payable\n returns (\n uint256 tokenId,\n uint128 liquidity,\n uint256 amount0,\n uint256 amount1\n );\n\n struct IncreaseLiquidityParams {\n uint256 tokenId;\n uint256 amount0Desired;\n uint256 amount1Desired;\n uint256 amount0Min;\n uint256 amount1Min;\n uint256 deadline;\n }\n\n /// @notice Increases the amount of liquidity in a position, with tokens paid by the `msg.sender`\n /// @param params tokenId The ID of the token for which liquidity is being increased,\n /// amount0Desired The desired amount of token0 to be spent,\n /// amount1Desired The desired amount of token1 to be spent,\n /// amount0Min The minimum amount of token0 to spend, which serves as a slippage check,\n /// amount1Min The minimum amount of token1 to spend, which serves as a slippage check,\n /// deadline The time by which the transaction must be included to effect the change\n /// @return liquidity The new liquidity amount as a result of the increase\n /// @return amount0 The amount of token0 to acheive resulting liquidity\n /// @return amount1 The amount of token1 to acheive resulting liquidity\n function increaseLiquidity(IncreaseLiquidityParams calldata params)\n external\n payable\n returns (\n uint128 liquidity,\n uint256 amount0,\n uint256 amount1\n );\n\n struct DecreaseLiquidityParams {\n uint256 tokenId;\n uint128 liquidity;\n uint256 amount0Min;\n uint256 amount1Min;\n uint256 deadline;\n }\n\n /// @notice Decreases the amount of liquidity in a position and accounts it to the position\n /// @param params tokenId The ID of the token for which liquidity is being decreased,\n /// amount The amount by which liquidity will be decreased,\n /// amount0Min The minimum amount of token0 that should be accounted for the burned liquidity,\n /// amount1Min The minimum amount of token1 that should be accounted for the burned liquidity,\n /// deadline The time by which the transaction must be included to effect the change\n /// @return amount0 The amount of token0 accounted to the position's tokens owed\n /// @return amount1 The amount of token1 accounted to the position's tokens owed\n /// @dev The use of this function can cause a loss to users of the NonfungiblePositionManager\n /// @dev for tokens that have very high decimals.\n /// @dev The amount of tokens necessary for the loss is: 3.4028237e+38.\n /// @dev This is equivalent to 1e20 value with 18 decimals.\n function decreaseLiquidity(DecreaseLiquidityParams calldata params)\n external\n payable\n returns (uint256 amount0, uint256 amount1);\n\n struct CollectParams {\n uint256 tokenId;\n address recipient;\n uint128 amount0Max;\n uint128 amount1Max;\n }\n\n /// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient\n /// @notice Used to update staked positions before deposit and withdraw\n /// @param params tokenId The ID of the NFT for which tokens are being collected,\n /// recipient The account that should receive the tokens,\n /// amount0Max The maximum amount of token0 to collect,\n /// amount1Max The maximum amount of token1 to collect\n /// @return amount0 The amount of fees collected in token0\n /// @return amount1 The amount of fees collected in token1\n function collect(CollectParams calldata params)\n external\n payable\n returns (uint256 amount0, uint256 amount1);\n\n /// @notice Burns a token ID, which deletes it from the NFT contract. The token must have 0 liquidity and all tokens\n /// must be collected first.\n /// @param tokenId The ID of the token that is being burned\n function burn(uint256 tokenId) external payable;\n\n /// @notice Sets a new Token Descriptor\n /// @param _tokenDescriptor Address of the new Token Descriptor to be chosen\n function setTokenDescriptor(address _tokenDescriptor) external;\n\n /// @notice Sets a new Owner address\n /// @param _owner Address of the new Owner to be chosen\n function setOwner(address _owner) external;\n}\n// slither-disable-end erc20-interface\n" + }, + "contracts/interfaces/aerodrome/ISugarHelper.sol": { + "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\npragma abicoder v2;\n\nimport { INonfungiblePositionManager } from \"./INonfungiblePositionManager.sol\";\n\ninterface ISugarHelper {\n struct PopulatedTick {\n int24 tick;\n uint160 sqrtRatioX96;\n int128 liquidityNet;\n uint128 liquidityGross;\n }\n\n ///\n /// Wrappers for LiquidityAmounts\n ///\n\n function getAmountsForLiquidity(\n uint160 sqrtRatioX96,\n uint160 sqrtRatioAX96,\n uint160 sqrtRatioBX96,\n uint128 liquidity\n ) external pure returns (uint256 amount0, uint256 amount1);\n\n function getLiquidityForAmounts(\n uint256 amount0,\n uint256 amount1,\n uint160 sqrtRatioX96,\n uint160 sqrtRatioAX96,\n uint160 sqrtRatioBX96\n ) external pure returns (uint128 liquidity);\n\n /// @notice Computes the amount of token0 for a given amount of token1 and price range\n /// @param amount1 Amount of token1 to estimate liquidity\n /// @param pool Address of the pool to be used\n /// @param sqrtRatioX96 A sqrt price representing the current pool prices\n /// @param tickLow Lower tick boundary\n /// @param tickLow Upper tick boundary\n /// @dev If the given pool address is not the zero address, will fetch `sqrtRatioX96` from pool\n /// @return amount0 Estimated amount of token0\n function estimateAmount0(\n uint256 amount1,\n address pool,\n uint160 sqrtRatioX96,\n int24 tickLow,\n int24 tickHigh\n ) external view returns (uint256 amount0);\n\n /// @notice Computes the amount of token1 for a given amount of token0 and price range\n /// @param amount0 Amount of token0 to estimate liquidity\n /// @param pool Address of the pool to be used\n /// @param sqrtRatioX96 A sqrt price representing the current pool prices\n /// @param tickLow Lower tick boundary\n /// @param tickLow Upper tick boundary\n /// @dev If the given pool address is not the zero address, will fetch `sqrtRatioX96` from pool\n /// @return amount1 Estimated amount of token1\n function estimateAmount1(\n uint256 amount0,\n address pool,\n uint160 sqrtRatioX96,\n int24 tickLow,\n int24 tickHigh\n ) external view returns (uint256 amount1);\n\n ///\n /// Wrappers for PositionValue\n ///\n\n function principal(\n INonfungiblePositionManager positionManager,\n uint256 tokenId,\n uint160 sqrtRatioX96\n ) external view returns (uint256 amount0, uint256 amount1);\n\n function fees(INonfungiblePositionManager positionManager, uint256 tokenId)\n external\n view\n returns (uint256 amount0, uint256 amount1);\n\n ///\n /// Wrappers for TickMath\n ///\n\n function getSqrtRatioAtTick(int24 tick)\n external\n pure\n returns (uint160 sqrtRatioX96);\n\n function getTickAtSqrtRatio(uint160 sqrtRatioX96)\n external\n pure\n returns (int24 tick);\n\n /// @notice Fetches Tick Data for all populated Ticks in given bitmaps\n /// @param pool Address of the pool from which to fetch data\n /// @param startTick Tick from which the first bitmap will be fetched\n /// @dev The number of bitmaps fetched by this function should always be `MAX_BITMAPS`,\n /// unless there are less than `MAX_BITMAPS` left to iterate through\n /// @return populatedTicks Array of all Populated Ticks in the provided bitmaps\n function getPopulatedTicks(address pool, int24 startTick)\n external\n view\n returns (PopulatedTick[] memory populatedTicks);\n}\n" + }, + "contracts/interfaces/aerodrome/ISwapRouter.sol": { + "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.7.5;\npragma abicoder v2;\n\n/// @title Router token swapping functionality\n/// @notice Functions for swapping tokens via CL\ninterface ISwapRouter {\n struct ExactInputSingleParams {\n address tokenIn;\n address tokenOut;\n int24 tickSpacing;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n uint160 sqrtPriceLimitX96;\n }\n\n /// @notice Swaps `amountIn` of one token for as much as possible of another token\n /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata\n /// @return amountOut The amount of the received token\n function exactInputSingle(ExactInputSingleParams calldata params)\n external\n payable\n returns (uint256 amountOut);\n\n struct ExactInputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n }\n\n /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path\n /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata\n /// @return amountOut The amount of the received token\n function exactInput(ExactInputParams calldata params)\n external\n payable\n returns (uint256 amountOut);\n\n struct ExactOutputSingleParams {\n address tokenIn;\n address tokenOut;\n int24 tickSpacing;\n address recipient;\n uint256 deadline;\n uint256 amountOut;\n uint256 amountInMaximum;\n uint160 sqrtPriceLimitX96;\n }\n\n /// @notice Swaps as little as possible of one token for `amountOut` of another token\n /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata\n /// @return amountIn The amount of the input token\n function exactOutputSingle(ExactOutputSingleParams calldata params)\n external\n payable\n returns (uint256 amountIn);\n\n struct ExactOutputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountOut;\n uint256 amountInMaximum;\n }\n\n /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)\n /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata\n /// @return amountIn The amount of the input token\n function exactOutput(ExactOutputParams calldata params)\n external\n payable\n returns (uint256 amountIn);\n}\n" + }, + "contracts/interfaces/algebra/IAlgebraGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IGauge {\n function owner() external view returns (address);\n\n function TOKEN() external view returns (address);\n\n function DISTRIBUTION() external view returns (address);\n\n function balanceOf(address account) external view returns (uint256);\n\n function claimFees() external returns (uint256 claimed0, uint256 claimed1);\n\n function deposit(uint256 amount) external;\n\n function depositAll() external;\n\n function earned(address account) external view returns (uint256);\n\n function getReward() external;\n\n function getReward(address _user) external;\n\n function isForPair() external view returns (bool);\n\n function lastTimeRewardApplicable() external view returns (uint256);\n\n function lastUpdateTime() external view returns (uint256);\n\n function notifyRewardAmount(address token, uint256 reward) external;\n\n function periodFinish() external view returns (uint256);\n\n function rewardForDuration() external view returns (uint256);\n\n function rewardPerToken() external view returns (uint256);\n\n function rewardPerTokenStored() external view returns (uint256);\n\n function rewardRate() external view returns (uint256);\n\n function rewardToken() external view returns (address);\n\n function rewards(address) external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function userRewardPerTokenPaid(address) external view returns (uint256);\n\n function withdraw(uint256 amount) external;\n\n function withdrawAll() external;\n\n function withdrawAllAndHarvest() external;\n\n function withdrawExcess(address token, uint256 amount) external;\n\n function emergency() external returns (bool);\n\n function emergencyWithdraw() external;\n\n function activateEmergencyMode() external;\n\n function stopEmergencyMode() external;\n}\n" + }, + "contracts/interfaces/algebra/IAlgebraPair.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IPair {\n event Approval(address indexed src, address indexed guy, uint256 wad);\n event Transfer(address indexed src, address indexed dst, uint256 wad);\n\n event Mint(address indexed sender, uint256 amount0, uint256 amount1);\n event Burn(\n address indexed sender,\n uint256 amount0,\n uint256 amount1,\n address indexed to\n );\n event Swap(\n address indexed sender,\n uint256 amount0In,\n uint256 amount1In,\n uint256 amount0Out,\n uint256 amount1Out,\n address indexed to\n );\n event Claim(\n address indexed sender,\n address indexed recipient,\n uint256 amount0,\n uint256 amount1\n );\n\n function metadata()\n external\n view\n returns (\n uint256 dec0,\n uint256 dec1,\n uint256 r0,\n uint256 r1,\n bool st,\n address t0,\n address t1\n );\n\n function claimFees() external returns (uint256, uint256);\n\n function tokens() external view returns (address, address);\n\n function token0() external view returns (address);\n\n function token1() external view returns (address);\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n function swap(\n uint256 amount0Out,\n uint256 amount1Out,\n address to,\n bytes calldata data\n ) external;\n\n function burn(address to)\n external\n returns (uint256 amount0, uint256 amount1);\n\n function mint(address to) external returns (uint256 liquidity);\n\n function getReserves()\n external\n view\n returns (\n uint256 _reserve0,\n uint256 _reserve1,\n uint256 _blockTimestampLast\n );\n\n function getAmountOut(uint256, address) external view returns (uint256);\n\n // ERC20 methods\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address) external view returns (uint256);\n\n function transfer(address recipient, uint256 amount)\n external\n returns (bool);\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n function allowance(address owner, address spender)\n external\n view\n returns (uint256);\n\n function approve(address spender, uint256 value) external returns (bool);\n\n function claimable0(address _user) external view returns (uint256);\n\n function claimable1(address _user) external view returns (uint256);\n\n function isStable() external view returns (bool);\n\n function skim(address to) external;\n\n function sync() external;\n}\n" + }, + "contracts/interfaces/balancer/IBalancerVault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\n\ninterface IBalancerVault {\n enum WeightedPoolJoinKind {\n INIT,\n EXACT_TOKENS_IN_FOR_BPT_OUT,\n TOKEN_IN_FOR_EXACT_BPT_OUT,\n ALL_TOKENS_IN_FOR_EXACT_BPT_OUT,\n ADD_TOKEN\n }\n\n enum WeightedPoolExitKind {\n EXACT_BPT_IN_FOR_ONE_TOKEN_OUT,\n EXACT_BPT_IN_FOR_TOKENS_OUT,\n BPT_IN_FOR_EXACT_TOKENS_OUT,\n REMOVE_TOKEN\n }\n\n /**\n * @dev Called by users to join a Pool, which transfers tokens from `sender` into the Pool's balance. This will\n * trigger custom Pool behavior, which will typically grant something in return to `recipient` - often tokenized\n * Pool shares.\n *\n * If the caller is not `sender`, it must be an authorized relayer for them.\n *\n * The `assets` and `maxAmountsIn` arrays must have the same length, and each entry indicates the maximum amount\n * to send for each asset. The amounts to send are decided by the Pool and not the Vault: it just enforces\n * these maximums.\n *\n * If joining a Pool that holds WETH, it is possible to send ETH directly: the Vault will do the wrapping. To enable\n * this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead of the\n * WETH address. Note that it is not possible to combine ETH and WETH in the same join. Any excess ETH will be sent\n * back to the caller (not the sender, which is important for relayers).\n *\n * `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when\n * interacting with Pools that register and deregister tokens frequently. If sending ETH however, the array must be\n * sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the final\n * `assets` array might not be sorted. Pools with no registered tokens cannot be joined.\n *\n * If `fromInternalBalance` is true, the caller's Internal Balance will be preferred: ERC20 transfers will only\n * be made for the difference between the requested amount and Internal Balance (if any). Note that ETH cannot be\n * withdrawn from Internal Balance: attempting to do so will trigger a revert.\n *\n * This causes the Vault to call the `IBasePool.onJoinPool` hook on the Pool's contract, where Pools implement\n * their own custom logic. This typically requires additional information from the user (such as the expected number\n * of Pool shares). This can be encoded in the `userData` argument, which is ignored by the Vault and passed\n * directly to the Pool's contract, as is `recipient`.\n *\n * Emits a `PoolBalanceChanged` event.\n */\n function joinPool(\n bytes32 poolId,\n address sender,\n address recipient,\n JoinPoolRequest memory request\n ) external payable;\n\n struct JoinPoolRequest {\n address[] assets;\n uint256[] maxAmountsIn;\n bytes userData;\n bool fromInternalBalance;\n }\n\n /**\n * @dev Called by users to exit a Pool, which transfers tokens from the Pool's balance to `recipient`. This will\n * trigger custom Pool behavior, which will typically ask for something in return from `sender` - often tokenized\n * Pool shares. The amount of tokens that can be withdrawn is limited by the Pool's `cash` balance (see\n * `getPoolTokenInfo`).\n *\n * If the caller is not `sender`, it must be an authorized relayer for them.\n *\n * The `tokens` and `minAmountsOut` arrays must have the same length, and each entry in these indicates the minimum\n * token amount to receive for each token contract. The amounts to send are decided by the Pool and not the Vault:\n * it just enforces these minimums.\n *\n * If exiting a Pool that holds WETH, it is possible to receive ETH directly: the Vault will do the unwrapping. To\n * enable this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead\n * of the WETH address. Note that it is not possible to combine ETH and WETH in the same exit.\n *\n * `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when\n * interacting with Pools that register and deregister tokens frequently. If receiving ETH however, the array must\n * be sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the\n * final `assets` array might not be sorted. Pools with no registered tokens cannot be exited.\n *\n * If `toInternalBalance` is true, the tokens will be deposited to `recipient`'s Internal Balance. Otherwise,\n * an ERC20 transfer will be performed. Note that ETH cannot be deposited to Internal Balance: attempting to\n * do so will trigger a revert.\n *\n * `minAmountsOut` is the minimum amount of tokens the user expects to get out of the Pool, for each token in the\n * `tokens` array. This array must match the Pool's registered tokens.\n *\n * This causes the Vault to call the `IBasePool.onExitPool` hook on the Pool's contract, where Pools implement\n * their own custom logic. This typically requires additional information from the user (such as the expected number\n * of Pool shares to return). This can be encoded in the `userData` argument, which is ignored by the Vault and\n * passed directly to the Pool's contract.\n *\n * Emits a `PoolBalanceChanged` event.\n */\n function exitPool(\n bytes32 poolId,\n address sender,\n address payable recipient,\n ExitPoolRequest memory request\n ) external;\n\n struct ExitPoolRequest {\n address[] assets;\n uint256[] minAmountsOut;\n bytes userData;\n bool toInternalBalance;\n }\n\n /**\n * @dev Returns a Pool's registered tokens, the total balance for each, and the latest block when *any* of\n * the tokens' `balances` changed.\n *\n * The order of the `tokens` array is the same order that will be used in `joinPool`, `exitPool`, as well as in all\n * Pool hooks (where applicable). Calls to `registerTokens` and `deregisterTokens` may change this order.\n *\n * If a Pool only registers tokens once, and these are sorted in ascending order, they will be stored in the same\n * order as passed to `registerTokens`.\n *\n * Total balances include both tokens held by the Vault and those withdrawn by the Pool's Asset Managers. These are\n * the amounts used by joins, exits and swaps. For a detailed breakdown of token balances, use `getPoolTokenInfo`\n * instead.\n */\n function getPoolTokens(bytes32 poolId)\n external\n view\n returns (\n IERC20[] memory tokens,\n uint256[] memory balances,\n uint256 lastChangeBlock\n );\n\n /**\n * @dev Performs a set of user balance operations, which involve Internal Balance (deposit, withdraw or transfer)\n * and plain ERC20 transfers using the Vault's allowance. This last feature is particularly useful for relayers, as\n * it lets integrators reuse a user's Vault allowance.\n *\n * For each operation, if the caller is not `sender`, it must be an authorized relayer for them.\n */\n function manageUserBalance(UserBalanceOp[] memory ops) external payable;\n\n struct UserBalanceOp {\n UserBalanceOpKind kind;\n address asset;\n uint256 amount;\n address sender;\n address payable recipient;\n }\n\n enum UserBalanceOpKind {\n DEPOSIT_INTERNAL,\n WITHDRAW_INTERNAL,\n TRANSFER_INTERNAL,\n TRANSFER_EXTERNAL\n }\n\n enum SwapKind {\n GIVEN_IN,\n GIVEN_OUT\n }\n\n struct SingleSwap {\n bytes32 poolId;\n SwapKind kind;\n address assetIn;\n address assetOut;\n uint256 amount;\n bytes userData;\n }\n\n struct FundManagement {\n address sender;\n bool fromInternalBalance;\n address payable recipient;\n bool toInternalBalance;\n }\n\n function swap(\n SingleSwap calldata singleSwap,\n FundManagement calldata funds,\n uint256 limit,\n uint256 deadline\n ) external returns (uint256 amountCalculated);\n\n function getPoolTokenInfo(bytes32 poolId, address token)\n external\n view\n returns (\n uint256 cash,\n uint256 managed,\n uint256 lastChangeBlock,\n address assetManager\n );\n}\n" + }, + "contracts/interfaces/cctp/ICCTP.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface ICCTPTokenMessenger {\n function depositForBurn(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller,\n uint256 maxFee,\n uint32 minFinalityThreshold\n ) external;\n\n function depositForBurnWithHook(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller,\n uint256 maxFee,\n uint32 minFinalityThreshold,\n bytes memory hookData\n ) external;\n\n function getMinFeeAmount(uint256 amount) external view returns (uint256);\n}\n\ninterface ICCTPMessageTransmitter {\n function sendMessage(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n uint32 minFinalityThreshold,\n bytes memory messageBody\n ) external;\n\n function receiveMessage(bytes calldata message, bytes calldata attestation)\n external\n returns (bool);\n}\n\ninterface IMessageHandlerV2 {\n /**\n * @notice Handles an incoming finalized message from an IReceiverV2\n * @dev Finalized messages have finality threshold values greater than or equal to 2000\n * @param sourceDomain The source domain of the message\n * @param sender The sender of the message\n * @param finalityThresholdExecuted the finality threshold at which the message was attested to\n * @param messageBody The raw bytes of the message body\n * @return success True, if successful; false, if not.\n */\n function handleReceiveFinalizedMessage(\n uint32 sourceDomain,\n bytes32 sender,\n uint32 finalityThresholdExecuted,\n bytes calldata messageBody\n ) external returns (bool);\n\n /**\n * @notice Handles an incoming unfinalized message from an IReceiverV2\n * @dev Unfinalized messages have finality threshold values less than 2000\n * @param sourceDomain The source domain of the message\n * @param sender The sender of the message\n * @param finalityThresholdExecuted The finality threshold at which the message was attested to\n * @param messageBody The raw bytes of the message body\n * @return success True, if successful; false, if not.\n */\n function handleReceiveUnfinalizedMessage(\n uint32 sourceDomain,\n bytes32 sender,\n uint32 finalityThresholdExecuted,\n bytes calldata messageBody\n ) external returns (bool);\n}\n" + }, + "contracts/interfaces/chainlink/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n}\n" + }, + "contracts/interfaces/hydrex/IHydrexGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title IHydrexGauge\n * @notice Minimal interface exposing the staked-token getter used by the\n * Hydrex GaugeV2 (>= v2.5). Hydrex renamed `TOKEN()` to `stakeToken()`\n * in v2.5; the rest of the gauge surface (deposit / withdraw /\n * getReward / emergency / emergencyWithdraw / balanceOf) is\n * ABI-compatible with `IAlgebraGauge` and is invoked through that\n * interface elsewhere in the strategy.\n */\ninterface IHydrexGauge {\n function stakeToken() external view returns (address);\n}\n" + }, + "contracts/interfaces/IBasicToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IBasicToken {\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\n}\n" + }, + "contracts/interfaces/IBeaconProofs.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IBeaconProofs {\n function verifyValidator(\n bytes32 beaconBlockRoot,\n bytes32 pubKeyHash,\n bytes calldata validatorPubKeyProof,\n uint40 validatorIndex,\n bytes32 withdrawalCredentials\n ) external view;\n\n function verifyValidatorWithdrawable(\n bytes32 beaconBlockRoot,\n uint40 validatorIndex,\n uint64 withdrawableEpoch,\n bytes calldata withdrawableEpochProof\n ) external view;\n\n function verifyBalancesContainer(\n bytes32 beaconBlockRoot,\n bytes32 balancesContainerLeaf,\n bytes calldata balancesContainerProof\n ) external view;\n\n function verifyValidatorBalance(\n bytes32 balancesContainerRoot,\n bytes32 validatorBalanceLeaf,\n bytes calldata balanceProof,\n uint40 validatorIndex\n ) external view returns (uint256 validatorBalance);\n\n function verifyPendingDepositsContainer(\n bytes32 beaconBlockRoot,\n bytes32 pendingDepositsContainerRoot,\n bytes calldata proof\n ) external view;\n\n function verifyPendingDeposit(\n bytes32 pendingDepositsContainerRoot,\n bytes32 pendingDepositRoot,\n bytes calldata proof,\n uint32 pendingDepositIndex\n ) external view;\n\n function verifyFirstPendingDeposit(\n bytes32 beaconBlockRoot,\n uint64 slot,\n bytes calldata firstPendingDepositSlotProof\n ) external view returns (bool isEmptyDepositQueue);\n\n function merkleizePendingDeposit(\n bytes32 pubKeyHash,\n bytes calldata withdrawalCredentials,\n uint64 amountGwei,\n bytes calldata signature,\n uint64 slot\n ) external pure returns (bytes32 root);\n\n function merkleizeSignature(bytes calldata signature)\n external\n pure\n returns (bytes32 root);\n}\n" + }, + "contracts/interfaces/IChildLiquidityGaugeFactory.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface IChildLiquidityGaugeFactory {\n event DeployedGauge(\n address indexed _implementation,\n address indexed _lp_token,\n address indexed _deployer,\n bytes32 _salt,\n address _gauge\n );\n event Minted(\n address indexed _user,\n address indexed _gauge,\n uint256 _new_total\n );\n event TransferOwnership(address _old_owner, address _new_owner);\n event UpdateCallProxy(address _old_call_proxy, address _new_call_proxy);\n event UpdateImplementation(\n address _old_implementation,\n address _new_implementation\n );\n event UpdateManager(address _manager);\n event UpdateMirrored(address indexed _gauge, bool _mirrored);\n event UpdateRoot(address _factory, address _implementation);\n event UpdateVotingEscrow(\n address _old_voting_escrow,\n address _new_voting_escrow\n );\n\n function accept_transfer_ownership() external;\n\n function call_proxy() external view returns (address);\n\n function commit_transfer_ownership(address _future_owner) external;\n\n function crv() external view returns (address);\n\n function deploy_gauge(address _lp_token, bytes32 _salt)\n external\n returns (address);\n\n function deploy_gauge(\n address _lp_token,\n bytes32 _salt,\n address _manager\n ) external returns (address);\n\n function future_owner() external view returns (address);\n\n function gauge_data(address arg0) external view returns (uint256);\n\n function get_gauge(uint256 arg0) external view returns (address);\n\n function get_gauge_count() external view returns (uint256);\n\n function get_gauge_from_lp_token(address arg0)\n external\n view\n returns (address);\n\n function get_implementation() external view returns (address);\n\n function is_mirrored(address _gauge) external view returns (bool);\n\n function is_valid_gauge(address _gauge) external view returns (bool);\n\n function last_request(address _gauge) external view returns (uint256);\n\n function manager() external view returns (address);\n\n function mint(address _gauge) external;\n\n function mint_many(address[32] memory _gauges) external;\n\n function minted(address arg0, address arg1) external view returns (uint256);\n\n function owner() external view returns (address);\n\n function root_factory() external view returns (address);\n\n function root_implementation() external view returns (address);\n\n function set_call_proxy(address _new_call_proxy) external;\n\n function set_crv(address _crv) external;\n\n function set_implementation(address _implementation) external;\n\n function set_manager(address _new_manager) external;\n\n function set_mirrored(address _gauge, bool _mirrored) external;\n\n function set_root(address _factory, address _implementation) external;\n\n function set_voting_escrow(address _voting_escrow) external;\n\n function version() external view returns (string memory);\n\n function voting_escrow() external view returns (address);\n}\n" + }, + "contracts/interfaces/ICurveLiquidityGaugeV6.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface ICurveLiquidityGaugeV6 {\n event ApplyOwnership(address admin);\n event Approval(\n address indexed _owner,\n address indexed _spender,\n uint256 _value\n );\n event CommitOwnership(address admin);\n event Deposit(address indexed provider, uint256 value);\n event SetGaugeManager(address _gauge_manager);\n event Transfer(address indexed _from, address indexed _to, uint256 _value);\n event UpdateLiquidityLimit(\n address indexed user,\n uint256 original_balance,\n uint256 original_supply,\n uint256 working_balance,\n uint256 working_supply\n );\n event Withdraw(address indexed provider, uint256 value);\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n function add_reward(address _reward_token, address _distributor) external;\n\n function allowance(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function balanceOf(address arg0) external view returns (uint256);\n\n function claim_rewards() external;\n\n function claim_rewards(address _addr) external;\n\n function claim_rewards(address _addr, address _receiver) external;\n\n function claimable_reward(address _user, address _reward_token)\n external\n view\n returns (uint256);\n\n function claimable_tokens(address addr) external returns (uint256);\n\n function claimed_reward(address _addr, address _token)\n external\n view\n returns (uint256);\n\n function decimals() external view returns (uint256);\n\n function decreaseAllowance(address _spender, uint256 _subtracted_value)\n external\n returns (bool);\n\n function deposit(uint256 _value) external;\n\n function deposit(uint256 _value, address _addr) external;\n\n function deposit(\n uint256 _value,\n address _addr,\n bool _claim_rewards\n ) external;\n\n function deposit_reward_token(address _reward_token, uint256 _amount)\n external;\n\n function deposit_reward_token(\n address _reward_token,\n uint256 _amount,\n uint256 _epoch\n ) external;\n\n function factory() external view returns (address);\n\n function future_epoch_time() external view returns (uint256);\n\n function increaseAllowance(address _spender, uint256 _added_value)\n external\n returns (bool);\n\n function inflation_rate() external view returns (uint256);\n\n function integrate_checkpoint() external view returns (uint256);\n\n function integrate_checkpoint_of(address arg0)\n external\n view\n returns (uint256);\n\n function integrate_fraction(address arg0) external view returns (uint256);\n\n function integrate_inv_supply(uint256 arg0) external view returns (uint256);\n\n function integrate_inv_supply_of(address arg0)\n external\n view\n returns (uint256);\n\n function is_killed() external view returns (bool);\n\n function kick(address addr) external;\n\n function lp_token() external view returns (address);\n\n function manager() external view returns (address);\n\n function name() external view returns (string memory);\n\n function nonces(address arg0) external view returns (uint256);\n\n function period() external view returns (int128);\n\n function period_timestamp(uint256 arg0) external view returns (uint256);\n\n function permit(\n address _owner,\n address _spender,\n uint256 _value,\n uint256 _deadline,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) external returns (bool);\n\n function reward_count() external view returns (uint256);\n\n function reward_integral_for(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function reward_tokens(uint256 arg0) external view returns (address);\n\n function rewards_receiver(address arg0) external view returns (address);\n\n function salt() external view returns (bytes32);\n\n function set_gauge_manager(address _gauge_manager) external;\n\n function set_killed(bool _is_killed) external;\n\n function set_reward_distributor(address _reward_token, address _distributor)\n external;\n\n function set_rewards_receiver(address _receiver) external;\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function user_checkpoint(address addr) external returns (bool);\n\n function version() external view returns (string memory);\n\n function withdraw(uint256 _value) external;\n\n function withdraw(uint256 _value, bool _claim_rewards) external;\n\n function working_balances(address arg0) external view returns (uint256);\n\n function working_supply() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/ICurveMinter.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface ICurveMinter {\n event Minted(address indexed recipient, address gauge, uint256 minted);\n\n function allowed_to_mint_for(address arg0, address arg1)\n external\n view\n returns (bool);\n\n function controller() external view returns (address);\n\n function mint(address gauge_addr) external;\n\n function mint_for(address gauge_addr, address _for) external;\n\n function mint_many(address[8] memory gauge_addrs) external;\n\n function minted(address arg0, address arg1) external view returns (uint256);\n\n function toggle_approve_mint(address minting_user) external;\n\n function token() external view returns (address);\n}\n" + }, + "contracts/interfaces/ICurveStableSwapNG.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface ICurveStableSwapNG {\n event AddLiquidity(\n address indexed provider,\n uint256[] token_amounts,\n uint256[] fees,\n uint256 invariant,\n uint256 token_supply\n );\n event ApplyNewFee(uint256 fee, uint256 offpeg_fee_multiplier);\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n event RampA(\n uint256 old_A,\n uint256 new_A,\n uint256 initial_time,\n uint256 future_time\n );\n event RemoveLiquidity(\n address indexed provider,\n uint256[] token_amounts,\n uint256[] fees,\n uint256 token_supply\n );\n event RemoveLiquidityImbalance(\n address indexed provider,\n uint256[] token_amounts,\n uint256[] fees,\n uint256 invariant,\n uint256 token_supply\n );\n event RemoveLiquidityOne(\n address indexed provider,\n int128 token_id,\n uint256 token_amount,\n uint256 coin_amount,\n uint256 token_supply\n );\n event SetNewMATime(uint256 ma_exp_time, uint256 D_ma_time);\n event StopRampA(uint256 A, uint256 t);\n event TokenExchange(\n address indexed buyer,\n int128 sold_id,\n uint256 tokens_sold,\n int128 bought_id,\n uint256 tokens_bought\n );\n event TokenExchangeUnderlying(\n address indexed buyer,\n int128 sold_id,\n uint256 tokens_sold,\n int128 bought_id,\n uint256 tokens_bought\n );\n event Transfer(\n address indexed sender,\n address indexed receiver,\n uint256 value\n );\n\n function A() external view returns (uint256);\n\n function A_precise() external view returns (uint256);\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n function D_ma_time() external view returns (uint256);\n\n function D_oracle() external view returns (uint256);\n\n function N_COINS() external view returns (uint256);\n\n function add_liquidity(uint256[] memory _amounts, uint256 _min_mint_amount)\n external\n returns (uint256);\n\n function add_liquidity(\n uint256[] memory _amounts,\n uint256 _min_mint_amount,\n address _receiver\n ) external returns (uint256);\n\n function admin_balances(uint256 arg0) external view returns (uint256);\n\n function admin_fee() external view returns (uint256);\n\n function allowance(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function balanceOf(address arg0) external view returns (uint256);\n\n function balances(uint256 i) external view returns (uint256);\n\n function calc_token_amount(uint256[] memory _amounts, bool _is_deposit)\n external\n view\n returns (uint256);\n\n function calc_withdraw_one_coin(uint256 _burn_amount, int128 i)\n external\n view\n returns (uint256);\n\n function coins(uint256 arg0) external view returns (address);\n\n function decimals() external view returns (uint8);\n\n function dynamic_fee(int128 i, int128 j) external view returns (uint256);\n\n function ema_price(uint256 i) external view returns (uint256);\n\n function exchange(\n int128 i,\n int128 j,\n uint256 _dx,\n uint256 _min_dy\n ) external returns (uint256);\n\n function exchange(\n int128 i,\n int128 j,\n uint256 _dx,\n uint256 _min_dy,\n address _receiver\n ) external returns (uint256);\n\n function exchange_received(\n int128 i,\n int128 j,\n uint256 _dx,\n uint256 _min_dy\n ) external returns (uint256);\n\n function exchange_received(\n int128 i,\n int128 j,\n uint256 _dx,\n uint256 _min_dy,\n address _receiver\n ) external returns (uint256);\n\n function fee() external view returns (uint256);\n\n function future_A() external view returns (uint256);\n\n function future_A_time() external view returns (uint256);\n\n function get_balances() external view returns (uint256[] memory);\n\n function get_dx(\n int128 i,\n int128 j,\n uint256 dy\n ) external view returns (uint256);\n\n function get_dy(\n int128 i,\n int128 j,\n uint256 dx\n ) external view returns (uint256);\n\n function get_p(uint256 i) external view returns (uint256);\n\n function get_virtual_price() external view returns (uint256);\n\n function initial_A() external view returns (uint256);\n\n function initial_A_time() external view returns (uint256);\n\n function last_price(uint256 i) external view returns (uint256);\n\n function ma_exp_time() external view returns (uint256);\n\n function ma_last_time() external view returns (uint256);\n\n function name() external view returns (string memory);\n\n function nonces(address arg0) external view returns (uint256);\n\n function offpeg_fee_multiplier() external view returns (uint256);\n\n function permit(\n address _owner,\n address _spender,\n uint256 _value,\n uint256 _deadline,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) external returns (bool);\n\n function price_oracle(uint256 i) external view returns (uint256);\n\n function ramp_A(uint256 _future_A, uint256 _future_time) external;\n\n function remove_liquidity(\n uint256 _burn_amount,\n uint256[] memory _min_amounts\n ) external returns (uint256[] memory);\n\n function remove_liquidity(\n uint256 _burn_amount,\n uint256[] memory _min_amounts,\n address _receiver\n ) external returns (uint256[] memory);\n\n function remove_liquidity(\n uint256 _burn_amount,\n uint256[] memory _min_amounts,\n address _receiver,\n bool _claim_admin_fees\n ) external returns (uint256[] memory);\n\n function remove_liquidity_imbalance(\n uint256[] memory _amounts,\n uint256 _max_burn_amount\n ) external returns (uint256);\n\n function remove_liquidity_imbalance(\n uint256[] memory _amounts,\n uint256 _max_burn_amount,\n address _receiver\n ) external returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _burn_amount,\n int128 i,\n uint256 _min_received\n ) external returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _burn_amount,\n int128 i,\n uint256 _min_received,\n address _receiver\n ) external returns (uint256);\n\n function salt() external view returns (bytes32);\n\n function set_ma_exp_time(uint256 _ma_exp_time, uint256 _D_ma_time) external;\n\n function set_new_fee(uint256 _new_fee, uint256 _new_offpeg_fee_multiplier)\n external;\n\n function stop_ramp_A() external;\n\n function stored_rates() external view returns (uint256[] memory);\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function version() external view returns (string memory);\n\n function withdraw_admin_fees() external;\n}\n" + }, + "contracts/interfaces/ICurveXChainLiquidityGauge.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface ICurveXChainLiquidityGauge {\n event Approval(\n address indexed _owner,\n address indexed _spender,\n uint256 _value\n );\n event Deposit(address indexed provider, uint256 value);\n event SetGaugeManager(address _gauge_manager);\n event Transfer(address indexed _from, address indexed _to, uint256 _value);\n event UpdateLiquidityLimit(\n address indexed user,\n uint256 original_balance,\n uint256 original_supply,\n uint256 working_balance,\n uint256 working_supply\n );\n event Withdraw(address indexed provider, uint256 value);\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n function add_reward(address _reward_token, address _distributor) external;\n\n function allowance(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function balanceOf(address arg0) external view returns (uint256);\n\n function claim_rewards() external;\n\n function claim_rewards(address _addr) external;\n\n function claim_rewards(address _addr, address _receiver) external;\n\n function claimable_reward(address _user, address _reward_token)\n external\n view\n returns (uint256);\n\n function claimable_tokens(address addr) external returns (uint256);\n\n function claimed_reward(address _addr, address _token)\n external\n view\n returns (uint256);\n\n function decimals() external view returns (uint256);\n\n function decreaseAllowance(address _spender, uint256 _subtracted_value)\n external\n returns (bool);\n\n function deposit(uint256 _value) external;\n\n function deposit(uint256 _value, address _addr) external;\n\n function deposit(\n uint256 _value,\n address _addr,\n bool _claim_rewards\n ) external;\n\n function deposit_reward_token(address _reward_token, uint256 _amount)\n external;\n\n function deposit_reward_token(\n address _reward_token,\n uint256 _amount,\n uint256 _epoch\n ) external;\n\n function factory() external view returns (address);\n\n function increaseAllowance(address _spender, uint256 _added_value)\n external\n returns (bool);\n\n function inflation_rate(uint256 arg0) external view returns (uint256);\n\n function initialize(\n address _lp_token,\n address _root,\n address _manager\n ) external;\n\n function integrate_checkpoint() external view returns (uint256);\n\n function integrate_checkpoint_of(address arg0)\n external\n view\n returns (uint256);\n\n function integrate_fraction(address arg0) external view returns (uint256);\n\n function integrate_inv_supply(int128 arg0) external view returns (uint256);\n\n function integrate_inv_supply_of(address arg0)\n external\n view\n returns (uint256);\n\n function is_killed() external view returns (bool);\n\n function lp_token() external view returns (address);\n\n function manager() external view returns (address);\n\n function name() external view returns (string memory);\n\n function nonces(address arg0) external view returns (uint256);\n\n function period() external view returns (int128);\n\n function period_timestamp(int128 arg0) external view returns (uint256);\n\n function permit(\n address _owner,\n address _spender,\n uint256 _value,\n uint256 _deadline,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) external returns (bool);\n\n function recover_remaining(address _reward_token) external;\n\n function reward_count() external view returns (uint256);\n\n function reward_integral_for(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function reward_remaining(address arg0) external view returns (uint256);\n\n function reward_tokens(uint256 arg0) external view returns (address);\n\n function rewards_receiver(address arg0) external view returns (address);\n\n function root_gauge() external view returns (address);\n\n function set_gauge_manager(address _gauge_manager) external;\n\n function set_killed(bool _is_killed) external;\n\n function set_manager(address _gauge_manager) external;\n\n function set_reward_distributor(address _reward_token, address _distributor)\n external;\n\n function set_rewards_receiver(address _receiver) external;\n\n function set_root_gauge(address _root) external;\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function update_voting_escrow() external;\n\n function user_checkpoint(address addr) external returns (bool);\n\n function version() external view returns (string memory);\n\n function voting_escrow() external view returns (address);\n\n function withdraw(uint256 _value) external;\n\n function withdraw(uint256 _value, bool _claim_rewards) external;\n\n function withdraw(\n uint256 _value,\n bool _claim_rewards,\n address _receiver\n ) external;\n\n function working_balances(address arg0) external view returns (uint256);\n\n function working_supply() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IDepositContract.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IDepositContract {\n /// @notice A processed deposit event.\n event DepositEvent(\n bytes pubkey,\n bytes withdrawal_credentials,\n bytes amount,\n bytes signature,\n bytes index\n );\n\n /// @notice Submit a Phase 0 DepositData object.\n /// @param pubkey A BLS12-381 public key.\n /// @param withdrawal_credentials Commitment to a public key for withdrawals.\n /// @param signature A BLS12-381 signature.\n /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.\n /// Used as a protection against malformed input.\n function deposit(\n bytes calldata pubkey,\n bytes calldata withdrawal_credentials,\n bytes calldata signature,\n bytes32 deposit_data_root\n ) external payable;\n\n /// @notice Query the current deposit root hash.\n /// @return The deposit root hash.\n function get_deposit_root() external view returns (bytes32);\n\n /// @notice Query the current deposit count.\n /// @return The deposit count encoded as a little endian 64-bit number.\n function get_deposit_count() external view returns (bytes memory);\n}\n" + }, + "contracts/interfaces/IMerkl.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IDistributor {\n event Claimed(address indexed user, address indexed token, uint256 amount);\n\n function claim(\n address[] calldata users,\n address[] calldata tokens,\n uint256[] calldata amounts,\n bytes32[][] calldata proofs\n ) external;\n}\n" + }, + "contracts/interfaces/IMockVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IVault } from \"./IVault.sol\";\n\ninterface IMockVault is IVault {\n function outstandingWithdrawalsAmount() external view returns (uint256);\n\n function wethAvailable() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IOracle.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IOracle {\n /**\n * @dev returns the asset price in USD, in 8 decimal digits.\n *\n * The version of priceProvider deployed for OETH has 18 decimal digits\n */\n function price(address asset) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IOUSD.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IOUSD {\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n event GovernorshipTransferred(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n event PendingGovernorshipTransfer(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n event TotalSupplyUpdatedHighres(\n uint256 totalSupply,\n uint256 rebasingCredits,\n uint256 rebasingCreditsPerToken\n );\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n function _totalSupply() external view returns (uint256);\n\n function allowance(address _owner, address _spender)\n external\n view\n returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function balanceOf(address _account) external view returns (uint256);\n\n function burn(address account, uint256 amount) external;\n\n function changeSupply(uint256 _newTotalSupply) external;\n\n function claimGovernance() external;\n\n function creditsBalanceOf(address _account)\n external\n view\n returns (uint256, uint256);\n\n function creditsBalanceOfHighres(address _account)\n external\n view\n returns (\n uint256,\n uint256,\n bool\n );\n\n function decimals() external view returns (uint8);\n\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\n external\n returns (bool);\n\n function governor() external view returns (address);\n\n function increaseAllowance(address _spender, uint256 _addedValue)\n external\n returns (bool);\n\n function initialize(\n string memory _nameArg,\n string memory _symbolArg,\n address _vaultAddress\n ) external;\n\n function isGovernor() external view returns (bool);\n\n function isUpgraded(address) external view returns (uint256);\n\n function mint(address _account, uint256 _amount) external;\n\n function name() external view returns (string memory);\n\n function nonRebasingCreditsPerToken(address)\n external\n view\n returns (uint256);\n\n function nonRebasingSupply() external view returns (uint256);\n\n function rebaseOptIn() external;\n\n function rebaseOptOut() external;\n\n function rebaseState(address) external view returns (uint8);\n\n function rebasingCredits() external view returns (uint256);\n\n function rebasingCreditsHighres() external view returns (uint256);\n\n function rebasingCreditsPerToken() external view returns (uint256);\n\n function rebasingCreditsPerTokenHighres() external view returns (uint256);\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function transferGovernance(address _newGovernor) external;\n\n function vaultAddress() external view returns (address);\n}\n" + }, + "contracts/interfaces/ISafe.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface ISafe {\n function execTransactionFromModule(\n address,\n uint256,\n bytes memory,\n uint8\n ) external returns (bool);\n}\n" + }, + "contracts/interfaces/ISSVNetwork.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nstruct Cluster {\n uint32 validatorCount;\n uint64 networkFeeIndex;\n uint64 index;\n bool active;\n uint256 balance;\n}\n\ninterface ISSVNetwork {\n /**********/\n /* Errors */\n /**********/\n\n error CallerNotOwner(); // 0x5cd83192\n error CallerNotWhitelisted(); // 0x8c6e5d71\n error FeeTooLow(); // 0x732f9413\n error FeeExceedsIncreaseLimit(); // 0x958065d9\n error NoFeeDeclared(); // 0x1d226c30\n error ApprovalNotWithinTimeframe(); // 0x97e4b518\n error OperatorDoesNotExist(); // 0x961e3e8c\n error InsufficientBalance(); // 0xf4d678b8\n error ValidatorDoesNotExist(); // 0xe51315d2\n error ClusterNotLiquidatable(); // 0x60300a8d\n error InvalidPublicKeyLength(); // 0x637297a4\n error InvalidOperatorIdsLength(); // 0x38186224\n error ClusterAlreadyEnabled(); // 0x3babafd2\n error ClusterIsLiquidated(); // 0x95a0cf33\n error ClusterDoesNotExists(); // 0x185e2b16\n error IncorrectClusterState(); // 0x12e04c87\n error UnsortedOperatorsList(); // 0xdd020e25\n error NewBlockPeriodIsBelowMinimum(); // 0x6e6c9cac\n error ExceedValidatorLimit(); // 0x6df5ab76\n error TokenTransferFailed(); // 0x045c4b02\n error SameFeeChangeNotAllowed(); // 0xc81272f8\n error FeeIncreaseNotAllowed(); // 0x410a2b6c\n error NotAuthorized(); // 0xea8e4eb5\n error OperatorsListNotUnique(); // 0xa5a1ff5d\n error OperatorAlreadyExists(); // 0x289c9494\n error TargetModuleDoesNotExist(); // 0x8f9195fb\n error MaxValueExceeded(); // 0x91aa3017\n error FeeTooHigh(); // 0xcd4e6167\n error PublicKeysSharesLengthMismatch(); // 0x9ad467b8\n error IncorrectValidatorStateWithData(bytes publicKey); // 0x89307938\n error ValidatorAlreadyExistsWithData(bytes publicKey); // 0x388e7999\n error EmptyPublicKeysList(); // df83e679\n\n // legacy errors\n error ValidatorAlreadyExists(); // 0x8d09a73e\n error IncorrectValidatorState(); // 0x2feda3c1\n\n event AdminChanged(address previousAdmin, address newAdmin);\n event BeaconUpgraded(address indexed beacon);\n event ClusterDeposited(\n address indexed owner,\n uint64[] operatorIds,\n uint256 value,\n Cluster cluster\n );\n event ClusterLiquidated(\n address indexed owner,\n uint64[] operatorIds,\n Cluster cluster\n );\n event ClusterReactivated(\n address indexed owner,\n uint64[] operatorIds,\n Cluster cluster\n );\n event ClusterWithdrawn(\n address indexed owner,\n uint64[] operatorIds,\n uint256 value,\n Cluster cluster\n );\n event DeclareOperatorFeePeriodUpdated(uint64 value);\n event ExecuteOperatorFeePeriodUpdated(uint64 value);\n event FeeRecipientAddressUpdated(\n address indexed owner,\n address recipientAddress\n );\n event Initialized(uint8 version);\n event LiquidationThresholdPeriodUpdated(uint64 value);\n event MinimumLiquidationCollateralUpdated(uint256 value);\n event NetworkEarningsWithdrawn(uint256 value, address recipient);\n event NetworkFeeUpdated(uint256 oldFee, uint256 newFee);\n event OperatorAdded(\n uint64 indexed operatorId,\n address indexed owner,\n bytes publicKey,\n uint256 fee\n );\n event OperatorFeeDeclarationCancelled(\n address indexed owner,\n uint64 indexed operatorId\n );\n event OperatorFeeDeclared(\n address indexed owner,\n uint64 indexed operatorId,\n uint256 blockNumber,\n uint256 fee\n );\n event OperatorFeeExecuted(\n address indexed owner,\n uint64 indexed operatorId,\n uint256 blockNumber,\n uint256 fee\n );\n event OperatorFeeIncreaseLimitUpdated(uint64 value);\n event OperatorMaximumFeeUpdated(uint64 maxFee);\n event OperatorRemoved(uint64 indexed operatorId);\n event OperatorWhitelistUpdated(\n uint64 indexed operatorId,\n address whitelisted\n );\n event OperatorWithdrawn(\n address indexed owner,\n uint64 indexed operatorId,\n uint256 value\n );\n event OwnershipTransferStarted(\n address indexed previousOwner,\n address indexed newOwner\n );\n event OwnershipTransferred(\n address indexed previousOwner,\n address indexed newOwner\n );\n event Upgraded(address indexed implementation);\n event ValidatorAdded(\n address indexed owner,\n uint64[] operatorIds,\n bytes publicKey,\n bytes shares,\n Cluster cluster\n );\n event ValidatorExited(\n address indexed owner,\n uint64[] operatorIds,\n bytes publicKey\n );\n event ValidatorRemoved(\n address indexed owner,\n uint64[] operatorIds,\n bytes publicKey,\n Cluster cluster\n );\n\n fallback() external;\n\n function acceptOwnership() external;\n\n function cancelDeclaredOperatorFee(uint64 operatorId) external;\n\n function declareOperatorFee(uint64 operatorId, uint256 fee) external;\n\n function deposit(\n address clusterOwner,\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function executeOperatorFee(uint64 operatorId) external;\n\n function exitValidator(bytes memory publicKey, uint64[] memory operatorIds)\n external;\n\n function bulkExitValidator(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds\n ) external;\n\n function getVersion() external pure returns (string memory version);\n\n function initialize(\n address token_,\n address ssvOperators_,\n address ssvClusters_,\n address ssvDAO_,\n address ssvViews_,\n uint64 minimumBlocksBeforeLiquidation_,\n uint256 minimumLiquidationCollateral_,\n uint32 validatorsPerOperatorLimit_,\n uint64 declareOperatorFeePeriod_,\n uint64 executeOperatorFeePeriod_,\n uint64 operatorMaxFeeIncrease_\n ) external;\n\n function liquidate(\n address clusterOwner,\n uint64[] memory operatorIds,\n Cluster memory cluster\n ) external;\n\n function owner() external view returns (address);\n\n function pendingOwner() external view returns (address);\n\n function proxiableUUID() external view returns (bytes32);\n\n function reactivate(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function reduceOperatorFee(uint64 operatorId, uint256 fee) external;\n\n function registerOperator(bytes memory publicKey, uint256 fee)\n external\n returns (uint64 id);\n\n function registerValidator(\n bytes memory publicKey,\n uint64[] memory operatorIds,\n bytes memory sharesData,\n Cluster memory cluster\n ) external payable;\n\n function bulkRegisterValidator(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds,\n bytes[] calldata sharesData,\n Cluster memory cluster\n ) external payable;\n\n function migrateClusterToETH(\n uint64[] calldata operatorIds,\n Cluster memory cluster\n ) external payable;\n\n function removeOperator(uint64 operatorId) external;\n\n function removeValidator(\n bytes memory publicKey,\n uint64[] memory operatorIds,\n Cluster memory cluster\n ) external;\n\n function bulkRemoveValidator(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds,\n Cluster memory cluster\n ) external;\n\n function renounceOwnership() external;\n\n function setFeeRecipientAddress(address recipientAddress) external;\n\n function setOperatorWhitelist(uint64 operatorId, address whitelisted)\n external;\n\n function transferOwnership(address newOwner) external;\n\n function updateDeclareOperatorFeePeriod(uint64 timeInSeconds) external;\n\n function updateExecuteOperatorFeePeriod(uint64 timeInSeconds) external;\n\n function updateLiquidationThresholdPeriod(uint64 blocks) external;\n\n function updateMaximumOperatorFee(uint64 maxFee) external;\n\n function updateMinimumLiquidationCollateral(uint256 amount) external;\n\n function updateModule(uint8 moduleId, address moduleAddress) external;\n\n function updateNetworkFee(uint256 fee) external;\n\n function updateOperatorFeeIncreaseLimit(uint64 percentage) external;\n\n function upgradeTo(address newImplementation) external;\n\n function upgradeToAndCall(address newImplementation, bytes memory data)\n external\n payable;\n\n function withdraw(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function withdrawAllOperatorEarnings(uint64 operatorId) external;\n\n function withdrawNetworkEarnings(uint256 amount) external;\n\n function withdrawOperatorEarnings(uint64 operatorId, uint256 amount)\n external;\n}\n" + }, + "contracts/interfaces/IStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\n */\ninterface IStrategy {\n /**\n * @dev Deposit the given asset to platform\n * @param _asset asset address\n * @param _amount Amount to deposit\n */\n function deposit(address _asset, uint256 _amount) external;\n\n /**\n * @dev Deposit the entire balance of all supported assets in the Strategy\n * to the platform\n */\n function depositAll() external;\n\n /**\n * @dev Withdraw given asset from Lending platform\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external;\n\n /**\n * @dev Liquidate all assets in strategy and return them to Vault.\n */\n function withdrawAll() external;\n\n /**\n * @dev Returns the current balance of the given asset.\n */\n function checkBalance(address _asset)\n external\n view\n returns (uint256 balance);\n\n /**\n * @dev Returns bool indicating whether strategy supports asset.\n */\n function supportsAsset(address _asset) external view returns (bool);\n\n /**\n * @dev Collect reward tokens from the Strategy.\n */\n function collectRewardTokens() external;\n\n /**\n * @dev The address array of the reward tokens for the Strategy.\n */\n function getRewardTokenAddresses() external view returns (address[] memory);\n\n function harvesterAddress() external view returns (address);\n\n function transferToken(address token, uint256 amount) external;\n\n function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\n external;\n}\n" + }, + "contracts/interfaces/IVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultStorage } from \"../vault/VaultStorage.sol\";\n\ninterface IVault {\n // slither-disable-start constable-states\n\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\n event StrategyApproved(address _addr);\n event StrategyRemoved(address _addr);\n event Mint(address _addr, uint256 _value);\n event Redeem(address _addr, uint256 _value);\n event CapitalPaused();\n event CapitalUnpaused();\n event DefaultStrategyUpdated(address _strategy);\n event RebasePaused();\n event RebaseUnpaused();\n event VaultBufferUpdated(uint256 _vaultBuffer);\n event AllocateThresholdUpdated(uint256 _threshold);\n event StrategistUpdated(address _address);\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\n event TrusteeFeeBpsChanged(uint256 _basis);\n event TrusteeAddressChanged(address _address);\n event StrategyAddedToMintWhitelist(address indexed strategy);\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\n event DripDurationChanged(uint256 dripDuration);\n event WithdrawalRequested(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount,\n uint256 _queued\n );\n event WithdrawalClaimed(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount\n );\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\n\n // Governable.sol\n function transferGovernance(address _newGovernor) external;\n\n function claimGovernance() external;\n\n function governor() external view returns (address);\n\n // VaultAdmin.sol\n function setVaultBuffer(uint256 _vaultBuffer) external;\n\n function vaultBuffer() external view returns (uint256);\n\n function setAutoAllocateThreshold(uint256 _threshold) external;\n\n function autoAllocateThreshold() external view returns (uint256);\n\n function setStrategistAddr(address _address) external;\n\n function strategistAddr() external view returns (address);\n\n function setOperatorAddr(address _operator) external;\n\n function operatorAddr() external view returns (address);\n\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\n\n function maxSupplyDiff() external view returns (uint256);\n\n function setTrusteeAddress(address _address) external;\n\n function trusteeAddress() external view returns (address);\n\n function setTrusteeFeeBps(uint256 _basis) external;\n\n function trusteeFeeBps() external view returns (uint256);\n\n function approveStrategy(address _addr) external;\n\n function removeStrategy(address _addr) external;\n\n function setDefaultStrategy(address _strategy) external;\n\n function defaultStrategy() external view returns (address);\n\n function pauseRebase() external;\n\n function unpauseRebase() external;\n\n function rebasePaused() external view returns (bool);\n\n function pauseCapital() external;\n\n function unpauseCapital() external;\n\n function capitalPaused() external view returns (bool);\n\n function transferToken(address _asset, uint256 _amount) external;\n\n function withdrawAllFromStrategy(address _strategyAddr) external;\n\n function withdrawAllFromStrategies() external;\n\n function withdrawFromStrategy(\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external;\n\n function depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external;\n\n // VaultCore.sol\n function mint(uint256 _amount) external;\n\n function mintForStrategy(uint256 _amount) external;\n\n function burnForStrategy(uint256 _amount) external;\n\n function allocate() external;\n\n function rebase() external;\n\n function totalValue() external view returns (uint256 value);\n\n function checkBalance(address _asset) external view returns (uint256);\n\n function getAssetCount() external view returns (uint256);\n\n function getAllAssets() external view returns (address[] memory);\n\n function getStrategyCount() external view returns (uint256);\n\n function getAllStrategies() external view returns (address[] memory);\n\n function strategies(address _addr)\n external\n view\n returns (VaultStorage.Strategy memory);\n\n /// @notice Deprecated: use `asset()` instead.\n function isSupportedAsset(address _asset) external view returns (bool);\n\n function asset() external view returns (address);\n\n function oToken() external view returns (address);\n\n function initialize(address) external;\n\n function addWithdrawalQueueLiquidity() external;\n\n function requestWithdrawal(uint256 _amount)\n external\n returns (uint256 requestId, uint256 queued);\n\n function claimWithdrawal(uint256 requestId)\n external\n returns (uint256 amount);\n\n function claimWithdrawals(uint256[] memory requestIds)\n external\n returns (uint256[] memory amounts, uint256 totalAmount);\n\n function withdrawalQueueMetadata()\n external\n view\n returns (VaultStorage.WithdrawalQueueMetadata memory);\n\n function withdrawalRequests(uint256 requestId)\n external\n view\n returns (VaultStorage.WithdrawalRequest memory);\n\n function addStrategyToMintWhitelist(address strategyAddr) external;\n\n function removeStrategyFromMintWhitelist(address strategyAddr) external;\n\n function isMintWhitelistedStrategy(address strategyAddr)\n external\n view\n returns (bool);\n\n function withdrawalClaimDelay() external view returns (uint256);\n\n function setWithdrawalClaimDelay(uint256 newDelay) external;\n\n function lastRebase() external view returns (uint64);\n\n function dripDuration() external view returns (uint64);\n\n function setDripDuration(uint256 _dripDuration) external;\n\n function rebasePerSecondMax() external view returns (uint64);\n\n function setRebaseRateMax(uint256 yearlyApr) external;\n\n function rebasePerSecondTarget() external view returns (uint64);\n\n function previewYield() external view returns (uint256 yield);\n\n // slither-disable-end constable-states\n}\n" + }, + "contracts/interfaces/IWETH9.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IWETH9 {\n event Approval(address indexed src, address indexed guy, uint256 wad);\n event Deposit(address indexed dst, uint256 wad);\n event Transfer(address indexed src, address indexed dst, uint256 wad);\n event Withdrawal(address indexed src, uint256 wad);\n\n function allowance(address, address) external view returns (uint256);\n\n function approve(address guy, uint256 wad) external returns (bool);\n\n function balanceOf(address) external view returns (uint256);\n\n function decimals() external view returns (uint8);\n\n function deposit() external payable;\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address dst, uint256 wad) external returns (bool);\n\n function transferFrom(\n address src,\n address dst,\n uint256 wad\n ) external returns (bool);\n\n function withdraw(uint256 wad) external;\n}\n" + }, + "contracts/interfaces/morpho/IMorphoV2Adapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IMorphoV2Adapter {\n // address of the underlying vault\n function morphoVaultV1() external view returns (address);\n\n // address of the parent Morpho V2 vault\n function parentVault() external view returns (address);\n}\n" + }, + "contracts/interfaces/morpho/IVaultV2.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC4626 } from \"../../../lib/openzeppelin/interfaces/IERC4626.sol\";\n\ninterface IVaultV2 is IERC4626 {\n function liquidityAdapter() external view returns (address);\n}\n" + }, + "contracts/interfaces/sonic/ISFC.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\n\n/**\n * @title Special Fee Contract for Sonic network\n * @notice The SFC maintains a list of validators and delegators and distributes rewards to them.\n * @custom:security-contact security@fantom.foundation\n */\ninterface ISFC {\n error StakeIsFullySlashed();\n\n event CreatedValidator(\n uint256 indexed validatorID,\n address indexed auth,\n uint256 createdEpoch,\n uint256 createdTime\n );\n event Delegated(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 amount\n );\n event Undelegated(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 indexed wrID,\n uint256 amount\n );\n event Withdrawn(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 indexed wrID,\n uint256 amount,\n uint256 penalty\n );\n event ClaimedRewards(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 rewards\n );\n event RestakedRewards(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 rewards\n );\n event BurntFTM(uint256 amount);\n event UpdatedSlashingRefundRatio(\n uint256 indexed validatorID,\n uint256 refundRatio\n );\n event RefundedSlashedLegacyDelegation(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 amount\n );\n\n event DeactivatedValidator(\n uint256 indexed validatorID,\n uint256 deactivatedEpoch,\n uint256 deactivatedTime\n );\n event ChangedValidatorStatus(uint256 indexed validatorID, uint256 status);\n event AnnouncedRedirection(address indexed from, address indexed to);\n\n function currentSealedEpoch() external view returns (uint256);\n\n function getEpochSnapshot(uint256 epoch)\n external\n view\n returns (\n uint256 endTime,\n uint256 endBlock,\n uint256 epochFee,\n uint256 baseRewardPerSecond,\n uint256 totalStake,\n uint256 totalSupply\n );\n\n function getStake(address delegator, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function getValidator(uint256 validatorID)\n external\n view\n returns (\n uint256 status,\n uint256 receivedStake,\n address auth,\n uint256 createdEpoch,\n uint256 createdTime,\n uint256 deactivatedTime,\n uint256 deactivatedEpoch\n );\n\n function getValidatorID(address auth) external view returns (uint256);\n\n function getValidatorPubkey(uint256 validatorID)\n external\n view\n returns (bytes memory);\n\n function pubkeyAddressvalidatorID(address pubkeyAddress)\n external\n view\n returns (uint256);\n\n function getWithdrawalRequest(\n address delegator,\n uint256 validatorID,\n uint256 wrID\n )\n external\n view\n returns (\n uint256 epoch,\n uint256 time,\n uint256 amount\n );\n\n function isOwner() external view returns (bool);\n\n function lastValidatorID() external view returns (uint256);\n\n function minGasPrice() external view returns (uint256);\n\n function owner() external view returns (address);\n\n function renounceOwnership() external;\n\n function slashingRefundRatio(uint256 validatorID)\n external\n view\n returns (uint256);\n\n function stashedRewardsUntilEpoch(address delegator, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function totalActiveStake() external view returns (uint256);\n\n function totalStake() external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function transferOwnership(address newOwner) external;\n\n function treasuryAddress() external view returns (address);\n\n function version() external pure returns (bytes3);\n\n function currentEpoch() external view returns (uint256);\n\n function updateConstsAddress(address v) external;\n\n function constsAddress() external view returns (address);\n\n function getEpochValidatorIDs(uint256 epoch)\n external\n view\n returns (uint256[] memory);\n\n function getEpochReceivedStake(uint256 epoch, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function getEpochAccumulatedRewardPerToken(\n uint256 epoch,\n uint256 validatorID\n ) external view returns (uint256);\n\n function getEpochAccumulatedUptime(uint256 epoch, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function getEpochAverageUptime(uint256 epoch, uint256 validatorID)\n external\n view\n returns (uint32);\n\n function getEpochAccumulatedOriginatedTxsFee(\n uint256 epoch,\n uint256 validatorID\n ) external view returns (uint256);\n\n function getEpochOfflineTime(uint256 epoch, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function getEpochOfflineBlocks(uint256 epoch, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function getEpochEndBlock(uint256 epoch) external view returns (uint256);\n\n function rewardsStash(address delegator, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function createValidator(bytes calldata pubkey) external payable;\n\n function getSelfStake(uint256 validatorID) external view returns (uint256);\n\n function delegate(uint256 validatorID) external payable;\n\n function undelegate(\n uint256 validatorID,\n uint256 wrID,\n uint256 amount\n ) external;\n\n function isSlashed(uint256 validatorID) external view returns (bool);\n\n function withdraw(uint256 validatorID, uint256 wrID) external;\n\n function deactivateValidator(uint256 validatorID, uint256 status) external;\n\n function pendingRewards(address delegator, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function stashRewards(address delegator, uint256 validatorID) external;\n\n function claimRewards(uint256 validatorID) external;\n\n function restakeRewards(uint256 validatorID) external;\n\n function updateSlashingRefundRatio(uint256 validatorID, uint256 refundRatio)\n external;\n\n function updateTreasuryAddress(address v) external;\n\n function burnFTM(uint256 amount) external;\n\n function sealEpoch(\n uint256[] calldata offlineTime,\n uint256[] calldata offlineBlocks,\n uint256[] calldata uptimes,\n uint256[] calldata originatedTxsFee\n ) external;\n\n function sealEpochValidators(uint256[] calldata nextValidatorIDs) external;\n\n function initialize(\n uint256 sealedEpoch,\n uint256 _totalSupply,\n address nodeDriver,\n address consts,\n address _owner\n ) external;\n\n function setGenesisValidator(\n address auth,\n uint256 validatorID,\n bytes calldata pubkey,\n uint256 createdTime\n ) external;\n\n function setGenesisDelegation(\n address delegator,\n uint256 validatorID,\n uint256 stake\n ) external;\n\n function updateStakeSubscriberAddress(address v) external;\n\n function stakeSubscriberAddress() external view returns (address);\n\n function setRedirectionAuthorizer(address v) external;\n\n function announceRedirection(address to) external;\n\n function initiateRedirection(address from, address to) external;\n\n function redirect(address to) external;\n}\n" + }, + "contracts/interfaces/sonic/IWrappedSonic.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IWrappedSonic {\n event Deposit(address indexed account, uint256 value);\n event Withdrawal(address indexed account, uint256 value);\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n\n function allowance(address owner, address spender)\n external\n view\n returns (uint256);\n\n function approve(address spender, uint256 value) external returns (bool);\n\n function balanceOf(address account) external view returns (uint256);\n\n function decimals() external view returns (uint8);\n\n function deposit() external payable;\n\n function depositFor(address account) external payable returns (bool);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address to, uint256 value) external returns (bool);\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external returns (bool);\n\n function withdraw(uint256 value) external;\n\n function withdrawTo(address account, uint256 value) external returns (bool);\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV2Router02.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IUniswapV2Router {\n function WETH() external pure returns (address);\n\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n\n function addLiquidity(\n address tokenA,\n address tokenB,\n uint256 amountADesired,\n uint256 amountBDesired,\n uint256 amountAMin,\n uint256 amountBMin,\n address to,\n uint256 deadline\n )\n external\n returns (\n uint256 amountA,\n uint256 amountB,\n uint256 liquidity\n );\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV3Router.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// -- Solididy v0.5.x compatible interface\ninterface IUniswapV3Router {\n struct ExactInputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n }\n\n /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path\n /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata\n /// @return amountOut The amount of the received token\n function exactInput(ExactInputParams calldata params)\n external\n payable\n returns (uint256 amountOut);\n}\n" + }, + "contracts/mocks/crosschain/CCTPMessageTransmitterMock.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ICCTPMessageTransmitter } from \"../../interfaces/cctp/ICCTP.sol\";\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { BytesHelper } from \"../../utils/BytesHelper.sol\";\nimport { AbstractCCTPIntegrator } from \"../../strategies/crosschain/AbstractCCTPIntegrator.sol\";\n\n/**\n * @title Mock conctract simulating the functionality of the CCTPTokenMessenger contract\n * for the porposes of unit testing.\n * @author Origin Protocol Inc\n */\n\ncontract CCTPMessageTransmitterMock is ICCTPMessageTransmitter {\n using BytesHelper for bytes;\n\n IERC20 public usdc;\n uint256 public nonce = 0;\n // Sender index in the burn message v2\n // Ref: https://github.com/circlefin/evm-cctp-contracts/blob/master/src/messages/v2/BurnMessageV2.sol\n uint8 constant BURN_MESSAGE_V2_MESSAGE_SENDER_INDEX = 100;\n uint8 constant BURN_MESSAGE_V2_HOOK_DATA_INDEX = 228;\n\n uint16 public messageFinality = 2000;\n address public messageSender;\n uint32 public sourceDomain = 4294967295; // 0xFFFFFFFF\n\n // Full message with header\n struct Message {\n uint32 version;\n uint32 sourceDomain;\n uint32 destinationDomain;\n bytes32 recipient;\n bytes32 messageHeaderRecipient;\n bytes32 sender;\n bytes32 destinationCaller;\n uint32 minFinalityThreshold;\n bool isTokenTransfer;\n uint256 tokenAmount;\n bytes messageBody;\n }\n\n Message[] public messages;\n // map of encoded messages to the corresponding message structs\n mapping(bytes32 => Message) public encodedMessages;\n\n constructor(address _usdc) {\n usdc = IERC20(_usdc);\n }\n\n // @dev for the porposes of unit tests queues the message to be mock-sent using\n // the cctp bridge.\n function sendMessage(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n uint32 minFinalityThreshold,\n bytes memory messageBody\n ) external virtual override {\n bytes32 nonceHash = keccak256(abi.encodePacked(nonce));\n nonce++;\n\n // If destination is mainnet, source is base and vice versa\n uint32 sourceDomain = destinationDomain == 0 ? 6 : 0;\n\n Message memory message = Message({\n version: 1,\n sourceDomain: sourceDomain,\n destinationDomain: destinationDomain,\n recipient: recipient,\n messageHeaderRecipient: recipient,\n sender: bytes32(uint256(uint160(msg.sender))),\n destinationCaller: destinationCaller,\n minFinalityThreshold: minFinalityThreshold,\n isTokenTransfer: false,\n tokenAmount: 0,\n messageBody: messageBody\n });\n\n messages.push(message);\n }\n\n // @dev for the porposes of unit tests queues the USDC burn/mint to be executed\n // using the cctp bridge.\n function sendTokenTransferMessage(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n uint32 minFinalityThreshold,\n uint256 tokenAmount,\n bytes memory messageBody\n ) external {\n bytes32 nonceHash = keccak256(abi.encodePacked(nonce));\n nonce++;\n\n // If destination is mainnet, source is base and vice versa\n uint32 sourceDomain = destinationDomain == 0 ? 6 : 0;\n\n Message memory message = Message({\n version: 1,\n sourceDomain: sourceDomain,\n destinationDomain: destinationDomain,\n recipient: recipient,\n messageHeaderRecipient: recipient,\n sender: bytes32(uint256(uint160(msg.sender))),\n destinationCaller: destinationCaller,\n minFinalityThreshold: minFinalityThreshold,\n isTokenTransfer: true,\n tokenAmount: tokenAmount,\n messageBody: messageBody\n });\n\n messages.push(message);\n }\n\n function receiveMessage(bytes memory message, bytes memory attestation)\n public\n virtual\n override\n returns (bool)\n {\n Message memory storedMsg = encodedMessages[keccak256(message)];\n AbstractCCTPIntegrator recipient = AbstractCCTPIntegrator(\n address(uint160(uint256(storedMsg.recipient)))\n );\n\n bytes32 sender = storedMsg.sender;\n bytes memory messageBody = storedMsg.messageBody;\n\n // Credit USDC in this step as it is done in the live cctp contracts\n if (storedMsg.isTokenTransfer) {\n usdc.transfer(address(recipient), storedMsg.tokenAmount);\n // override the sender with the one stored in the Burn message as the sender int he\n // message header is the TokenMessenger.\n sender = bytes32(\n uint256(\n uint160(\n storedMsg.messageBody.extractAddress(\n BURN_MESSAGE_V2_MESSAGE_SENDER_INDEX\n )\n )\n )\n );\n messageBody = storedMsg.messageBody.extractSlice(\n BURN_MESSAGE_V2_HOOK_DATA_INDEX,\n storedMsg.messageBody.length\n );\n } else {\n bytes32 overrideSenderBytes = bytes32(\n uint256(uint160(messageSender))\n );\n if (messageFinality >= 2000) {\n recipient.handleReceiveFinalizedMessage(\n sourceDomain == 4294967295\n ? storedMsg.sourceDomain\n : sourceDomain,\n messageSender == address(0) ? sender : overrideSenderBytes,\n messageFinality,\n messageBody\n );\n } else {\n recipient.handleReceiveUnfinalizedMessage(\n sourceDomain == 4294967295\n ? storedMsg.sourceDomain\n : sourceDomain,\n messageSender == address(0) ? sender : overrideSenderBytes,\n messageFinality,\n messageBody\n );\n }\n }\n\n return true;\n }\n\n function addMessage(Message memory storedMsg) external {\n messages.push(storedMsg);\n }\n\n function _encodeMessageHeader(\n uint32 version,\n uint32 sourceDomain,\n bytes32 sender,\n bytes32 recipient,\n bytes memory messageBody\n ) internal pure returns (bytes memory) {\n bytes memory header = abi.encodePacked(\n version, // 0-3\n sourceDomain, // 4-7\n bytes32(0), // 8-39 destinationDomain\n bytes4(0), // 40-43 nonce\n sender, // 44-75 sender\n recipient, // 76-107 recipient\n bytes32(0), // other stuff\n bytes8(0) // other stuff\n );\n return abi.encodePacked(header, messageBody);\n }\n\n function _removeFront() internal returns (Message memory) {\n require(messages.length > 0, \"No messages\");\n Message memory removed = messages[0];\n // Shift array\n for (uint256 i = 0; i < messages.length - 1; i++) {\n messages[i] = messages[i + 1];\n }\n messages.pop();\n return removed;\n }\n\n function _processMessage(Message memory storedMsg) internal {\n bytes memory encodedMessage = _encodeMessageHeader(\n storedMsg.version,\n storedMsg.sourceDomain,\n storedMsg.sender,\n storedMsg.messageHeaderRecipient,\n storedMsg.messageBody\n );\n\n encodedMessages[keccak256(encodedMessage)] = storedMsg;\n\n address recipient = address(uint160(uint256(storedMsg.recipient)));\n\n AbstractCCTPIntegrator(recipient).relay(encodedMessage, bytes(\"\"));\n }\n\n function _removeBack() internal returns (Message memory) {\n require(messages.length > 0, \"No messages\");\n Message memory last = messages[messages.length - 1];\n messages.pop();\n return last;\n }\n\n function messagesInQueue() external view returns (uint256) {\n return messages.length;\n }\n\n function processFrontOverrideHeader(bytes4 customHeader) external {\n Message memory storedMsg = _removeFront();\n\n bytes memory modifiedBody = abi.encodePacked(\n customHeader,\n storedMsg.messageBody.extractSlice(4, storedMsg.messageBody.length)\n );\n\n storedMsg.messageBody = modifiedBody;\n\n _processMessage(storedMsg);\n }\n\n function processFrontOverrideVersion(uint32 customVersion) external {\n Message memory storedMsg = _removeFront();\n storedMsg.version = customVersion;\n _processMessage(storedMsg);\n }\n\n function processFrontOverrideSender(address customSender) external {\n Message memory storedMsg = _removeFront();\n storedMsg.sender = bytes32(uint256(uint160(customSender)));\n _processMessage(storedMsg);\n }\n\n function processFrontOverrideRecipient(address customRecipient) external {\n Message memory storedMsg = _removeFront();\n storedMsg.messageHeaderRecipient = bytes32(\n uint256(uint160(customRecipient))\n );\n _processMessage(storedMsg);\n }\n\n function processFrontOverrideMessageBody(bytes memory customMessageBody)\n external\n {\n Message memory storedMsg = _removeFront();\n storedMsg.messageBody = customMessageBody;\n _processMessage(storedMsg);\n }\n\n function processFront() external {\n Message memory storedMsg = _removeFront();\n _processMessage(storedMsg);\n }\n\n function processBack() external {\n Message memory storedMsg = _removeBack();\n _processMessage(storedMsg);\n }\n\n function getMessagesLength() external view returns (uint256) {\n return messages.length;\n }\n\n function overrideMessageFinality(uint16 _finality) external {\n messageFinality = _finality;\n }\n\n function overrideSender(address _sender) external {\n messageSender = _sender;\n }\n\n function overrideSourceDomain(uint32 _sourceDomain) external {\n sourceDomain = _sourceDomain;\n }\n}\n" + }, + "contracts/mocks/crosschain/CCTPMessageTransmitterMock2.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IMessageHandlerV2 } from \"../../interfaces/cctp/ICCTP.sol\";\nimport { BytesHelper } from \"../../utils/BytesHelper.sol\";\nimport { CCTPMessageTransmitterMock } from \"./CCTPMessageTransmitterMock.sol\";\n\nuint8 constant SOURCE_DOMAIN_INDEX = 4;\nuint8 constant RECIPIENT_INDEX = 76;\nuint8 constant SENDER_INDEX = 44;\nuint8 constant MESSAGE_BODY_INDEX = 148;\n\n/**\n * @title Mock conctract simulating the functionality of the CCTPTokenMessenger contract\n * for the porposes of unit testing.\n * @author Origin Protocol Inc\n */\n\ncontract CCTPMessageTransmitterMock2 is CCTPMessageTransmitterMock {\n using BytesHelper for bytes;\n\n address public cctpTokenMessenger;\n uint32 public peerDomainId;\n\n event MessageReceivedInMockTransmitter(bytes message);\n event MessageSent(bytes message);\n\n constructor(address _usdc, uint32 _peerDomainId)\n CCTPMessageTransmitterMock(_usdc)\n {\n peerDomainId = _peerDomainId;\n }\n\n function setCCTPTokenMessenger(address _cctpTokenMessenger) external {\n cctpTokenMessenger = _cctpTokenMessenger;\n }\n\n function setPeerDomainId(uint32 _peerDomainId) external {\n peerDomainId = _peerDomainId;\n }\n\n function sendMessage(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n uint32 minFinalityThreshold,\n bytes memory messageBody\n ) external virtual override {\n bytes memory message = abi.encodePacked(\n uint32(1), // version\n destinationDomain == 0 ? peerDomainId : 0, // source domain\n uint32(destinationDomain), // destination domain\n uint256(0),\n bytes32(uint256(uint160(msg.sender))), // sender\n recipient, // recipient\n destinationCaller, // destination caller\n minFinalityThreshold, // min finality threshold\n uint32(0),\n messageBody // message body\n );\n emit MessageSent(message);\n }\n\n function receiveMessage(bytes memory message, bytes memory attestation)\n public\n virtual\n override\n returns (bool)\n {\n uint32 sourceDomain = message.extractUint32(SOURCE_DOMAIN_INDEX);\n address recipient = message.extractAddress(RECIPIENT_INDEX);\n address sender = message.extractAddress(SENDER_INDEX);\n\n bytes memory messageBody = message.extractSlice(\n MESSAGE_BODY_INDEX,\n message.length\n );\n\n bool isBurnMessage = recipient == cctpTokenMessenger;\n\n if (isBurnMessage) {\n // recipient = messageBody.extractAddress(BURN_MESSAGE_V2_RECIPIENT_INDEX);\n // This step won't mint USDC, transfer it to the recipient address\n // in your tests\n } else {\n IMessageHandlerV2(recipient).handleReceiveFinalizedMessage(\n sourceDomain,\n bytes32(uint256(uint160(sender))),\n 2000,\n messageBody\n );\n }\n\n // This step won't mint USDC, transfer it to the recipient address\n // in your tests\n emit MessageReceivedInMockTransmitter(message);\n\n return true;\n }\n}\n" + }, + "contracts/mocks/crosschain/CCTPTokenMessengerMock.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ICCTPTokenMessenger } from \"../../interfaces/cctp/ICCTP.sol\";\nimport { CCTPMessageTransmitterMock } from \"./CCTPMessageTransmitterMock.sol\";\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\n\n/**\n * @title Mock conctract simulating the functionality of the CCTPTokenMessenger contract\n * for the porposes of unit testing.\n * @author Origin Protocol Inc\n */\n\ncontract CCTPTokenMessengerMock is ICCTPTokenMessenger {\n IERC20 public usdc;\n CCTPMessageTransmitterMock public cctpMessageTransmitterMock;\n\n constructor(address _usdc, address _cctpMessageTransmitterMock) {\n usdc = IERC20(_usdc);\n cctpMessageTransmitterMock = CCTPMessageTransmitterMock(\n _cctpMessageTransmitterMock\n );\n }\n\n function depositForBurn(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller,\n uint256 maxFee,\n uint32 minFinalityThreshold\n ) external override {\n revert(\"Not implemented\");\n }\n\n /**\n * @dev mocks the depositForBurnWithHook function by sending the USDC to the CCTPMessageTransmitterMock\n * called by the AbstractCCTPIntegrator contract.\n */\n function depositForBurnWithHook(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller,\n uint256 maxFee,\n uint32 minFinalityThreshold,\n bytes memory hookData\n ) external override {\n require(burnToken == address(usdc), \"Invalid burn token\");\n\n usdc.transferFrom(msg.sender, address(this), maxFee);\n uint256 destinationAmount = amount - maxFee;\n usdc.transferFrom(\n msg.sender,\n address(cctpMessageTransmitterMock),\n destinationAmount\n );\n\n bytes memory burnMessage = _encodeBurnMessageV2(\n mintRecipient,\n amount,\n msg.sender,\n maxFee,\n maxFee,\n hookData\n );\n\n cctpMessageTransmitterMock.sendTokenTransferMessage(\n destinationDomain,\n mintRecipient,\n destinationCaller,\n minFinalityThreshold,\n destinationAmount,\n burnMessage\n );\n }\n\n function _encodeBurnMessageV2(\n bytes32 mintRecipient,\n uint256 amount,\n address messageSender,\n uint256 maxFee,\n uint256 feeExecuted,\n bytes memory hookData\n ) internal view returns (bytes memory) {\n bytes32 burnTokenBytes32 = bytes32(\n abi.encodePacked(bytes12(0), bytes20(uint160(address(usdc))))\n );\n bytes32 messageSenderBytes32 = bytes32(\n abi.encodePacked(bytes12(0), bytes20(uint160(messageSender)))\n );\n bytes32 expirationBlock = bytes32(0);\n\n // Ref: https://developers.circle.com/cctp/technical-guide#message-body\n return\n abi.encodePacked(\n uint32(1), // 0-3: version\n burnTokenBytes32, // 4-35: burnToken (bytes32 left-padded address)\n mintRecipient, // 36-67: mintRecipient (bytes32 left-padded address)\n amount, // 68-99: uint256 amount\n messageSenderBytes32, // 100-131: messageSender (bytes32 left-padded address)\n maxFee, // 132-163: uint256 maxFee\n feeExecuted, // 164-195: uint256 feeExecuted\n expirationBlock, // 196-227: bytes32 expirationBlock\n hookData // 228+: dynamic hookData\n );\n }\n\n function getMinFeeAmount(uint256 amount)\n external\n view\n override\n returns (uint256)\n {\n return 0;\n }\n}\n" + }, + "contracts/mocks/MockAutoWithdrawalVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultStorage } from \"../vault/VaultStorage.sol\";\n\ncontract MockAutoWithdrawalVault {\n address public asset;\n\n VaultStorage.WithdrawalQueueMetadata public withdrawalQueueMetadata;\n\n uint256 private _totalValue;\n bool private _revertNextWithdraw;\n bool private _revertNextDeposit;\n\n event MockedWithdrawal(address strategy, address asset, uint256 amount);\n event MockedDeposit(address strategy, address asset, uint256 amount);\n\n constructor(address _asset) {\n asset = _asset;\n }\n\n function setWithdrawalQueueMetadata(uint256 queued, uint256 claimable)\n external\n {\n withdrawalQueueMetadata.queued = uint128(queued);\n withdrawalQueueMetadata.claimable = uint128(claimable);\n }\n\n function revertNextWithdraw() external {\n _revertNextWithdraw = true;\n }\n\n function revertNextDeposit() external {\n _revertNextDeposit = true;\n }\n\n function setTotalValue(uint256 val) external {\n _totalValue = val;\n }\n\n function totalValue() external view returns (uint256) {\n return _totalValue;\n }\n\n function addWithdrawalQueueLiquidity() external {\n // Do nothing\n }\n\n function withdrawFromStrategy(\n address strategy,\n address[] memory assets,\n uint256[] memory amounts\n ) external {\n if (_revertNextWithdraw) {\n _revertNextWithdraw = false;\n revert(\"Mocked withdrawal revert\");\n }\n emit MockedWithdrawal(strategy, assets[0], amounts[0]);\n }\n\n function depositToStrategy(\n address strategy,\n address[] memory assets,\n uint256[] memory amounts\n ) external {\n if (_revertNextDeposit) {\n _revertNextDeposit = false;\n revert(\"Mocked deposit revert\");\n }\n emit MockedDeposit(strategy, assets[0], amounts[0]);\n }\n}\n" + }, + "contracts/mocks/MockLimitedWrappedOusd.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { WrappedOusd } from \"../token/WrappedOusd.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockLimitedWrappedOusd is WrappedOusd {\n constructor(ERC20 underlying_) WrappedOusd(underlying_) {}\n\n function maxDeposit(address)\n public\n view\n virtual\n override\n returns (uint256)\n {\n return 1e18;\n }\n}\n" + }, + "contracts/mocks/MockNonRebasing.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nimport { OUSD } from \"../token/OUSD.sol\";\n\ncontract MockNonRebasing {\n OUSD oUSD;\n\n function setOUSD(address _oUSDAddress) public {\n oUSD = OUSD(_oUSDAddress);\n }\n\n function rebaseOptIn() public {\n oUSD.rebaseOptIn();\n }\n\n function rebaseOptOut() public {\n oUSD.rebaseOptOut();\n }\n\n function transfer(address _to, uint256 _value) public {\n oUSD.transfer(_to, _value);\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public {\n oUSD.transferFrom(_from, _to, _value);\n }\n\n function approve(address _spender, uint256 _addedValue) public {\n oUSD.approve(_spender, _addedValue);\n }\n\n function mintOusd(address _vaultContract, uint256 _amount) public {\n IVault(_vaultContract).mint(_amount);\n }\n\n function redeemOusd(address _vaultContract, uint256 _amount) public {\n IVault(_vaultContract).requestWithdrawal(_amount);\n }\n\n function approveFor(\n address _contract,\n address _spender,\n uint256 _addedValue\n ) public {\n IERC20(_contract).approve(_spender, _addedValue);\n }\n}\n" + }, + "contracts/mocks/MockRebornMinter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n// solhint-disable-next-line no-console\nimport \"hardhat/console.sol\";\n\ncontract Sanctum {\n address public asset;\n address public vault;\n address public reborner;\n bool public shouldAttack = false;\n // should selfdestruct in the constructor\n bool public shouldDestruct = false;\n uint256 public targetMethod;\n address public ousdContract;\n\n constructor(address _asset, address _vault) {\n asset = _asset;\n vault = _vault;\n }\n\n function deploy(uint256 salt, bytes memory bytecode)\n public\n returns (address addr)\n {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)\n }\n require(addr != address(0), \"Create2: Failed on deploy\");\n }\n\n function computeAddress(uint256 salt, bytes memory bytecode)\n public\n view\n returns (address)\n {\n bytes32 bytecodeHashHash = keccak256(bytecode);\n bytes32 _data = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n bytecodeHashHash\n )\n );\n return address(bytes20(_data << 96));\n }\n\n function setShouldAttack(bool _shouldAttack) public {\n shouldAttack = _shouldAttack;\n }\n\n // should call selfdestruct in the constructor\n function setShouldDesctruct(bool _shouldDestruct) public {\n shouldDestruct = _shouldDestruct;\n }\n\n function setTargetMethod(uint256 target) public {\n targetMethod = target;\n }\n\n function setOUSDAddress(address _ousdContract) public {\n ousdContract = _ousdContract;\n }\n}\n\ncontract Reborner {\n Sanctum sanctum;\n bool logging = false;\n\n constructor(address _sanctum) {\n log(\"We are created...\");\n sanctum = Sanctum(_sanctum);\n if (sanctum.shouldAttack()) {\n log(\"We are attacking now...\");\n\n uint256 target = sanctum.targetMethod();\n\n if (target == 1) {\n redeem();\n } else if (target == 2) {\n transfer();\n } else {\n mint();\n }\n }\n\n if (sanctum.shouldDestruct()) {\n bye();\n }\n }\n\n function mint() public {\n log(\"We are attempting to mint..\");\n address asset = sanctum.asset();\n address vault = sanctum.vault();\n IERC20(asset).approve(vault, 1e6);\n IVault(vault).mint(1e6);\n log(\"We are now minting..\");\n }\n\n function redeem() public {\n log(\"We are attempting to request withdrawal..\");\n address vault = sanctum.vault();\n IVault(vault).requestWithdrawal(1e18);\n log(\"We are now requesting withdrawal..\");\n }\n\n function transfer() public {\n log(\"We are attempting to transfer..\");\n address ousd = sanctum.ousdContract();\n require(IERC20(ousd).transfer(address(1), 1e18), \"transfer failed\");\n log(\"We are now transfering..\");\n }\n\n function bye() public {\n log(\"We are now destructing..\");\n selfdestruct(payable(msg.sender));\n }\n\n function log(string memory message) internal view {\n if (logging) {\n // solhint-disable-next-line no-console\n console.log(message);\n }\n }\n}\n" + }, + "contracts/mocks/MockVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"../vault/VaultAdmin.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport \"../utils/Helpers.sol\";\n\ncontract MockVault is VaultAdmin {\n using StableMath for uint256;\n\n uint256 storedTotalValue;\n\n constructor(address _asset) VaultAdmin(_asset) {}\n\n function setTotalValue(uint256 _value) public {\n storedTotalValue = _value;\n }\n\n function totalValue() external view override returns (uint256) {\n return storedTotalValue;\n }\n\n function _totalValue() internal view override returns (uint256) {\n return storedTotalValue;\n }\n\n function _checkBalance(address _asset)\n internal\n view\n override\n returns (uint256 balance)\n {\n // Avoids rounding errors by returning the total value\n // in a single currency\n if (asset == _asset) {\n uint256 decimals = Helpers.getDecimals(_asset);\n return storedTotalValue.scaleBy(decimals, 18);\n } else {\n return 0;\n }\n }\n}\n" + }, + "contracts/mocks/MockVaultCoreInstantRebase.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultCore } from \"../vault/VaultCore.sol\";\n\ncontract MockVaultCoreInstantRebase is VaultCore {\n constructor(address _asset) VaultCore(_asset) {}\n\n function _nextYield(uint256 supply, uint256 vaultValue)\n internal\n view\n override\n returns (uint256 yield, uint256 targetRate)\n {\n if (vaultValue <= supply) {\n return (0, 0);\n }\n yield = vaultValue - supply;\n return (yield, 0);\n }\n}\n" + }, + "contracts/mocks/TestUpgradedOUSD.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../token/OUSD.sol\";\n\n// used to alter internal state of OUSD contract\ncontract TestUpgradedOUSD is OUSD {\n constructor() OUSD() {}\n\n function overwriteCreditBalances(address _account, uint256 _creditBalance)\n public\n {\n creditBalances[_account] = _creditBalance;\n }\n\n function overwriteAlternativeCPT(address _account, uint256 _acpt) public {\n alternativeCreditsPerToken[_account] = _acpt;\n }\n\n function overwriteRebaseState(address _account, RebaseOptions _rebaseOption)\n public\n {\n rebaseState[_account] = _rebaseOption;\n }\n}\n" + }, + "contracts/strategies/aerodrome/AerodromeAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Aerodrome AMO strategy\n * @author Origin Protocol Inc\n */\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\n\nimport { ISugarHelper } from \"../../interfaces/aerodrome/ISugarHelper.sol\";\nimport { INonfungiblePositionManager } from \"../../interfaces/aerodrome/INonfungiblePositionManager.sol\";\nimport { ISwapRouter } from \"../../interfaces/aerodrome/ISwapRouter.sol\";\nimport { ICLPool } from \"../../interfaces/aerodrome/ICLPool.sol\";\nimport { ICLGauge } from \"../../interfaces/aerodrome/ICLGauge.sol\";\nimport { IVault } from \"../../interfaces/IVault.sol\";\n\ncontract AerodromeAMOStrategy is InitializableAbstractStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n using SafeCast for uint256;\n\n /************************************************\n Important (!) setup configuration\n *************************************************/\n\n /**\n * In order to be able to remove a reasonable amount of complexity from the contract one of the\n * preconditions for this contract to function correctly is to have an outside account mint a small\n * amount of liquidity in the tick space where the contract will deploy's its liquidity and then send\n * that NFT LP position to a dead address (transfer to zero address not allowed.) See example of such\n * NFT LP token:\n * https://basescan.org/token/0x827922686190790b37229fd06084350e74485b72?a=413296#inventory\n */\n\n /***************************************\n Storage slot members\n ****************************************/\n\n /// @notice tokenId of the liquidity position\n uint256 public tokenId;\n /// @dev Minimum amount of tokens the strategy would be able to withdraw from the pool.\n /// minimum amount of tokens are withdrawn at a 1:1 price\n uint256 public underlyingAssets;\n /// @notice Marks the start of the interval that defines the allowed range of WETH share in\n /// the pre-configured pool's liquidity ticker\n uint256 public allowedWethShareStart;\n /// @notice Marks the end of the interval that defines the allowed range of WETH share in\n /// the pre-configured pool's liquidity ticker\n uint256 public allowedWethShareEnd;\n /// @dev reserved for inheritance\n int256[46] private __reserved;\n\n /***************************************\n Constants, structs and events\n ****************************************/\n\n /// @notice The address of the Wrapped ETH (WETH) token contract\n address public immutable WETH;\n /// @notice The address of the OETHb token contract\n address public immutable OETHb;\n /// @notice lower tick set to -1 representing the price of 1.0001 of WETH for 1 OETHb.\n int24 public immutable lowerTick;\n /// @notice lower tick set to 0 representing the price of 1.0000 of WETH for 1 OETHb.\n int24 public immutable upperTick;\n /// @notice tick spacing of the pool (set to 1)\n int24 public immutable tickSpacing;\n /// @notice the swapRouter for performing swaps\n ISwapRouter public immutable swapRouter;\n /// @notice the underlying AMO Slipstream pool\n ICLPool public immutable clPool;\n /// @notice the gauge for the corresponding Slipstream pool (clPool)\n /// @dev can become an immutable once the gauge is created on the base main-net\n ICLGauge public immutable clGauge;\n /// @notice the Position manager contract that is used to manage the pool's position\n INonfungiblePositionManager public immutable positionManager;\n /// @notice helper contract for liquidity and ticker math\n ISugarHelper public immutable helper;\n /// @notice sqrtRatioX96TickLower\n /// @dev tick lower has value -1 and represents the lowest price of WETH priced in OETHb. Meaning the pool\n /// offers less than 1 OETHb for 1 WETH. In other terms to get 1 OETHB the swap needs to offer 1.0001 WETH\n /// this is where purchasing OETHb with WETH within the liquidity position is most expensive\n uint160 public immutable sqrtRatioX96TickLower;\n /// @notice sqrtRatioX96TickHigher\n /// @dev tick higher has value 0 and represents 1:1 price parity of WETH to OETHb\n uint160 public immutable sqrtRatioX96TickHigher;\n /// @dev tick closest to 1:1 price parity\n /// Correctly assessing which tick is closer to 1:1 price parity is important since it affects\n /// the way we calculate the underlying assets in check Balance. The underlying aerodrome pool\n /// orders the tokens depending on the values of their addresses. If OETH token is token0 in the pool\n /// then sqrtRatioX96TickClosestToParity=sqrtRatioX96TickLower. If it is token1 in the pool then\n /// sqrtRatioX96TickClosestToParity=sqrtRatioX96TickHigher\n uint160 public immutable sqrtRatioX96TickClosestToParity;\n\n /// @dev a threshold under which the contract no longer allows for the protocol to rebalance. Guarding\n /// against a strategist / guardian being taken over and with multiple transactions draining the\n /// protocol funds.\n uint256 public constant SOLVENCY_THRESHOLD = 0.998 ether;\n\n error NotEnoughWethForSwap(uint256 wethBalance, uint256 requiredWeth); // 0x989e5ca8\n error NotEnoughWethLiquidity(uint256 wethBalance, uint256 requiredWeth); // 0xa6737d87\n error PoolRebalanceOutOfBounds(\n uint256 currentPoolWethShare,\n uint256 allowedWethShareStart,\n uint256 allowedWethShareEnd\n ); // 0x3681e8e0\n error OutsideExpectedTickRange(int24 currentTick); // 0x5a2eba75\n\n event PoolRebalanced(uint256 currentPoolWethShare);\n\n event PoolWethShareIntervalUpdated(\n uint256 allowedWethShareStart,\n uint256 allowedWethShareEnd\n );\n\n event LiquidityRemoved(\n uint256 withdrawLiquidityShare,\n uint256 removedWETHAmount,\n uint256 removedOETHbAmount,\n uint256 wethAmountCollected,\n uint256 oethbAmountCollected,\n uint256 underlyingAssets\n );\n\n event LiquidityAdded(\n uint256 wethAmountDesired,\n uint256 oethbAmountDesired,\n uint256 wethAmountSupplied,\n uint256 oethbAmountSupplied,\n uint256 tokenId,\n uint256 underlyingAssets\n );\n\n event UnderlyingAssetsUpdated(uint256 underlyingAssets);\n\n /**\n * @dev Un-stakes the token from the gauge for the execution duration of\n * the function and after that re-stakes it back in.\n *\n * It is important that the token is unstaked and owned by the strategy contract\n * during any liquidity altering operations and that it is re-staked back into the\n * gauge after liquidity changes. If the token fails to re-stake back to the\n * gauge it is not earning incentives.\n */\n // all functions using this modifier are used by functions with reentrancy check\n // slither-disable-start reentrancy-no-eth\n modifier gaugeUnstakeAndRestake() {\n // because of solidity short-circuit _isLpTokenStakedInGauge doesn't get called\n // when tokenId == 0\n if (tokenId != 0 && _isLpTokenStakedInGauge()) {\n clGauge.withdraw(tokenId);\n }\n _;\n // because of solidity short-circuit _isLpTokenStakedInGauge doesn't get called\n // when tokenId == 0\n if (tokenId != 0 && !_isLpTokenStakedInGauge()) {\n /**\n * It can happen that a withdrawal (or a full withdrawal) transactions would\n * remove all of the liquidity from the token with a NFT token still existing.\n * In that case the token can not be staked into the gauge, as some liquidity\n * needs to be added to it first.\n */\n if (_getLiquidity() > 0) {\n // if token liquidity changes the positionManager requires re-approval.\n // to any contract pre-approved to handle the token.\n positionManager.approve(address(clGauge), tokenId);\n clGauge.deposit(tokenId);\n }\n }\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice the constructor\n /// @dev This contract is intended to be used as a proxy. To prevent the\n /// potential confusion of having a functional implementation contract\n /// the constructor has the `initializer` modifier. This way the\n /// `initialize` function can not be called on the implementation contract.\n /// For the same reason the implementation contract also has the governor\n /// set to a zero address.\n /// @param _stratConfig the basic strategy configuration\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _oethbAddress Address of the Erc20 OETHb Token contract\n /// @param _swapRouter Address of the Aerodrome Universal Swap Router\n /// @param _nonfungiblePositionManager Address of position manager to add/remove\n /// the liquidity\n /// @param _clPool Address of the Aerodrome concentrated liquidity pool\n /// @param _clGauge Address of the Aerodrome slipstream pool gauge\n /// @param _sugarHelper Address of the Aerodrome Sugar helper contract\n /// @param _lowerBoundingTick Smaller bounding tick of our liquidity position\n /// @param _upperBoundingTick Larger bounding tick of our liquidity position\n /// @param _tickClosestToParity Tick that is closer to 1:1 price parity\n constructor(\n BaseStrategyConfig memory _stratConfig,\n address _wethAddress,\n address _oethbAddress,\n address _swapRouter,\n address _nonfungiblePositionManager,\n address _clPool,\n address _clGauge,\n address _sugarHelper,\n int24 _lowerBoundingTick,\n int24 _upperBoundingTick,\n int24 _tickClosestToParity\n ) initializer InitializableAbstractStrategy(_stratConfig) {\n require(\n _lowerBoundingTick == _tickClosestToParity ||\n _upperBoundingTick == _tickClosestToParity,\n \"Misconfigured tickClosestToParity\"\n );\n require(\n ICLPool(_clPool).token0() == _wethAddress,\n \"Only WETH supported as token0\"\n );\n require(\n ICLPool(_clPool).token1() == _oethbAddress,\n \"Only OETHb supported as token1\"\n );\n int24 _tickSpacing = ICLPool(_clPool).tickSpacing();\n // when we generalize AMO we might support other tick spacings\n require(_tickSpacing == 1, \"Unsupported tickSpacing\");\n\n WETH = _wethAddress;\n OETHb = _oethbAddress;\n swapRouter = ISwapRouter(_swapRouter);\n positionManager = INonfungiblePositionManager(\n _nonfungiblePositionManager\n );\n clPool = ICLPool(_clPool);\n clGauge = ICLGauge(_clGauge);\n helper = ISugarHelper(_sugarHelper);\n sqrtRatioX96TickLower = ISugarHelper(_sugarHelper).getSqrtRatioAtTick(\n _lowerBoundingTick\n );\n sqrtRatioX96TickHigher = ISugarHelper(_sugarHelper).getSqrtRatioAtTick(\n _upperBoundingTick\n );\n sqrtRatioX96TickClosestToParity = ISugarHelper(_sugarHelper)\n .getSqrtRatioAtTick(_tickClosestToParity);\n\n lowerTick = _lowerBoundingTick;\n upperTick = _upperBoundingTick;\n tickSpacing = _tickSpacing;\n\n // prevent implementation contract to be governed\n _setGovernor(address(0));\n }\n\n /**\n * @notice initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n */\n function initialize(address[] memory _rewardTokenAddresses)\n external\n onlyGovernor\n initializer\n {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n new address[](0),\n new address[](0)\n );\n }\n\n /***************************************\n Configuration \n ****************************************/\n\n /**\n * @notice Set allowed pool weth share interval. After the rebalance happens\n * the share of WETH token in the ticker needs to be withing the specifications\n * of the interval.\n *\n * @param _allowedWethShareStart Start of WETH share interval expressed as 18 decimal amount\n * @param _allowedWethShareEnd End of WETH share interval expressed as 18 decimal amount\n */\n function setAllowedPoolWethShareInterval(\n uint256 _allowedWethShareStart,\n uint256 _allowedWethShareEnd\n ) external onlyGovernor {\n require(\n _allowedWethShareStart < _allowedWethShareEnd,\n \"Invalid interval\"\n );\n // can not go below 1% weth share\n require(_allowedWethShareStart > 0.01 ether, \"Invalid interval start\");\n // can not go above 95% weth share\n require(_allowedWethShareEnd < 0.95 ether, \"Invalid interval end\");\n\n allowedWethShareStart = _allowedWethShareStart;\n allowedWethShareEnd = _allowedWethShareEnd;\n emit PoolWethShareIntervalUpdated(\n allowedWethShareStart,\n allowedWethShareEnd\n );\n }\n\n /***************************************\n Periphery utils\n ****************************************/\n\n function _isLpTokenStakedInGauge() internal view returns (bool) {\n require(tokenId != 0, \"Missing NFT LP token\");\n\n address owner = positionManager.ownerOf(tokenId);\n require(\n owner == address(clGauge) || owner == address(this),\n \"Unexpected token owner\"\n );\n return owner == address(clGauge);\n }\n\n /***************************************\n Strategy overrides \n ****************************************/\n\n /**\n * @notice Deposit an amount of assets into the strategy contract. Calling deposit doesn't\n * automatically deposit funds into the underlying Aerodrome pool\n * @param _asset Address for the asset\n * @param _amount Units of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /**\n * @notice Deposit WETH to the strategy contract. This function does not add liquidity to the\n * underlying Aerodrome pool.\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 _wethBalance = IERC20(WETH).balanceOf(address(this));\n if (_wethBalance > 1e12) {\n _deposit(WETH, _wethBalance);\n }\n }\n\n /**\n * @dev Deposit WETH to the contract. This function doesn't deposit the liquidity to the\n * pool, that is done via the rebalance call.\n * @param _asset Address of the asset to deposit\n * @param _amount Amount of assets to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal {\n require(_asset == WETH, \"Unsupported asset\");\n require(_amount > 0, \"Must deposit something\");\n emit Deposit(_asset, address(0), _amount);\n\n // if the pool price is not within the expected interval leave the WETH on the contract\n // as to not break the mints\n (bool _isExpectedRange, ) = _checkForExpectedPoolPrice(false);\n if (_isExpectedRange) {\n // deposit funds into the underlying pool\n _rebalance(0, false, 0);\n }\n }\n\n /**\n * @notice Rebalance the pool to the desired token split and Deposit any WETH on the contract to the\n * underlying aerodrome pool. Print the required amount of corresponding OETHb. After the rebalancing is\n * done burn any potentially remaining OETHb tokens still on the strategy contract.\n *\n * This function has a slightly different behaviour depending on the status of the underlying Aerodrome\n * slipstream pool. The function consists of the following 3 steps:\n * 1. withdrawPartialLiquidity -> so that moving the activeTrading price via a swap is cheaper\n * 2. swapToDesiredPosition -> move active trading price in the pool to be able to deposit WETH & OETHb\n * tokens with the desired pre-configured shares\n * 3. addLiquidity -> add liquidity into the pool respecting share split configuration\n *\n * Scenario 1: When there is no liquidity in the pool from the strategy but there is from other LPs then\n * only step 1 is skipped. (It is important to note that liquidity needs to exist in the configured\n * strategy tick ranges in order for the swap to be possible) Step 3 mints new liquidity position\n * instead of adding to an existing one.\n * Scenario 2: When there is strategy's liquidity in the pool all 3 steps are taken\n *\n *\n * Exact _amountToSwap, _swapWeth & _minTokenReceived parameters shall be determined by simulating the\n * transaction off-chain. The strategy checks that after the swap the share of the tokens is in the\n * expected ranges.\n *\n * @param _amountToSwap The amount of the token to swap\n * @param _swapWeth Swap using WETH when true, use OETHb when false\n * @param _minTokenReceived Slippage check -> minimum amount of token expected in return\n */\n function rebalance(\n uint256 _amountToSwap,\n bool _swapWeth,\n uint256 _minTokenReceived\n ) external nonReentrant onlyGovernorOrStrategist {\n _rebalance(_amountToSwap, _swapWeth, _minTokenReceived);\n }\n\n function _rebalance(\n uint256 _amountToSwap,\n bool _swapWeth,\n uint256 _minTokenReceived\n ) internal {\n /**\n * Would be nice to check if there is any total liquidity in the pool before performing this swap\n * but there is no easy way to do that in UniswapV3:\n * - clPool.liquidity() -> only liquidity in the active tick\n * - asset[1&2].balanceOf(address(clPool)) -> will include uncollected tokens of LP providers\n * after their liquidity position has been decreased\n */\n\n /**\n * When rebalance is called for the first time there is no strategy\n * liquidity in the pool yet. The liquidity removal is thus skipped.\n * Also execute this function when WETH is required for the swap.\n */\n if (tokenId != 0 && _swapWeth && _amountToSwap > 0) {\n _ensureWETHBalance(_amountToSwap);\n }\n\n // in some cases we will just want to add liquidity and not issue a swap to move the\n // active trading position within the pool\n if (_amountToSwap > 0) {\n _swapToDesiredPosition(_amountToSwap, _swapWeth, _minTokenReceived);\n }\n // calling check liquidity early so we don't get unexpected errors when adding liquidity\n // in the later stages of this function\n _checkForExpectedPoolPrice(true);\n\n _addLiquidity();\n\n // this call shouldn't be necessary, since adding liquidity shouldn't affect the active\n // trading price. It is a defensive programming measure.\n (, uint256 _wethSharePct) = _checkForExpectedPoolPrice(true);\n\n // revert if protocol insolvent\n _solvencyAssert();\n\n emit PoolRebalanced(_wethSharePct);\n }\n\n /**\n * Checks that the protocol is solvent, protecting from a rogue Strategist / Guardian that can\n * keep rebalancing the pool in both directions making the protocol lose a tiny amount of\n * funds each time.\n *\n * Protocol must be at least SOLVENCY_THRESHOLD (99,8 %) backed in order for the rebalances to\n * function.\n */\n function _solvencyAssert() internal view {\n uint256 _totalVaultValue = IVault(vaultAddress).totalValue();\n uint256 _totalOethbSupply = IERC20(OETHb).totalSupply();\n\n if (\n _totalVaultValue.divPrecisely(_totalOethbSupply) <\n SOLVENCY_THRESHOLD\n ) {\n revert(\"Protocol insolvent\");\n }\n }\n\n /**\n * @dev Decrease partial or all liquidity from the pool.\n * @param _liquidityToDecrease The amount of liquidity to remove expressed in 18 decimal point\n */\n function _removeLiquidity(uint256 _liquidityToDecrease)\n internal\n gaugeUnstakeAndRestake\n {\n require(_liquidityToDecrease > 0, \"Must remove some liquidity\");\n\n uint128 _liquidity = _getLiquidity();\n // need to convert to uint256 since intermittent result is to big for uint128 to handle\n uint128 _liquidityToRemove = uint256(_liquidity)\n .mulTruncate(_liquidityToDecrease)\n .toUint128();\n\n /**\n * There is no liquidity to remove -> exit function early. This can happen after a\n * withdraw/withdrawAll removes all of the liquidity while retaining the NFT token.\n */\n if (_liquidity == 0 || _liquidityToRemove == 0) {\n return;\n }\n\n (uint256 _amountWeth, uint256 _amountOethb) = positionManager\n .decreaseLiquidity(\n // Both expected amounts can be 0 since we don't really care if any swaps\n // happen just before the liquidity removal.\n INonfungiblePositionManager.DecreaseLiquidityParams({\n tokenId: tokenId,\n liquidity: _liquidityToRemove,\n amount0Min: 0,\n amount1Min: 0,\n deadline: block.timestamp\n })\n );\n\n (\n uint256 _amountWethCollected,\n uint256 _amountOethbCollected\n ) = positionManager.collect(\n INonfungiblePositionManager.CollectParams({\n tokenId: tokenId,\n recipient: address(this),\n amount0Max: type(uint128).max, // defaults to all tokens owed\n amount1Max: type(uint128).max // defaults to all tokens owed\n })\n );\n\n _updateUnderlyingAssets();\n\n emit LiquidityRemoved(\n _liquidityToDecrease,\n _amountWeth, //removedWethAmount\n _amountOethb, //removedOethbAmount\n _amountWethCollected,\n _amountOethbCollected,\n underlyingAssets\n );\n\n _burnOethbOnTheContract();\n }\n\n /**\n * @dev Perform a swap so that after the swap the ticker has the desired WETH to OETHb token share.\n */\n function _swapToDesiredPosition(\n uint256 _amountToSwap,\n bool _swapWeth,\n uint256 _minTokenReceived\n ) internal {\n IERC20 _tokenToSwap = IERC20(_swapWeth ? WETH : OETHb);\n uint256 _balance = _tokenToSwap.balanceOf(address(this));\n\n if (_balance < _amountToSwap) {\n // This should never trigger since _ensureWETHBalance will already\n // throw an error if there is not enough WETH\n if (_swapWeth) {\n revert NotEnoughWethForSwap(_balance, _amountToSwap);\n }\n // if swapping OETHb\n uint256 mintForSwap = _amountToSwap - _balance;\n IVault(vaultAddress).mintForStrategy(mintForSwap);\n }\n\n // approve the specific amount of WETH required\n if (_swapWeth) {\n IERC20(WETH).approve(address(swapRouter), _amountToSwap);\n }\n\n // Swap it\n swapRouter.exactInputSingle(\n // sqrtPriceLimitX96 is just a rough sanity check that we are within 0 -> 1 tick\n // a more fine check is performed in _checkForExpectedPoolPrice\n // Note: this needs further work if we want to generalize this approach\n ISwapRouter.ExactInputSingleParams({\n tokenIn: address(_tokenToSwap),\n tokenOut: _swapWeth ? OETHb : WETH,\n tickSpacing: tickSpacing, // set to 1\n recipient: address(this),\n deadline: block.timestamp,\n amountIn: _amountToSwap,\n amountOutMinimum: _minTokenReceived, // slippage check\n sqrtPriceLimitX96: _swapWeth\n ? sqrtRatioX96TickLower\n : sqrtRatioX96TickHigher\n })\n );\n\n /**\n * In the interest of each function in _rebalance to leave the contract state as\n * clean as possible the OETHb tokens here are burned. This decreases the\n * dependence where `_swapToDesiredPosition` function relies on later functions\n * (`addLiquidity`) to burn the OETHb. Reducing the risk of error introduction.\n */\n _burnOethbOnTheContract();\n }\n\n /**\n * @dev Add liquidity into the pool in the pre-configured WETH to OETHb share ratios\n * defined by the allowedPoolWethShareStart|End interval. This function will respect\n * liquidity ratios when there is no liquidity yet in the pool. If liquidity is already\n * present then it relies on the `_swapToDesiredPosition` function in a step before\n * to already move the trading price to desired position (with some tolerance).\n */\n // rebalance already has re-entrency checks\n // slither-disable-start reentrancy-no-eth\n function _addLiquidity() internal gaugeUnstakeAndRestake {\n uint256 _wethBalance = IERC20(WETH).balanceOf(address(this));\n uint256 _oethbBalance = IERC20(OETHb).balanceOf(address(this));\n // don't deposit small liquidity amounts\n if (_wethBalance <= 1e12) {\n return;\n }\n\n uint160 _currentPrice = getPoolX96Price();\n /**\n * Sanity check active trading price is positioned within our desired tick.\n *\n * We revert when price is equal to the lower tick even though that is still\n * a valid amount in regards to ticker position by Sugar.estimateAmount call.\n * Current price equaling tick bound at the 1:1 price parity results in\n * uint overfow when calculating the OETHb balance to deposit.\n */\n if (\n _currentPrice <= sqrtRatioX96TickLower ||\n _currentPrice >= sqrtRatioX96TickHigher\n ) {\n revert OutsideExpectedTickRange(getCurrentTradingTick());\n }\n\n /**\n * If estimateAmount1 call fails it could be due to _currentPrice being really\n * close to a tick and amount1 is a larger number than the sugar helper is able\n * to compute.\n *\n * If token addresses were reversed estimateAmount0 would be required here\n */\n uint256 _oethbRequired = helper.estimateAmount1(\n _wethBalance,\n address(0), // no need to pass pool address when current price is specified\n _currentPrice,\n lowerTick,\n upperTick\n );\n\n if (_oethbRequired > _oethbBalance) {\n IVault(vaultAddress).mintForStrategy(\n _oethbRequired - _oethbBalance\n );\n }\n\n // approve the specific amount of WETH required\n IERC20(WETH).approve(address(positionManager), _wethBalance);\n\n uint256 _wethAmountSupplied;\n uint256 _oethbAmountSupplied;\n if (tokenId == 0) {\n (\n tokenId,\n ,\n _wethAmountSupplied,\n _oethbAmountSupplied\n ) = positionManager.mint(\n /** amount0Min & amount1Min are left at 0 because slippage protection is ensured by the\n * _checkForExpectedPoolPrice\n *›\n * Also sqrtPriceX96 is 0 because the pool is already created\n * non zero amount attempts to create a new instance of the pool\n */\n INonfungiblePositionManager.MintParams({\n token0: WETH,\n token1: OETHb,\n tickSpacing: tickSpacing,\n tickLower: lowerTick,\n tickUpper: upperTick,\n amount0Desired: _wethBalance,\n amount1Desired: _oethbRequired,\n amount0Min: 0,\n amount1Min: 0,\n recipient: address(this),\n deadline: block.timestamp,\n sqrtPriceX96: 0\n })\n );\n } else {\n (, _wethAmountSupplied, _oethbAmountSupplied) = positionManager\n .increaseLiquidity(\n /** amount0Min & amount1Min are left at 0 because slippage protection is ensured by the\n * _checkForExpectedPoolPrice\n */\n INonfungiblePositionManager.IncreaseLiquidityParams({\n tokenId: tokenId,\n amount0Desired: _wethBalance,\n amount1Desired: _oethbRequired,\n amount0Min: 0,\n amount1Min: 0,\n deadline: block.timestamp\n })\n );\n }\n\n _updateUnderlyingAssets();\n emit LiquidityAdded(\n _wethBalance, // wethAmountDesired\n _oethbRequired, // oethbAmountDesired\n _wethAmountSupplied, // wethAmountSupplied\n _oethbAmountSupplied, // oethbAmountSupplied\n tokenId, // tokenId\n underlyingAssets\n );\n\n // burn remaining OETHb\n _burnOethbOnTheContract();\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /**\n * @dev Check that the Aerodrome pool price is within the expected\n * parameters.\n * This function works whether the strategy contract has liquidity\n * position in the pool or not. The function returns _wethSharePct\n * as a gas optimization measure.\n * @param throwException when set to true the function throws an exception\n * when pool's price is not within expected range.\n * @return _isExpectedRange Bool expressing price is within expected range\n * @return _wethSharePct Share of WETH owned by this strategy contract in the\n * configured ticker.\n */\n function _checkForExpectedPoolPrice(bool throwException)\n internal\n view\n returns (bool _isExpectedRange, uint256 _wethSharePct)\n {\n require(\n allowedWethShareStart != 0 && allowedWethShareEnd != 0,\n \"Weth share interval not set\"\n );\n\n uint160 _currentPrice = getPoolX96Price();\n\n /**\n * First check we are in expected tick range\n *\n * We revert even though price being equal to the lower tick would still\n * count being within lower tick for the purpose of Sugar.estimateAmount calls\n */\n if (\n _currentPrice <= sqrtRatioX96TickLower ||\n _currentPrice >= sqrtRatioX96TickHigher\n ) {\n if (throwException) {\n revert OutsideExpectedTickRange(getCurrentTradingTick());\n }\n return (false, 0);\n }\n\n // 18 decimal number expressed WETH tick share\n _wethSharePct = _getWethShare(_currentPrice);\n\n if (\n _wethSharePct < allowedWethShareStart ||\n _wethSharePct > allowedWethShareEnd\n ) {\n if (throwException) {\n revert PoolRebalanceOutOfBounds(\n _wethSharePct,\n allowedWethShareStart,\n allowedWethShareEnd\n );\n }\n return (false, _wethSharePct);\n }\n\n return (true, _wethSharePct);\n }\n\n /**\n * Burns any OETHb tokens remaining on the strategy contract\n */\n function _burnOethbOnTheContract() internal {\n uint256 _oethbBalance = IERC20(OETHb).balanceOf(address(this));\n if (_oethbBalance > 1e12) {\n IVault(vaultAddress).burnForStrategy(_oethbBalance);\n }\n }\n\n /// @dev This function assumes there are no uncollected tokens in the clPool owned by the strategy contract.\n /// For that reason any liquidity withdrawals must also collect the tokens.\n function _updateUnderlyingAssets() internal {\n if (tokenId == 0) {\n underlyingAssets = 0;\n emit UnderlyingAssetsUpdated(underlyingAssets);\n return;\n }\n\n uint128 _liquidity = _getLiquidity();\n\n /**\n * Our net value represent the smallest amount of tokens we are able to extract from the position\n * given our liquidity.\n *\n * The least amount of tokens extraditable from the position is where the active trading price is\n * at the ticker 0 meaning the pool is offering 1:1 trades between WETH & OETHb. At that moment the pool\n * consists completely of OETHb and no WETH.\n *\n * The more swaps from WETH -> OETHb happen on the pool the more the price starts to move towards the -1\n * ticker making OETHb (priced in WETH) more expensive.\n *\n * An additional note: when liquidity is 0 then the helper returns 0 for both token amounts. And the\n * function set underlying assets to 0.\n */\n (uint256 _wethAmount, uint256 _oethbAmount) = helper\n .getAmountsForLiquidity(\n sqrtRatioX96TickClosestToParity, // sqrtRatioX96\n sqrtRatioX96TickLower, // sqrtRatioAX96\n sqrtRatioX96TickHigher, // sqrtRatioBX96\n _liquidity\n );\n\n require(_wethAmount == 0, \"Non zero wethAmount\");\n underlyingAssets = _oethbAmount;\n emit UnderlyingAssetsUpdated(underlyingAssets);\n }\n\n /**\n * @dev This function removes the appropriate amount of liquidity to assure that the required\n * amount of WETH is available on the contract\n *\n * @param _amount WETH balance required on the contract\n */\n function _ensureWETHBalance(uint256 _amount) internal {\n uint256 _wethBalance = IERC20(WETH).balanceOf(address(this));\n if (_wethBalance >= _amount) {\n return;\n }\n\n require(tokenId != 0, \"No liquidity available\");\n uint256 _additionalWethRequired = _amount - _wethBalance;\n (uint256 _wethInThePool, ) = getPositionPrincipal();\n\n if (_wethInThePool < _additionalWethRequired) {\n revert NotEnoughWethLiquidity(\n _wethInThePool,\n _additionalWethRequired\n );\n }\n\n uint256 shareOfWethToRemove = Math.min(\n _additionalWethRequired.divPrecisely(_wethInThePool) + 1,\n 1e18\n );\n _removeLiquidity(shareOfWethToRemove);\n }\n\n /**\n * @notice Withdraw an `amount` of assets from the platform and\n * send to the `_recipient`.\n * @param _recipient Address to which the asset should be sent\n * @param _asset WETH address\n * @param _amount Amount of WETH to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_asset == WETH, \"Unsupported asset\");\n require(_recipient == vaultAddress, \"Only withdraw to vault allowed\");\n\n _ensureWETHBalance(_amount);\n\n _withdraw(_recipient, _amount);\n }\n\n /**\n * @notice Withdraw WETH and sends it to the Vault.\n */\n function withdrawAll() external override onlyVault nonReentrant {\n if (tokenId != 0) {\n _removeLiquidity(1e18);\n }\n\n uint256 _balance = IERC20(WETH).balanceOf(address(this));\n if (_balance > 0) {\n _withdraw(vaultAddress, _balance);\n }\n }\n\n function _withdraw(address _recipient, uint256 _amount) internal {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient == vaultAddress, \"Only withdraw to vault allowed\");\n\n IERC20(WETH).safeTransfer(_recipient, _amount);\n emit Withdrawal(WETH, address(0), _amount);\n }\n\n /**\n * @dev Collect the AERO token from the gauge\n */\n function _collectRewardTokens() internal override {\n if (tokenId != 0 && _isLpTokenStakedInGauge()) {\n clGauge.getReward(tokenId);\n }\n super._collectRewardTokens();\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == WETH;\n }\n\n /**\n * @dev Approve the spending of all assets\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n // to add liquidity to the clPool\n IERC20(OETHb).approve(address(positionManager), type(uint256).max);\n // to be able to rebalance using the swapRouter\n IERC20(OETHb).approve(address(swapRouter), type(uint256).max);\n\n /* the behaviour of this strategy has slightly changed and WETH could be\n * present on the contract between the transactions. For that reason we are\n * un-approving WETH to the swapRouter & positionManager and only approving\n * the required amount before a transaction\n */\n IERC20(WETH).approve(address(swapRouter), 0);\n IERC20(WETH).approve(address(positionManager), 0);\n }\n\n /***************************************\n Balances and Fees\n ****************************************/\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256)\n {\n require(_asset == WETH, \"Only WETH supported\");\n\n // we could in theory deposit to the strategy and forget to call rebalance in the same\n // governance transaction batch. In that case the WETH that is on the strategy contract\n // also needs to be accounted for.\n uint256 _wethBalance = IERC20(WETH).balanceOf(address(this));\n // just paranoia check, in case there is OETHb in the strategy that for some reason hasn't\n // been burned yet.\n uint256 _oethbBalance = IERC20(OETHb).balanceOf(address(this));\n return underlyingAssets + _wethBalance + _oethbBalance;\n }\n\n /**\n * @dev Returns the balance of both tokens in a given position (excluding fees)\n * @return _amountWeth Amount of WETH in position\n * @return _amountOethb Amount of OETHb in position\n */\n function getPositionPrincipal()\n public\n view\n returns (uint256 _amountWeth, uint256 _amountOethb)\n {\n if (tokenId == 0) {\n return (0, 0);\n }\n\n uint160 _sqrtRatioX96 = getPoolX96Price();\n (_amountWeth, _amountOethb) = helper.principal(\n positionManager,\n tokenId,\n _sqrtRatioX96\n );\n }\n\n /**\n * @notice Returns the current pool price in X96 format\n * @return _sqrtRatioX96 Pool price\n */\n function getPoolX96Price() public view returns (uint160 _sqrtRatioX96) {\n (_sqrtRatioX96, , , , , ) = clPool.slot0();\n }\n\n /**\n * @notice Returns the current active trading tick of the underlying pool\n * @return _currentTick Current pool trading tick\n */\n function getCurrentTradingTick() public view returns (int24 _currentTick) {\n (, _currentTick, , , , ) = clPool.slot0();\n }\n\n /**\n * @notice Returns the percentage of WETH liquidity in the configured ticker\n * owned by this strategy contract.\n * @return uint256 1e18 denominated percentage expressing the share\n */\n function getWETHShare() external view returns (uint256) {\n uint160 _currentPrice = getPoolX96Price();\n return _getWethShare(_currentPrice);\n }\n\n /**\n * @notice Returns the amount of liquidity in the contract's LP position\n * @return _liquidity Amount of liquidity in the position\n */\n function _getLiquidity() internal view returns (uint128 _liquidity) {\n if (tokenId == 0) {\n revert(\"No LP position\");\n }\n\n (, , , , , , , _liquidity, , , , ) = positionManager.positions(tokenId);\n }\n\n function _getWethShare(uint160 _currentPrice)\n internal\n view\n returns (uint256)\n {\n /**\n * If estimateAmount1 call fails it could be due to _currentPrice being really\n * close to a tick and amount1 too big to compute.\n *\n * If token addresses were reversed estimateAmount0 would be required here\n */\n uint256 _normalizedWethAmount = 1 ether;\n uint256 _correspondingOethAmount = helper.estimateAmount1(\n _normalizedWethAmount,\n address(0), // no need to pass pool address when current price is specified\n _currentPrice,\n lowerTick,\n upperTick\n );\n\n // 18 decimal number expressed weth tick share\n return\n _normalizedWethAmount.divPrecisely(\n _normalizedWethAmount + _correspondingOethAmount\n );\n }\n\n /***************************************\n Hidden functions\n ****************************************/\n /// @inheritdoc InitializableAbstractStrategy\n function setPTokenAddress(address, address) external override {\n // The pool tokens can never change.\n revert(\"Unsupported method\");\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function removePToken(uint256) external override {\n // The pool tokens can never change.\n revert(\"Unsupported method\");\n }\n\n /**\n * @dev Not supported\n */\n function _abstractSetPToken(address, address) internal override {\n // the deployer shall call safeApproveAllTokens() to set necessary approvals\n revert(\"Unsupported method\");\n }\n\n /***************************************\n ERC721 management\n ****************************************/\n\n /// @notice Callback function for whenever a NFT is transferred to this contract\n // solhint-disable-next-line max-line-length\n /// Ref: https://docs.openzeppelin.com/contracts/3.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-\n function onERC721Received(\n address,\n address,\n uint256,\n bytes calldata\n ) external returns (bytes4) {\n return this.onERC721Received.selector;\n }\n}\n" + }, + "contracts/strategies/algebra/OETHSupernovaAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Supernova OETH Algorithmic Market Maker (AMO) Strategy\n * @notice AMO strategy for the Supernova OETH/WETH stable pool\n * @author Origin Protocol Inc\n */\nimport { StableSwapAMMStrategy } from \"./StableSwapAMMStrategy.sol\";\nimport { IGauge } from \"../../interfaces/algebra/IAlgebraGauge.sol\";\n\ncontract OETHSupernovaAMOStrategy is StableSwapAMMStrategy {\n /**\n * @param _baseConfig The `platformAddress` is the address of the Supernova OETH/WETH pool.\n * The `vaultAddress` is the address of the OETH Vault.\n * @param _gauge Address of the Supernova gauge for the pool.\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _gauge)\n StableSwapAMMStrategy(_baseConfig, _gauge, IGauge(_gauge).TOKEN())\n {}\n}\n" + }, + "contracts/strategies/algebra/StableSwapAMMStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Algebra Algorithmic Market Maker (AMO) Strategy\n * @notice AMO strategy for the Algebra stable swap pool\n * @author Origin Protocol Inc\n */\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\nimport { sqrt } from \"../../utils/PRBMath.sol\";\nimport { IBasicToken } from \"../../interfaces/IBasicToken.sol\";\nimport { IPair } from \"../../interfaces/algebra/IAlgebraPair.sol\";\nimport { IGauge } from \"../../interfaces/algebra/IAlgebraGauge.sol\";\nimport { IVault } from \"../../interfaces/IVault.sol\";\n\ncontract StableSwapAMMStrategy is InitializableAbstractStrategy {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n using SafeCast for uint256;\n\n /**\n * @notice a threshold under which the contract no longer allows for the protocol to manually rebalance.\n * Guarding against a strategist / guardian being taken over and with multiple transactions\n * draining the protocol funds.\n */\n uint256 public constant SOLVENCY_THRESHOLD = 0.998 ether;\n\n /// @notice Precision for the Algebra Stable AMM (sAMM) invariant k.\n uint256 public constant PRECISION = 1e18;\n\n /// @notice Address of the asset (non OToken) token contract\n address public immutable asset;\n\n /// @notice Address of the OToken token contract.\n address public immutable oToken;\n\n /// @notice Address of the Algebra Stable pool contract.\n address public immutable pool;\n\n /// @notice Address of the Algebra Gauge contract.\n address public immutable gauge;\n\n /// @notice Index of the OToken in the Algebra pool.\n uint256 public immutable oTokenPoolIndex;\n\n /// @notice The max amount the OToken/asset price can deviate from peg (1e18)\n /// before deposits are reverted scaled to 18 decimals.\n /// eg 0.01e18 or 1e16 is 1% which is 100 basis points.\n /// This is the amount below and above peg so a 50 basis point deviation (0.005e18)\n /// allows a price range from 0.995 to 1.005.\n uint256 public maxDepeg;\n\n event SwapOTokensToPool(\n uint256 oTokenMinted,\n uint256 assetDepositAmount,\n uint256 oTokenDepositAmount,\n uint256 lpTokens\n );\n event SwapAssetsToPool(\n uint256 assetSwapped,\n uint256 lpTokens,\n uint256 oTokenBurnt\n );\n event MaxDepegUpdated(uint256 maxDepeg);\n\n /**\n * @dev Verifies that the caller is the Strategist of the Vault.\n */\n modifier onlyStrategist() {\n require(\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n _;\n }\n\n /**\n * @dev Skim the Algebra pool in case any extra asset or OToken tokens were added\n */\n modifier skimPool() {\n IPair(pool).skim(address(this));\n _;\n }\n\n /**\n * @dev Checks the pool is balanced enough to allow deposits.\n */\n modifier nearBalancedPool() {\n // OToken/asset price = asset / OToken\n // Get the OToken/asset price for selling 1 OToken for asset\n // As OToken is 1, the asset amount is the OToken/asset price\n uint256 sellPrice = IPair(pool).getAmountOut(1e18, oToken);\n\n // Get the amount of OToken received from selling 1 asset. This is buying OToken.\n uint256 oTokenAmount = IPair(pool).getAmountOut(1e18, asset);\n\n // If the pool is degenerate, then the pool is not valid and we can't deposit.\n require(oTokenAmount > 0, \"Pool degenerate\");\n\n // Convert to a OToken/asset price = asset / OToken\n uint256 buyPrice = 1e36 / oTokenAmount;\n\n uint256 pegPrice = 1e18;\n\n require(\n sellPrice >= pegPrice - maxDepeg && buyPrice <= pegPrice + maxDepeg,\n \"price out of range\"\n );\n _;\n }\n\n /**\n * @dev Checks the pool's balances have improved and the balances\n * have not tipped to the other side.\n * This modifier is only applied to functions that do swaps against the pool.\n * Deposits and withdrawals are proportional to the pool's balances hence don't need this check.\n */\n modifier improvePoolBalance() {\n // Get the asset and OToken balances in the pool\n (\n uint256 assetReserveBefore,\n uint256 oTokenReserveBefore\n ) = _getPoolReserves();\n // diff = asset balance - OToken balance\n int256 diffBefore = assetReserveBefore.toInt256() -\n oTokenReserveBefore.toInt256();\n\n _;\n\n // Get the asset and OToken balances in the pool\n (\n uint256 assetReserveAfter,\n uint256 oTokenReserveAfter\n ) = _getPoolReserves();\n // diff = asset balance - OToken balance\n int256 diffAfter = assetReserveAfter.toInt256() -\n oTokenReserveAfter.toInt256();\n\n if (diffBefore == 0) {\n require(diffAfter == 0, \"Position balance is worsened\");\n } else if (diffBefore < 0) {\n // If the pool was originally imbalanced in favor of OToken, then\n // we want to check that the pool is now more balanced\n require(diffAfter <= 0, \"Assets overshot peg\");\n require(diffBefore < diffAfter, \"OTokens balance worse\");\n } else if (diffBefore > 0) {\n // If the pool was originally imbalanced in favor of asset, then\n // we want to check that the pool is now more balanced\n require(diffAfter >= 0, \"OTokens overshot peg\");\n require(diffAfter < diffBefore, \"Assets balance worse\");\n }\n }\n\n /**\n * @param _baseConfig The `platformAddress` is the address of the Algebra pool.\n * The `vaultAddress` is the address of the Origin Vault.\n * @param _gauge Address of the Algebra gauge for the pool.\n * @param _gaugeStakeToken The pool LP token address as reported by the\n * gauge. The inheriting contract is expected to resolve this via\n * whichever getter its gauge exposes (e.g. `IGauge.TOKEN()` for\n * legacy GaugeV2 ≤ v2.4 or `IHydrexGauge.stakeToken()` for\n * Hydrex GaugeV2 ≥ v2.5) and pass the result here. The constructor\n * verifies it matches `_baseConfig.platformAddress`.\n */\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _gauge,\n address _gaugeStakeToken\n ) InitializableAbstractStrategy(_baseConfig) {\n // Read the oToken address from the Vault\n address oTokenMem = IVault(_baseConfig.vaultAddress).oToken();\n address assetMem = IVault(_baseConfig.vaultAddress).asset();\n\n // Checked both tokens are to 18 decimals\n require(\n IBasicToken(assetMem).decimals() == 18 &&\n IBasicToken(oTokenMem).decimals() == 18,\n \"Incorrect token decimals\"\n );\n // Check the Algebra pool is a Stable AMM (sAMM)\n require(\n IPair(_baseConfig.platformAddress).isStable() == true,\n \"Pool not stable\"\n );\n // Check the gauge is wired to the expected pool LP token. The\n // inheriting contract is responsible for fetching `_gaugeStakeToken`\n // from whichever getter the underlying gauge variant exposes.\n require(\n _gaugeStakeToken == _baseConfig.platformAddress,\n \"Incorrect gauge\"\n );\n oTokenPoolIndex = IPair(_baseConfig.platformAddress).token0() ==\n oTokenMem\n ? 0\n : 1;\n // Check the pool tokens are correct\n require(\n IPair(_baseConfig.platformAddress).token0() ==\n (oTokenPoolIndex == 0 ? oTokenMem : assetMem) &&\n IPair(_baseConfig.platformAddress).token1() ==\n (oTokenPoolIndex == 0 ? assetMem : oTokenMem),\n \"Incorrect pool tokens\"\n );\n\n // Set the immutable variables\n oToken = oTokenMem;\n asset = assetMem;\n pool = _baseConfig.platformAddress;\n gauge = _gauge;\n\n // This is an implementation contract. The governor is set in the proxy contract.\n _setGovernor(address(0));\n }\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Algebra strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Array containing SWPx token address\n * @param _maxDepeg The max amount the OToken/asset price can deviate from peg (1e18) before deposits are reverted.\n */\n function initialize(\n address[] calldata _rewardTokenAddresses,\n uint256 _maxDepeg\n ) external onlyGovernor initializer {\n address[] memory pTokens = new address[](1);\n pTokens[0] = pool;\n\n address[] memory _assets = new address[](1);\n _assets[0] = asset;\n\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n pTokens\n );\n\n maxDepeg = _maxDepeg;\n\n _approveBase();\n }\n\n /***************************************\n Deposit\n ****************************************/\n\n /**\n * @notice Deposit an amount of asset into the Algebra pool.\n * Mint OToken in proportion to the pool's asset and OToken reserves,\n * transfer asset and OToken to the pool,\n * mint the pool's LP token and deposit in the gauge.\n * @dev This tx must be wrapped by the VaultValueChecker.\n * To minimize loses, the pool should be rebalanced before depositing.\n * The pool's oToken/asset price must be within the maxDepeg range.\n * @param _asset Address of asset token.\n * @param _assetAmount Amount of asset tokens to deposit.\n */\n function deposit(address _asset, uint256 _assetAmount)\n external\n override\n onlyVault\n nonReentrant\n skimPool\n nearBalancedPool\n {\n require(_asset == asset, \"Unsupported asset\");\n require(_assetAmount > 0, \"Must deposit something\");\n\n (uint256 oTokenDepositAmount, ) = _deposit(_assetAmount);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n // Emit event for the deposited asset tokens\n emit Deposit(asset, pool, _assetAmount);\n // Emit event for the minted OToken tokens\n emit Deposit(oToken, pool, oTokenDepositAmount);\n }\n\n /**\n * @notice Deposit all the strategy's asset tokens into the Algebra pool.\n * Mint OToken in proportion to the pool's asset and OToken reserves,\n * transfer asset and OToken to the pool,\n * mint the pool's LP token and deposit in the gauge.\n * @dev This tx must be wrapped by the VaultValueChecker.\n * To minimize loses, the pool should be rebalanced before depositing.\n * The pool's oToken/asset price must be within the maxDepeg range.\n */\n function depositAll()\n external\n override\n onlyVault\n nonReentrant\n skimPool\n nearBalancedPool\n {\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\n if (assetBalance > 0) {\n (uint256 oTokenDepositAmount, ) = _deposit(assetBalance);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n // Emit event for the deposited asset tokens\n emit Deposit(asset, pool, assetBalance);\n // Emit event for the minted OToken tokens\n emit Deposit(oToken, pool, oTokenDepositAmount);\n }\n }\n\n /**\n * @dev Mint OToken in proportion to the pool's asset and OToken reserves,\n * transfer asset and OToken to the pool,\n * mint the pool's LP token and deposit in the gauge.\n * @param _assetAmount Amount of asset tokens to deposit.\n * @return oTokenDepositAmount Amount of OToken tokens minted and deposited into the pool.\n * @return lpTokens Amount of Algebra pool LP tokens minted and deposited into the gauge.\n */\n function _deposit(uint256 _assetAmount)\n internal\n returns (uint256 oTokenDepositAmount, uint256 lpTokens)\n {\n // Calculate the required amount of OToken to mint based on the asset amount.\n oTokenDepositAmount = _calcTokensToMint(_assetAmount);\n\n // Mint the required OToken tokens to this strategy\n IVault(vaultAddress).mintForStrategy(oTokenDepositAmount);\n\n // Add asset and OToken liquidity to the pool and stake in gauge\n lpTokens = _depositToPoolAndGauge(_assetAmount, oTokenDepositAmount);\n }\n\n /***************************************\n Withdraw\n ****************************************/\n\n /**\n * @notice Withdraw asset and OToken from the Algebra pool, burn the OToken,\n * and transfer the asset to the recipient.\n * @param _recipient Address of the Vault.\n * @param _asset Address of the asset token.\n * @param _assetAmount Amount of asset tokens to withdraw.\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _assetAmount\n ) external override onlyVault nonReentrant skimPool {\n require(_assetAmount > 0, \"Must withdraw something\");\n require(_asset == asset, \"Unsupported asset\");\n // This strategy can't be set as a default strategy for asset in the Vault.\n // This means the recipient must always be the Vault.\n require(_recipient == vaultAddress, \"Only withdraw to vault allowed\");\n\n // Calculate how much pool LP tokens to burn to get the required amount of asset tokens back\n uint256 lpTokens = _calcTokensToBurn(_assetAmount);\n\n // Withdraw pool LP tokens from the gauge and remove assets from from the pool\n _withdrawFromGaugeAndPool(lpTokens);\n\n // Burn all the removed OToken and any that was left in the strategy\n uint256 oTokenToBurn = IERC20(oToken).balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oTokenToBurn);\n\n // Transfer asset to the recipient\n // Note there can be a dust amount of asset left in the strategy as\n // the burn of the pool's LP tokens is rounded up\n require(\n IERC20(asset).balanceOf(address(this)) >= _assetAmount,\n \"Not enough asset removed\"\n );\n IERC20(asset).safeTransfer(_recipient, _assetAmount);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n // Emit event for the withdrawn asset tokens\n emit Withdrawal(asset, pool, _assetAmount);\n // Emit event for the burnt OToken tokens\n emit Withdrawal(oToken, pool, oTokenToBurn);\n }\n\n /**\n * @notice Withdraw all pool LP tokens from the gauge,\n * remove all asset and OToken from the Algebra pool,\n * burn all the OToken,\n * and transfer all the asset to the Vault contract.\n * @dev There is no solvency check here as withdrawAll can be called to\n * quickly secure assets to the Vault in emergencies.\n */\n function withdrawAll()\n external\n override\n onlyVaultOrGovernor\n nonReentrant\n skimPool\n {\n // Get all the pool LP tokens the strategy has staked in the gauge\n uint256 lpTokens = IGauge(gauge).balanceOf(address(this));\n // Can not withdraw zero LP tokens from the gauge\n if (lpTokens == 0) return;\n\n if (IGauge(gauge).emergency()) {\n // The gauge is in emergency mode\n _emergencyWithdrawFromGaugeAndPool();\n } else {\n // Withdraw pool LP tokens from the gauge and remove assets from from the pool\n _withdrawFromGaugeAndPool(lpTokens);\n }\n\n // Burn all OToken in this strategy contract\n uint256 oTokenToBurn = IERC20(oToken).balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oTokenToBurn);\n\n // Get the strategy contract's asset balance.\n // This includes all that was removed from the Algebra pool and\n // any that was sitting in the strategy contract before the removal.\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\n IERC20(asset).safeTransfer(vaultAddress, assetBalance);\n\n // Emit event for the withdrawn asset tokens\n emit Withdrawal(asset, pool, assetBalance);\n // Emit event for the burnt OToken tokens\n emit Withdrawal(oToken, pool, oTokenToBurn);\n }\n\n /***************************************\n Pool Rebalancing\n ****************************************/\n\n /** @notice Used when there is more OToken than asset in the pool.\n * asset and OToken is removed from the pool, the received asset is swapped for OToken\n * and the left over OToken in the strategy is burnt.\n * The OToken/asset price is < 1.0 so OToken is being bought at a discount.\n * @param _assetAmount Amount of asset tokens to swap into the pool.\n */\n function swapAssetsToPool(uint256 _assetAmount)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n skimPool\n {\n require(_assetAmount > 0, \"Must swap something\");\n\n // 1. Partially remove liquidity so there’s enough asset for the swap\n\n // Calculate how much pool LP tokens to burn to get the required amount of asset tokens back\n uint256 lpTokens = _calcTokensToBurn(_assetAmount);\n require(lpTokens > 0, \"No LP tokens to burn\");\n\n _withdrawFromGaugeAndPool(lpTokens);\n\n // 2. Swap asset for OToken against the pool\n // Swap exact amount of asset for OToken against the pool\n // There can be a dust amount of asset left in the strategy as the burn of the pool's LP tokens is rounded up\n _swapExactTokensForTokens(_assetAmount, asset, oToken);\n\n // 3. Burn all the OToken left in the strategy from the remove liquidity and swap\n uint256 oTokenToBurn = IERC20(oToken).balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oTokenToBurn);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n // Emit event for the burnt OToken tokens\n emit Withdrawal(oToken, pool, oTokenToBurn);\n // Emit event for the swap\n emit SwapAssetsToPool(_assetAmount, lpTokens, oTokenToBurn);\n }\n\n /**\n * @notice Used when there is more asset than OToken in the pool.\n * OToken is minted and swapped for asset against the pool,\n * more OToken is minted and added back into the pool with the swapped out asset.\n * The OToken/asset price is > 1.0 so OToken is being sold at a premium.\n * @param _oTokenAmount Amount of OToken to swap into the pool.\n */\n function swapOTokensToPool(uint256 _oTokenAmount)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n skimPool\n {\n require(_oTokenAmount > 0, \"Must swap something\");\n\n // 1. Mint OToken so it can be swapped into the pool\n\n // There can be OToken in the strategy from skimming the pool\n uint256 oTokenInStrategy = IERC20(oToken).balanceOf(address(this));\n require(\n _oTokenAmount >= oTokenInStrategy,\n \"Too much OToken in strategy\"\n );\n uint256 oTokenToMint = _oTokenAmount - oTokenInStrategy;\n\n // Mint the required OToken tokens to this strategy\n IVault(vaultAddress).mintForStrategy(oTokenToMint);\n\n // 2. Swap OToken for asset against the pool\n _swapExactTokensForTokens(_oTokenAmount, oToken, asset);\n\n // The asset is from the swap and any asset that was sitting in the strategy\n uint256 assetDepositAmount = IERC20(asset).balanceOf(address(this));\n\n // 3. Add asset and OToken back to the pool in proportion to the pool's reserves\n (uint256 oTokenDepositAmount, uint256 lpTokens) = _deposit(\n assetDepositAmount\n );\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n // Emit event for the minted OToken tokens\n emit Deposit(oToken, pool, oTokenToMint + oTokenDepositAmount);\n // Emit event for the swap\n emit SwapOTokensToPool(\n oTokenToMint,\n assetDepositAmount,\n oTokenDepositAmount,\n lpTokens\n );\n }\n\n /***************************************\n Assets and Rewards\n ****************************************/\n\n /**\n * @notice Get the asset value of assets in the strategy and Algebra pool.\n * The value of the assets in the pool is calculated assuming the pool is balanced.\n * This way the value can not be manipulated by changing the pool's token balances.\n * @param _asset Address of the asset token\n * @return balance Total value in asset.\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == asset, \"Unsupported asset\");\n\n // asset balance needed here for the balance check that happens from vault during depositing.\n balance = IERC20(asset).balanceOf(address(this));\n\n // This assumes 1 gauge LP token = 1 pool LP token\n uint256 lpTokens = IGauge(gauge).balanceOf(address(this));\n if (lpTokens == 0) return balance;\n\n // Add the strategy’s share of the asset and OToken tokens in the Algebra pool if the pool was balanced.\n balance += _lpValue(lpTokens);\n }\n\n /**\n * @notice Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == asset;\n }\n\n /**\n * @notice Collect accumulated SWPx (and other) rewards and send to the Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvesterOrStrategist\n nonReentrant\n {\n // Collect SWPx rewards from the gauge\n IGauge(gauge).getReward();\n\n _collectRewardTokens();\n }\n\n /***************************************\n Internal Algebra Pool and Gauge Functions\n ****************************************/\n\n /**\n * @dev Calculate the required amount of OToken to mint based on the asset amount.\n * This ensures the proportion of OToken tokens being added to the pool matches the proportion of asset tokens.\n * For example, if the added asset tokens is 10% of existing asset tokens in the pool,\n * then the OToken tokens being added should also be 10% of the OToken tokens in the pool.\n * @param _assetAmount Amount of asset tokens to be added to the pool.\n * @return oTokenAmount Amount of OToken tokens to be minted and added to the pool.\n */\n function _calcTokensToMint(uint256 _assetAmount)\n internal\n view\n returns (uint256 oTokenAmount)\n {\n (uint256 assetReserves, uint256 oTokenReserves) = _getPoolReserves();\n require(assetReserves > 0, \"Empty pool\");\n\n // OToken to add = (asset being added * OToken in pool) / asset in pool\n oTokenAmount = (_assetAmount * oTokenReserves) / assetReserves;\n }\n\n /**\n * @dev Calculate how much pool LP tokens to burn to get the required amount of asset tokens back\n * from the pool.\n * @param _assetAmount Amount of asset tokens to be removed from the pool.\n * @return lpTokens Amount of Algebra pool LP tokens to burn.\n */\n function _calcTokensToBurn(uint256 _assetAmount)\n internal\n view\n returns (uint256 lpTokens)\n {\n /* The Algebra pool proportionally returns the reserve tokens when removing liquidity.\n * First, calculate the proportion of required asset tokens against the pools asset reserves.\n * That same proportion is used to calculate the required amount of pool LP tokens.\n * For example, if the required asset tokens is 10% of the pool's asset reserves,\n * then 10% of the pool's LP supply needs to be burned.\n *\n * Because we are doing balanced removal we should be making profit when removing liquidity in a\n * pool tilted to either side.\n *\n * Important: A downside is that the Strategist / Governor needs to be\n * cognizant of not removing too much liquidity. And while the proposal to remove liquidity\n * is being voted on, the pool tilt might change so much that the proposal that has been valid while\n * created is no longer valid.\n */\n\n (uint256 assetReserves, ) = _getPoolReserves();\n require(assetReserves > 0, \"Empty pool\");\n\n lpTokens = (_assetAmount * IPair(pool).totalSupply()) / assetReserves;\n lpTokens += 1; // Add 1 to ensure we get enough LP tokens with rounding\n }\n\n /**\n * @dev Deposit asset and OToken liquidity to the Algebra pool\n * and stake the pool's LP token in the gauge.\n * @param _assetAmount Amount of asset to deposit.\n * @param _oTokenAmount Amount of OToken to deposit.\n * @return lpTokens Amount of Algebra pool LP tokens minted.\n */\n function _depositToPoolAndGauge(uint256 _assetAmount, uint256 _oTokenAmount)\n internal\n returns (uint256 lpTokens)\n {\n // Transfer asset to the pool\n IERC20(asset).safeTransfer(pool, _assetAmount);\n // Transfer OToken to the pool\n IERC20(oToken).safeTransfer(pool, _oTokenAmount);\n\n // Mint LP tokens from the pool\n lpTokens = IPair(pool).mint(address(this));\n\n // Deposit the pool's LP tokens into the gauge\n IGauge(gauge).deposit(lpTokens);\n }\n\n /**\n * @dev Withdraw pool LP tokens from the gauge and remove asset and OToken from the pool.\n * @param _lpTokens Amount of Algebra pool LP tokens to withdraw from the gauge\n */\n function _withdrawFromGaugeAndPool(uint256 _lpTokens) internal {\n require(\n IGauge(gauge).balanceOf(address(this)) >= _lpTokens,\n \"Not enough LP tokens in gauge\"\n );\n\n // Withdraw pool LP tokens from the gauge\n IGauge(gauge).withdraw(_lpTokens);\n\n // Transfer the pool LP tokens to the pool\n IERC20(pool).safeTransfer(pool, _lpTokens);\n\n // Burn the LP tokens and transfer the asset and OToken back to the strategy\n IPair(pool).burn(address(this));\n }\n\n /**\n * @dev Withdraw all pool LP tokens from the gauge when it's in emergency mode\n * and remove asset and OToken from the pool.\n */\n function _emergencyWithdrawFromGaugeAndPool() internal {\n // Withdraw all pool LP tokens from the gauge\n IGauge(gauge).emergencyWithdraw();\n\n // Get the pool LP tokens in strategy\n uint256 _lpTokens = IERC20(pool).balanceOf(address(this));\n\n // Transfer the pool LP tokens to the pool\n IERC20(pool).safeTransfer(pool, _lpTokens);\n\n // Burn the LP tokens and transfer the asset and OToken back to the strategy\n IPair(pool).burn(address(this));\n }\n\n /**\n * @dev Swap exact amount of tokens for another token against the pool.\n * @param _amountIn Amount of tokens to swap into the pool.\n * @param _tokenIn Address of the token going into the pool.\n * @param _tokenOut Address of the token being swapped out of the pool.\n */\n function _swapExactTokensForTokens(\n uint256 _amountIn,\n address _tokenIn,\n address _tokenOut\n ) internal {\n // Calculate how much out tokens we get from the swap\n uint256 amountOut = IPair(pool).getAmountOut(_amountIn, _tokenIn);\n\n // Transfer in tokens to the pool after the amountOut calculation has been mde.\n // This way we don't have to worry about sending tokens to pool confusing the pool's reserves.\n IERC20(_tokenIn).safeTransfer(pool, _amountIn);\n\n // Safety check that we are dealing with the correct pool tokens\n require(\n (_tokenIn == asset && _tokenOut == oToken) ||\n (_tokenIn == oToken && _tokenOut == asset),\n \"Unsupported swap\"\n );\n\n uint256 amount0;\n uint256 amount1;\n\n // Work out the correct order of the amounts for the pool\n if (_tokenIn == asset) {\n if (oTokenPoolIndex == 0) {\n amount0 = amountOut;\n amount1 = 0;\n } else {\n amount0 = 0;\n amount1 = amountOut;\n }\n } else {\n if (oTokenPoolIndex == 0) {\n amount0 = 0;\n amount1 = amountOut;\n } else {\n amount0 = amountOut;\n amount1 = 0;\n }\n }\n\n // Perform the swap on the pool\n IPair(pool).swap(amount0, amount1, address(this), new bytes(0));\n\n // The slippage protection against the amount out is indirectly done\n // via the improvePoolBalance\n }\n\n /// @dev Calculate the value of a LP position in a Algebra stable pool\n /// if the pool was balanced.\n /// @param _lpTokens Amount of LP tokens in the Algebra pool\n /// @return value The asset value of the LP tokens when the pool is balanced\n function _lpValue(uint256 _lpTokens) internal view returns (uint256 value) {\n // Get total supply of LP tokens\n uint256 totalSupply = IPair(pool).totalSupply();\n if (totalSupply == 0) return 0;\n\n // Get the current reserves of the pool\n (uint256 assetReserves, uint256 oTokenReserves) = _getPoolReserves();\n\n // Calculate the invariant of the pool assuming both tokens have 18 decimals.\n // k is scaled to 18 decimals.\n uint256 k = _invariant(assetReserves, oTokenReserves);\n\n // If x = y, let’s denote x = y = z (where z is the common reserve value)\n // Substitute z into the invariant:\n // k = z^3 * z + z * z^3\n // k = 2 * z^4\n // Going back the other way to calculate the common reserve value z\n // z = (k / 2) ^ (1/4)\n // the total value of the pool when x = y is 2 * z, which is 2 * (k / 2) ^ (1/4)\n uint256 zSquared = sqrt((k * 1e18) / 2); // 18 + 18 = 36 decimals becomes 18 decimals after sqrt\n uint256 z = sqrt(zSquared * 1e18); // 18 + 18 = 36 decimals becomes 18 decimals after sqrt\n uint256 totalValueOfPool = 2 * z;\n\n // lp value = lp tokens * value of pool / total supply\n value = (_lpTokens * totalValueOfPool) / totalSupply;\n }\n\n /**\n * @dev Compute the invariant for a Algebra stable pool.\n * This assumed both x and y tokens are to 18 decimals which is checked in the constructor.\n * invariant: k = x^3 * y + x * y^3\n * @dev This implementation is copied from Algebra's Pair contract.\n * @param _x The amount of asset tokens in the pool\n * @param _y The amount of the OToken tokens in the pool\n * @return k The invariant of the Algebra stable pool\n */\n function _invariant(uint256 _x, uint256 _y)\n internal\n pure\n returns (uint256 k)\n {\n uint256 _a = (_x * _y) / PRECISION;\n uint256 _b = ((_x * _x) / PRECISION + (_y * _y) / PRECISION);\n // slither-disable-next-line divide-before-multiply\n k = (_a * _b) / PRECISION;\n }\n\n /**\n * @dev Checks that the protocol is solvent, protecting from a rogue Strategist / Guardian that can\n * keep rebalancing the pool in both directions making the protocol lose a tiny amount of\n * funds each time.\n *\n * Protocol must be at least SOLVENCY_THRESHOLD (99,8 %) backed in order for the rebalances to\n * function.\n */\n function _solvencyAssert() internal view {\n uint256 _totalVaultValue = IVault(vaultAddress).totalValue();\n uint256 _totalSupply = IERC20(oToken).totalSupply();\n\n if (\n _totalSupply > 0 &&\n _totalVaultValue.divPrecisely(_totalSupply) < SOLVENCY_THRESHOLD\n ) {\n revert(\"Protocol insolvent\");\n }\n }\n\n /**\n * @dev Get the reserves of the pool no matter the order of tokens in the underlying\n * Algebra pool.\n * @return assetReserves The reserves of the asset token in the pool.\n * @return oTokenReserves The reserves of the OToken token in the pool.\n */\n function _getPoolReserves()\n internal\n view\n returns (uint256 assetReserves, uint256 oTokenReserves)\n {\n (uint256 reserve0, uint256 reserve1, ) = IPair(pool).getReserves();\n assetReserves = oTokenPoolIndex == 0 ? reserve1 : reserve0;\n oTokenReserves = oTokenPoolIndex == 0 ? reserve0 : reserve1;\n }\n\n /***************************************\n Setters\n ****************************************/\n\n /**\n * @notice Set the maximum deviation from the OToken/asset peg (1e18) before deposits are reverted.\n * @param _maxDepeg the OToken/asset price from peg (1e18) in 18 decimals.\n * eg 0.01e18 or 1e16 is 1% which is 100 basis points.\n */\n function setMaxDepeg(uint256 _maxDepeg) external onlyGovernor {\n require(\n _maxDepeg >= 0.001 ether && _maxDepeg <= 0.1 ether,\n \"Invalid max depeg range\"\n );\n maxDepeg = _maxDepeg;\n\n emit MaxDepegUpdated(_maxDepeg);\n }\n\n /***************************************\n Approvals\n ****************************************/\n\n /**\n * @notice Approve the spending of all assets by their corresponding pool tokens,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n _approveBase();\n }\n\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {}\n\n function _approveBase() internal {\n // Approve Algebra gauge contract to transfer Algebra pool LP tokens\n // This is needed for deposits of Algebra pool LP tokens into the gauge.\n // slither-disable-next-line unused-return\n IPair(pool).approve(address(gauge), type(uint256).max);\n }\n}\n" + }, + "contracts/strategies/BaseCurveAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Curve Automated Market Maker (AMO) Strategy\n * @notice AMO strategy for the Curve OETH/WETH pool\n * @author Origin Protocol Inc\n */\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { ICurveStableSwapNG } from \"../interfaces/ICurveStableSwapNG.sol\";\nimport { ICurveXChainLiquidityGauge } from \"../interfaces/ICurveXChainLiquidityGauge.sol\";\nimport { IChildLiquidityGaugeFactory } from \"../interfaces/IChildLiquidityGaugeFactory.sol\";\n\ncontract BaseCurveAMOStrategy is InitializableAbstractStrategy {\n using StableMath for uint256;\n using SafeCast for uint256;\n\n /**\n * @dev a threshold under which the contract no longer allows for the protocol to manually rebalance.\n * Guarding against a strategist / guardian being taken over and with multiple transactions\n * draining the protocol funds.\n */\n uint256 public constant SOLVENCY_THRESHOLD = 0.998 ether;\n\n // New immutable variables that must be set in the constructor\n /**\n * @notice Address of the Wrapped ETH (WETH) contract.\n */\n IWETH9 public immutable weth;\n\n /**\n * @notice Address of the OETH token contract.\n */\n IERC20 public immutable oeth;\n\n /**\n * @notice Address of the LP (Liquidity Provider) token contract.\n */\n IERC20 public immutable lpToken;\n\n /**\n * @notice Address of the Curve StableSwap NG pool contract.\n */\n ICurveStableSwapNG public immutable curvePool;\n\n /**\n * @notice Address of the Curve X-Chain Liquidity Gauge contract.\n */\n ICurveXChainLiquidityGauge public immutable gauge;\n\n /**\n * @notice Address of the Child Liquidity Gauge Factory contract.\n */\n IChildLiquidityGaugeFactory public immutable gaugeFactory;\n\n // Ordered list of pool assets\n uint128 public immutable oethCoinIndex;\n uint128 public immutable wethCoinIndex;\n\n /**\n * @notice Maximum slippage allowed for adding/removing liquidity from the Curve pool.\n */\n uint256 public maxSlippage;\n\n event MaxSlippageUpdated(uint256 newMaxSlippage);\n\n /**\n * @dev Verifies that the caller is the Strategist.\n */\n modifier onlyStrategist() {\n require(\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n _;\n }\n\n /**\n * @dev Checks the Curve pool's balances have improved and the balances\n * have not tipped to the other side.\n * This modifier is only applied to functions that do a single sided add or remove.\n * The standard deposit function adds to both sides of the pool in a way that\n * the pool's balance is not worsened.\n * Withdrawals are proportional so doesn't change the pools asset balance.\n */\n modifier improvePoolBalance() {\n // Get the asset and OToken balances in the Curve pool\n uint256[] memory balancesBefore = curvePool.get_balances();\n // diff = ETH balance - OETH balance\n int256 diffBefore = balancesBefore[wethCoinIndex].toInt256() -\n balancesBefore[oethCoinIndex].toInt256();\n\n _;\n\n // Get the asset and OToken balances in the Curve pool\n uint256[] memory balancesAfter = curvePool.get_balances();\n // diff = ETH balance - OETH balance\n int256 diffAfter = balancesAfter[wethCoinIndex].toInt256() -\n balancesAfter[oethCoinIndex].toInt256();\n\n if (diffBefore == 0) {\n require(diffAfter == 0, \"Position balance is worsened\");\n } else if (diffBefore < 0) {\n // If the pool was originally imbalanced in favor of OETH, then\n // we want to check that the pool is now more balanced\n require(diffAfter <= 0, \"OTokens overshot peg\");\n require(diffBefore < diffAfter, \"OTokens balance worse\");\n } else if (diffBefore > 0) {\n // If the pool was originally imbalanced in favor of ETH, then\n // we want to check that the pool is now more balanced\n require(diffAfter >= 0, \"Assets overshot peg\");\n require(diffAfter < diffBefore, \"Assets balance worse\");\n }\n }\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _oeth,\n address _weth,\n address _gauge,\n address _gaugeFactory,\n uint128 _oethCoinIndex,\n uint128 _wethCoinIndex\n ) InitializableAbstractStrategy(_baseConfig) {\n oethCoinIndex = _oethCoinIndex;\n wethCoinIndex = _wethCoinIndex;\n\n lpToken = IERC20(_baseConfig.platformAddress);\n curvePool = ICurveStableSwapNG(_baseConfig.platformAddress);\n\n oeth = IERC20(_oeth);\n weth = IWETH9(_weth);\n gauge = ICurveXChainLiquidityGauge(_gauge);\n gaugeFactory = IChildLiquidityGaugeFactory(_gaugeFactory);\n\n _setGovernor(address(0));\n }\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Curve strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Address of CRV\n * @param _maxSlippage Maximum slippage allowed for adding/removing liquidity from the Curve pool.\n */\n function initialize(\n address[] calldata _rewardTokenAddresses, // CRV\n uint256 _maxSlippage\n ) external onlyGovernor initializer {\n address[] memory pTokens = new address[](1);\n pTokens[0] = address(curvePool);\n\n address[] memory _assets = new address[](1);\n _assets[0] = address(weth);\n\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n pTokens\n );\n\n _approveBase();\n _setMaxSlippage(_maxSlippage);\n }\n\n /***************************************\n Deposit\n ****************************************/\n\n /**\n * @notice Deposit WETH into the Curve pool\n * @param _weth Address of Wrapped ETH (WETH) contract.\n * @param _amount Amount of WETH to deposit.\n */\n function deposit(address _weth, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_weth, _amount);\n }\n\n function _deposit(address _weth, uint256 _wethAmount) internal {\n require(_wethAmount > 0, \"Must deposit something\");\n require(_weth == address(weth), \"Can only deposit WETH\");\n\n emit Deposit(_weth, address(lpToken), _wethAmount);\n\n // Get the asset and OToken balances in the Curve pool\n uint256[] memory balances = curvePool.get_balances();\n // safe to cast since min value is at least 0\n uint256 oethToAdd = uint256(\n _max(\n 0,\n balances[wethCoinIndex].toInt256() +\n _wethAmount.toInt256() -\n balances[oethCoinIndex].toInt256()\n )\n );\n\n /* Add so much OETH so that the pool ends up being balanced. And at minimum\n * add as much OETH as WETH and at maximum twice as much OETH.\n */\n oethToAdd = Math.max(oethToAdd, _wethAmount);\n oethToAdd = Math.min(oethToAdd, _wethAmount * 2);\n\n /* Mint OETH with a strategy that attempts to contribute to stability of OETH/WETH pool. Try\n * to mint so much OETH that after deployment of liquidity pool ends up being balanced.\n *\n * To manage unpredictability minimal OETH minted will always be at least equal or greater\n * to WETH amount deployed. And never larger than twice the WETH amount deployed even if\n * it would have a further beneficial effect on pool stability.\n */\n IVault(vaultAddress).mintForStrategy(oethToAdd);\n\n emit Deposit(address(oeth), address(lpToken), oethToAdd);\n\n uint256[] memory _amounts = new uint256[](2);\n _amounts[wethCoinIndex] = _wethAmount;\n _amounts[oethCoinIndex] = oethToAdd;\n\n uint256 valueInLpTokens = (_wethAmount + oethToAdd).divPrecisely(\n curvePool.get_virtual_price()\n );\n uint256 minMintAmount = valueInLpTokens.mulTruncate(\n uint256(1e18) - maxSlippage\n );\n\n // Do the deposit to the Curve pool\n uint256 lpDeposited = curvePool.add_liquidity(_amounts, minMintAmount);\n require(lpDeposited >= minMintAmount, \"Min LP amount error\");\n\n // Deposit the Curve pool's LP tokens into the Curve gauge\n gauge.deposit(lpDeposited);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n }\n\n /**\n * @notice Deposit the strategy's entire balance of WETH into the Curve pool\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 balance = weth.balanceOf(address(this));\n if (balance > 0) {\n _deposit(address(weth), balance);\n }\n }\n\n /***************************************\n Withdraw\n ****************************************/\n\n /**\n * @notice Withdraw ETH and OETH from the Curve pool, burn the OETH,\n * convert the ETH to WETH and transfer to the recipient.\n * @param _recipient Address to receive withdrawn asset which is normally the Vault.\n * @param _weth Address of the Wrapped ETH (WETH) contract.\n * @param _amount Amount of WETH to withdraw.\n */\n function withdraw(\n address _recipient,\n address _weth,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(_weth == address(weth), \"Can only withdraw WETH\");\n\n emit Withdrawal(_weth, address(lpToken), _amount);\n\n uint256 requiredLpTokens = calcTokenToBurn(_amount);\n\n _lpWithdraw(requiredLpTokens);\n\n /* math in requiredLpTokens should correctly calculate the amount of LP to remove\n * in that the strategy receives enough WETH on balanced removal\n */\n uint256[] memory _minWithdrawalAmounts = new uint256[](2);\n _minWithdrawalAmounts[wethCoinIndex] = _amount;\n // slither-disable-next-line unused-return\n curvePool.remove_liquidity(requiredLpTokens, _minWithdrawalAmounts);\n\n // Burn all the removed OETH and any that was left in the strategy\n uint256 oethToBurn = oeth.balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n\n emit Withdrawal(address(oeth), address(lpToken), oethToBurn);\n\n // Transfer WETH to the recipient\n require(\n weth.transfer(_recipient, _amount),\n \"Transfer of WETH not successful\"\n );\n\n // Ensure solvency of the vault\n _solvencyAssert();\n }\n\n function calcTokenToBurn(uint256 _wethAmount)\n internal\n view\n returns (uint256 lpToBurn)\n {\n /* The rate between coins in the pool determines the rate at which pool returns\n * tokens when doing balanced removal (remove_liquidity call). And by knowing how much WETH\n * we want we can determine how much of OETH we receive by removing liquidity.\n *\n * Because we are doing balanced removal we should be making profit when removing liquidity in a\n * pool tilted to either side.\n *\n * Important: A downside is that the Strategist / Governor needs to be\n * cognisant of not removing too much liquidity. And while the proposal to remove liquidity\n * is being voted on the pool tilt might change so much that the proposal that has been valid while\n * created is no longer valid.\n */\n\n uint256 poolWETHBalance = curvePool.balances(wethCoinIndex);\n /* K is multiplied by 1e36 which is used for higher precision calculation of required\n * pool LP tokens. Without it the end value can have rounding errors up to precision of\n * 10 digits. This way we move the decimal point by 36 places when doing the calculation\n * and again by 36 places when we are done with it.\n */\n uint256 k = (1e36 * lpToken.totalSupply()) / poolWETHBalance;\n // prettier-ignore\n // slither-disable-next-line divide-before-multiply\n uint256 diff = (_wethAmount + 1) * k;\n lpToBurn = diff / 1e36;\n }\n\n /**\n * @notice Remove all ETH and OETH from the Curve pool, burn the OETH,\n * convert the ETH to WETH and transfer to the Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 gaugeTokens = gauge.balanceOf(address(this));\n // Can not withdraw zero LP tokens from the gauge\n if (gaugeTokens == 0) return;\n _lpWithdraw(gaugeTokens);\n\n // Withdraws are proportional to assets held by 3Pool\n uint256[] memory minWithdrawAmounts = new uint256[](2);\n\n // Remove liquidity\n // slither-disable-next-line unused-return\n curvePool.remove_liquidity(\n lpToken.balanceOf(address(this)),\n minWithdrawAmounts\n );\n\n // Burn all OETH\n uint256 oethToBurn = oeth.balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n\n // Get the strategy contract's WETH balance.\n // This includes all that was removed from the Curve pool and\n // any ether that was sitting in the strategy contract before the removal.\n uint256 ethBalance = weth.balanceOf(address(this));\n require(\n weth.transfer(vaultAddress, ethBalance),\n \"Transfer of WETH not successful\"\n );\n\n emit Withdrawal(address(weth), address(lpToken), ethBalance);\n emit Withdrawal(address(oeth), address(lpToken), oethToBurn);\n }\n\n /***************************************\n Curve pool Rebalancing\n ****************************************/\n\n /**\n * @notice Mint OTokens and one-sided add to the Curve pool.\n * This is used when the Curve pool does not have enough OTokens and too many ETH.\n * The OToken/Asset, eg OETH/ETH, price with increase.\n * The amount of assets in the vault is unchanged.\n * The total supply of OTokens is increased.\n * The asset value of the strategy and vault is increased.\n * @param _oTokens The amount of OTokens to be minted and added to the pool.\n */\n function mintAndAddOTokens(uint256 _oTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n IVault(vaultAddress).mintForStrategy(_oTokens);\n\n uint256[] memory amounts = new uint256[](2);\n amounts[oethCoinIndex] = _oTokens;\n\n // Convert OETH to Curve pool LP tokens\n uint256 valueInLpTokens = (_oTokens).divPrecisely(\n curvePool.get_virtual_price()\n );\n // Apply slippage to LP tokens\n uint256 minMintAmount = valueInLpTokens.mulTruncate(\n uint256(1e18) - maxSlippage\n );\n\n // Add the minted OTokens to the Curve pool\n uint256 lpDeposited = curvePool.add_liquidity(amounts, minMintAmount);\n require(lpDeposited >= minMintAmount, \"Min LP amount error\");\n\n // Deposit the Curve pool LP tokens to the Curve gauge\n gauge.deposit(lpDeposited);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Deposit(address(oeth), address(lpToken), _oTokens);\n }\n\n /**\n * @notice One-sided remove of OTokens from the Curve pool which are then burned.\n * This is used when the Curve pool has too many OTokens and not enough ETH.\n * The amount of assets in the vault is unchanged.\n * The total supply of OTokens is reduced.\n * The asset value of the strategy and vault is reduced.\n * @param _lpTokens The amount of Curve pool LP tokens to be burned for OTokens.\n */\n function removeAndBurnOTokens(uint256 _lpTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n // Withdraw Curve pool LP tokens from Convex and remove OTokens from the Curve pool\n uint256 oethToBurn = _withdrawAndRemoveFromPool(\n _lpTokens,\n oethCoinIndex\n );\n\n // The vault burns the OTokens from this strategy\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Withdrawal(address(oeth), address(lpToken), oethToBurn);\n }\n\n /**\n * @notice One-sided remove of ETH from the Curve pool, convert to WETH\n * and transfer to the vault.\n * This is used when the Curve pool does not have enough OTokens and too many ETH.\n * The OToken/Asset, eg OETH/ETH, price with decrease.\n * The amount of assets in the vault increases.\n * The total supply of OTokens does not change.\n * The asset value of the strategy reduces.\n * The asset value of the vault should be close to the same.\n * @param _lpTokens The amount of Curve pool LP tokens to be burned for ETH.\n * @dev Curve pool LP tokens is used rather than WETH assets as Curve does not\n * have a way to accurately calculate the amount of LP tokens for a required\n * amount of ETH. Curve's `calc_token_amount` functioun does not include fees.\n * A 3rd party libary can be used that takes into account the fees, but this\n * is a gas intensive process. It's easier for the trusted strategist to\n * caclulate the amount of Curve pool LP tokens required off-chain.\n */\n function removeOnlyAssets(uint256 _lpTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n // Withdraw Curve pool LP tokens from Curve gauge and remove ETH from the Curve pool\n uint256 ethAmount = _withdrawAndRemoveFromPool(\n _lpTokens,\n wethCoinIndex\n );\n\n // Transfer WETH to the vault\n require(\n weth.transfer(vaultAddress, ethAmount),\n \"Transfer of WETH not successful\"\n );\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Withdrawal(address(weth), address(lpToken), ethAmount);\n }\n\n /**\n * @dev Remove Curve pool LP tokens from the Convex pool and\n * do a one-sided remove of ETH or OETH from the Curve pool.\n * @param _lpTokens The amount of Curve pool LP tokens to be removed from the Convex pool.\n * @param coinIndex The index of the coin to be removed from the Curve pool. 0 = ETH, 1 = OETH.\n * @return coinsRemoved The amount of ETH or OETH removed from the Curve pool.\n */\n function _withdrawAndRemoveFromPool(uint256 _lpTokens, uint128 coinIndex)\n internal\n returns (uint256 coinsRemoved)\n {\n // Withdraw Curve pool LP tokens from Curve gauge\n _lpWithdraw(_lpTokens);\n\n // Convert Curve pool LP tokens to ETH value\n uint256 valueInEth = _lpTokens.mulTruncate(\n curvePool.get_virtual_price()\n );\n // Apply slippage to ETH value\n uint256 minAmount = valueInEth.mulTruncate(uint256(1e18) - maxSlippage);\n\n // Remove just the ETH from the Curve pool\n coinsRemoved = curvePool.remove_liquidity_one_coin(\n _lpTokens,\n int128(coinIndex),\n minAmount,\n address(this)\n );\n }\n\n /**\n * Checks that the protocol is solvent, protecting from a rogue Strategist / Guardian that can\n * keep rebalancing the pool in both directions making the protocol lose a tiny amount of\n * funds each time.\n *\n * Protocol must be at least SOLVENCY_THRESHOLD (99,8 %) backed in order for the rebalances to\n * function.\n */\n function _solvencyAssert() internal view {\n uint256 _totalVaultValue = IVault(vaultAddress).totalValue();\n uint256 _totalOethbSupply = oeth.totalSupply();\n\n if (\n _totalVaultValue.divPrecisely(_totalOethbSupply) <\n SOLVENCY_THRESHOLD\n ) {\n revert(\"Protocol insolvent\");\n }\n }\n\n /***************************************\n Assets and Rewards\n ****************************************/\n\n /**\n * @notice Collect accumulated CRV (and other) rewards and send to the Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvesterOrStrategist\n nonReentrant\n {\n // CRV rewards flow.\n //---\n // CRV inflation:\n // Gauge receive CRV rewards from inflation.\n // Each checkpoint on the gauge send this CRV inflation to gauge factory.\n // This strategy should call mint on the gauge factory to collect the CRV rewards.\n // ---\n // Extra rewards:\n // Calling claim_rewards on the gauge will only claim extra rewards (outside of CRV).\n // ---\n\n // Mint CRV on Child Liquidity gauge factory\n gaugeFactory.mint(address(gauge));\n // Collect extra gauge rewards (outside of CRV)\n gauge.claim_rewards();\n\n _collectRewardTokens();\n }\n\n function _lpWithdraw(uint256 _lpAmount) internal {\n // withdraw lp tokens from the gauge without claiming rewards\n gauge.withdraw(_lpAmount);\n }\n\n /**\n * @notice Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == address(weth), \"Unsupported asset\");\n\n // WETH balance needed here for the balance check that happens from vault during depositing.\n balance = weth.balanceOf(address(this));\n uint256 lpTokens = gauge.balanceOf(address(this));\n if (lpTokens > 0) {\n balance += (lpTokens * curvePool.get_virtual_price()) / 1e18;\n }\n }\n\n /**\n * @notice Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == address(weth);\n }\n\n /***************************************\n Approvals\n ****************************************/\n\n /**\n * @notice Sets the maximum slippage allowed for any swap/liquidity operation\n * @param _maxSlippage Maximum slippage allowed, 1e18 = 100%.\n */\n function setMaxSlippage(uint256 _maxSlippage) external onlyGovernor {\n _setMaxSlippage(_maxSlippage);\n }\n\n function _setMaxSlippage(uint256 _maxSlippage) internal {\n require(_maxSlippage <= 5e16, \"Slippage must be less than 100%\");\n maxSlippage = _maxSlippage;\n emit MaxSlippageUpdated(_maxSlippage);\n }\n\n /**\n * @notice Approve the spending of all assets by their corresponding pool tokens,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n _approveBase();\n }\n\n /**\n * @dev Since we are unwrapping WETH before depositing it to Curve\n * there is no need to set an approval for WETH on the Curve\n * pool\n * @param _asset Address of the asset\n * @param _pToken Address of the Curve LP token\n */\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {}\n\n function _approveBase() internal {\n // Approve Curve pool for OETH (required for adding liquidity)\n // slither-disable-next-line unused-return\n oeth.approve(platformAddress, type(uint256).max);\n\n // Approve Curve pool for WETH (required for adding liquidity)\n // slither-disable-next-line unused-return\n weth.approve(platformAddress, type(uint256).max);\n\n // Approve Curve gauge contract to transfer Curve pool LP tokens\n // This is needed for deposits if Curve pool LP tokens into the Curve gauge.\n // slither-disable-next-line unused-return\n lpToken.approve(address(gauge), type(uint256).max);\n }\n\n /**\n * @dev Returns the largest of two numbers int256 version\n */\n function _max(int256 a, int256 b) internal pure returns (int256) {\n return a >= b ? a : b;\n }\n}\n" + }, + "contracts/strategies/BridgedWOETHStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20, SafeERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { AggregatorV3Interface } from \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\n\ncontract BridgedWOETHStrategy is InitializableAbstractStrategy {\n using StableMath for uint256;\n using StableMath for uint128;\n using SafeCast for uint256;\n using SafeERC20 for IERC20;\n\n event MaxPriceDiffBpsUpdated(uint128 oldValue, uint128 newValue);\n event WOETHPriceUpdated(uint128 oldValue, uint128 newValue);\n\n IWETH9 public immutable weth;\n IERC20 public immutable bridgedWOETH;\n IERC20 public immutable oethb;\n IOracle public immutable oracle;\n\n uint128 public lastOraclePrice;\n uint128 public maxPriceDiffBps;\n\n constructor(\n BaseStrategyConfig memory _stratConfig,\n address _weth,\n address _bridgedWOETH,\n address _oethb,\n address _oracle\n ) InitializableAbstractStrategy(_stratConfig) {\n weth = IWETH9(_weth);\n bridgedWOETH = IERC20(_bridgedWOETH);\n oethb = IERC20(_oethb);\n oracle = IOracle(_oracle);\n }\n\n function initialize(uint128 _maxPriceDiffBps)\n external\n onlyGovernor\n initializer\n {\n InitializableAbstractStrategy._initialize(\n new address[](0), // No reward tokens\n new address[](0), // No assets\n new address[](0) // No pTokens\n );\n\n _setMaxPriceDiffBps(_maxPriceDiffBps);\n }\n\n /**\n * @dev Sets the max price diff bps for the wOETH value appreciation\n * @param _maxPriceDiffBps Bps value, 10k == 100%\n */\n function setMaxPriceDiffBps(uint128 _maxPriceDiffBps)\n external\n onlyGovernor\n {\n _setMaxPriceDiffBps(_maxPriceDiffBps);\n }\n\n /**\n * @dev Sets the max price diff bps for the wOETH value appreciation\n * @param _maxPriceDiffBps Bps value, 10k == 100%\n */\n function _setMaxPriceDiffBps(uint128 _maxPriceDiffBps) internal {\n require(\n _maxPriceDiffBps > 0 && _maxPriceDiffBps <= 10000,\n \"Invalid bps value\"\n );\n\n emit MaxPriceDiffBpsUpdated(maxPriceDiffBps, _maxPriceDiffBps);\n\n maxPriceDiffBps = _maxPriceDiffBps;\n }\n\n /**\n * @dev Wrapper for _updateWOETHOraclePrice with nonReentrant flag\n * @return The latest price of wOETH from Oracle\n */\n function updateWOETHOraclePrice() external nonReentrant returns (uint256) {\n return _updateWOETHOraclePrice();\n }\n\n /**\n * @dev Finds the value of bridged wOETH from the Oracle.\n * Ensures that it's within the bounds and reasonable.\n * And stores it.\n *\n * NOTE: Intentionally not caching `Vault.priceProvider` here,\n * since doing so would mean that we also have to update this\n * strategy every time there's a change in oracle router.\n * Besides on L2, the gas is considerably cheaper than mainnet.\n *\n * @return Latest price from oracle\n */\n function _updateWOETHOraclePrice() internal returns (uint256) {\n // WETH price per unit of bridged wOETH\n uint256 oraclePrice = oracle.price(address(bridgedWOETH));\n\n // 1 wOETH > 1 WETH, always\n require(oraclePrice > 1 ether, \"Invalid wOETH value\");\n\n uint128 oraclePrice128 = oraclePrice.toUint128();\n\n // Do some checks\n if (lastOraclePrice > 0) {\n // Make sure the value only goes up\n require(oraclePrice128 >= lastOraclePrice, \"Negative wOETH yield\");\n\n // lastOraclePrice * (1 + maxPriceDiffBps)\n uint256 maxPrice = (lastOraclePrice * (1e4 + maxPriceDiffBps)) /\n 1e4;\n\n // And that it's within the bounds.\n require(oraclePrice128 <= maxPrice, \"Price diff beyond threshold\");\n }\n\n emit WOETHPriceUpdated(lastOraclePrice, oraclePrice128);\n\n // Store the price\n lastOraclePrice = oraclePrice128;\n\n return oraclePrice;\n }\n\n /**\n * @dev Computes & returns the value of given wOETH in WETH\n * @param woethAmount Amount of wOETH\n * @return Value of wOETH in WETH (using the last stored oracle price)\n */\n function getBridgedWOETHValue(uint256 woethAmount)\n public\n view\n returns (uint256)\n {\n return (woethAmount * lastOraclePrice) / 1 ether;\n }\n\n /**\n * @dev Takes in bridged wOETH and mints & returns\n * equivalent amount of OETHb.\n * @param woethAmount Amount of bridged wOETH to transfer in\n */\n function depositBridgedWOETH(uint256 woethAmount)\n external\n onlyGovernorOrStrategist\n nonReentrant\n {\n // Update wOETH price\n uint256 oraclePrice = _updateWOETHOraclePrice();\n\n // Figure out how much they are worth\n uint256 oethToMint = (woethAmount * oraclePrice) / 1 ether;\n\n require(oethToMint > 0, \"Invalid deposit amount\");\n\n // There's no pToken, however, it just uses WOETH address in the event\n emit Deposit(address(weth), address(bridgedWOETH), oethToMint);\n\n // Mint OETHb tokens and transfer it to the caller\n IVault(vaultAddress).mintForStrategy(oethToMint);\n\n // Transfer out minted OETHb\n // slither-disable-next-line unchecked-transfer unused-return\n oethb.transfer(msg.sender, oethToMint);\n\n // Transfer in all bridged wOETH tokens\n // slither-disable-next-line unchecked-transfer unused-return\n bridgedWOETH.transferFrom(msg.sender, address(this), woethAmount);\n }\n\n /**\n * @dev Takes in OETHb and burns it and returns\n * equivalent amount of bridged wOETH.\n * @param oethToBurn Amount of OETHb to burn\n */\n function withdrawBridgedWOETH(uint256 oethToBurn)\n external\n onlyGovernorOrStrategist\n nonReentrant\n {\n // Update wOETH price\n uint256 oraclePrice = _updateWOETHOraclePrice();\n\n // Figure out how much they are worth\n uint256 woethAmount = (oethToBurn * 1 ether) / oraclePrice;\n\n require(woethAmount > 0, \"Invalid withdraw amount\");\n\n // There's no pToken, however, it just uses WOETH address in the event\n emit Withdrawal(address(weth), address(bridgedWOETH), oethToBurn);\n\n // Transfer WOETH back\n // slither-disable-next-line unchecked-transfer unused-return\n bridgedWOETH.transfer(msg.sender, woethAmount);\n\n // Transfer in OETHb\n // slither-disable-next-line unchecked-transfer unused-return\n oethb.transferFrom(msg.sender, address(this), oethToBurn);\n\n // Burn OETHb\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n }\n\n /**\n * @notice Returns the amount of backing WETH the strategy holds\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == address(weth), \"Unsupported asset\");\n\n // Figure out how much wOETH is worth at the time.\n // Always uses the last stored oracle price.\n // Call updateWOETHOraclePrice manually to pull in latest yields.\n\n // NOTE: If the contract has been deployed but the call to\n // `updateWOETHOraclePrice()` has never been made, then this\n // will return zero. It should be fine because the strategy\n // should update the price whenever a deposit/withdraw happens.\n\n // If `updateWOETHOraclePrice()` hasn't been called in a while,\n // the strategy will underreport its holdings but never overreport it.\n\n balance =\n (bridgedWOETH.balanceOf(address(this)) * lastOraclePrice) /\n 1 ether;\n }\n\n /**\n * @notice Check if an asset is supported.\n * @param _asset Address of the asset\n * @return bool Whether asset is supported\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n // Strategist deposits bridged wOETH but the contract only\n // reports the balance in WETH. As far as Vault is concerned,\n // it isn't aware of bridged wOETH token\n return _asset == address(weth);\n }\n\n /***************************************\n Overridden methods\n ****************************************/\n /**\n * @inheritdoc InitializableAbstractStrategy\n */\n function transferToken(address _asset, uint256 _amount)\n public\n override\n onlyGovernor\n {\n require(\n _asset != address(bridgedWOETH) && _asset != address(weth),\n \"Cannot transfer supported asset\"\n );\n // Use SafeERC20 only for rescuing unknown assets; core tokens are standard.\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /**\n * @notice deposit() function not used for this strategy\n */\n function deposit(address, uint256)\n external\n override\n onlyVault\n nonReentrant\n {\n // Use depositBridgedWOETH() instead\n require(false, \"Deposit disabled\");\n }\n\n /**\n * @notice depositAll() function not used for this strategy\n */\n function depositAll() external override onlyVault nonReentrant {\n // Use depositBridgedWOETH() instead\n require(false, \"Deposit disabled\");\n }\n\n /**\n * @notice withdraw() function not used for this strategy\n */\n function withdraw(\n // solhint-disable-next-line no-unused-vars\n address _recipient,\n // solhint-disable-next-line no-unused-vars\n address _asset,\n // solhint-disable-next-line no-unused-vars\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(false, \"Withdrawal disabled\");\n }\n\n /**\n * @notice withdrawAll() function not used for this strategy\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n // Withdrawal disabled\n }\n\n function _abstractSetPToken(address, address) internal override {\n revert(\"No pTokens are used\");\n }\n\n function safeApproveAllTokens() external override {}\n\n /**\n * @inheritdoc InitializableAbstractStrategy\n */\n function removePToken(uint256) external override {\n revert(\"No pTokens are used\");\n }\n\n /**\n * @inheritdoc InitializableAbstractStrategy\n */\n function collectRewardTokens() external override {}\n}\n" + }, + "contracts/strategies/crosschain/AbstractCCTPIntegrator.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title AbstractCCTPIntegrator\n * @author Origin Protocol Inc\n *\n * @dev Abstract contract that contains all the logic used to integrate with CCTP.\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\n\nimport { ICCTPTokenMessenger, ICCTPMessageTransmitter, IMessageHandlerV2 } from \"../../interfaces/cctp/ICCTP.sol\";\n\nimport { CrossChainStrategyHelper } from \"./CrossChainStrategyHelper.sol\";\nimport { Governable } from \"../../governance/Governable.sol\";\nimport { BytesHelper } from \"../../utils/BytesHelper.sol\";\nimport \"../../utils/Helpers.sol\";\n\nabstract contract AbstractCCTPIntegrator is Governable, IMessageHandlerV2 {\n using SafeERC20 for IERC20;\n\n using BytesHelper for bytes;\n using CrossChainStrategyHelper for bytes;\n\n event LastTransferNonceUpdated(uint64 lastTransferNonce);\n event NonceProcessed(uint64 nonce);\n\n event CCTPMinFinalityThresholdSet(uint16 minFinalityThreshold);\n event CCTPFeePremiumBpsSet(uint16 feePremiumBps);\n event OperatorChanged(address operator);\n event TokensBridged(\n uint32 destinationDomain,\n address peerStrategy,\n address tokenAddress,\n uint256 tokenAmount,\n uint256 maxFee,\n uint32 minFinalityThreshold,\n bytes hookData\n );\n event MessageTransmitted(\n uint32 destinationDomain,\n address peerStrategy,\n uint32 minFinalityThreshold,\n bytes message\n );\n\n // Message body V2 fields\n // Ref: https://developers.circle.com/cctp/technical-guide#message-body\n // Ref: https://github.com/circlefin/evm-cctp-contracts/blob/master/src/messages/v2/BurnMessageV2.sol\n uint8 private constant BURN_MESSAGE_V2_VERSION_INDEX = 0;\n uint8 private constant BURN_MESSAGE_V2_BURN_TOKEN_INDEX = 4;\n uint8 private constant BURN_MESSAGE_V2_RECIPIENT_INDEX = 36;\n uint8 private constant BURN_MESSAGE_V2_AMOUNT_INDEX = 68;\n uint8 private constant BURN_MESSAGE_V2_MESSAGE_SENDER_INDEX = 100;\n uint8 private constant BURN_MESSAGE_V2_FEE_EXECUTED_INDEX = 164;\n uint8 private constant BURN_MESSAGE_V2_HOOK_DATA_INDEX = 228;\n\n /**\n * @notice Max transfer threshold imposed by the CCTP\n * Ref: https://developers.circle.com/cctp/evm-smart-contracts#depositforburn\n * @dev 10M USDC limit applies to both standard and fast transfer modes. The fast transfer mode has\n * an additional limitation that is not present on-chain and Circle may alter that amount off-chain\n * at their preference. The amount available for fast transfer can be queried here:\n * https://iris-api.circle.com/v2/fastBurn/USDC/allowance .\n * If a fast transfer token transaction has been issued and there is not enough allowance for it\n * the off-chain Iris component will re-attempt the transaction and if it fails it will fallback\n * to a standard transfer. Reference section 4.3 in the whitepaper:\n * https://6778953.fs1.hubspotusercontent-na1.net/hubfs/6778953/PDFs/Whitepapers/CCTPV2_White_Paper.pdf\n */\n uint256 public constant MAX_TRANSFER_AMOUNT = 10_000_000 * 10**6; // 10M USDC\n\n /// @notice Minimum transfer amount to avoid zero or dust transfers\n uint256 public constant MIN_TRANSFER_AMOUNT = 10**6;\n\n // CCTP contracts\n // This implementation assumes that remote and local chains have these contracts\n // deployed on the same addresses.\n /// @notice CCTP message transmitter contract\n ICCTPMessageTransmitter public immutable cctpMessageTransmitter;\n /// @notice CCTP token messenger contract\n ICCTPTokenMessenger public immutable cctpTokenMessenger;\n\n /// @notice USDC address on local chain\n address public immutable usdcToken;\n\n /// @notice USDC address on remote chain\n address public immutable peerUsdcToken;\n\n /// @notice Domain ID of the chain from which messages are accepted\n uint32 public immutable peerDomainID;\n\n /// @notice Strategy address on other chain\n address public immutable peerStrategy;\n\n /**\n * @notice Minimum finality threshold\n * Can be 1000 (safe, after 1 epoch) or 2000 (finalized, after 2 epochs).\n * Ref: https://developers.circle.com/cctp/technical-guide#finality-thresholds\n * @dev When configuring the contract for fast transfer we should check the available\n * allowance of USDC that can be bridged using fast mode:\n * wget https://iris-api.circle.com/v2/fastBurn/USDC/allowance\n */\n uint16 public minFinalityThreshold;\n\n /// @notice Fee premium in basis points\n uint16 public feePremiumBps;\n\n /// @notice Nonce of the last known deposit or withdrawal\n uint64 public lastTransferNonce;\n\n /// @notice Operator address: Can relay CCTP messages\n address public operator;\n\n /// @notice Mapping of processed nonces\n mapping(uint64 => bool) private nonceProcessed;\n\n // For future use\n uint256[48] private __gap;\n\n modifier onlyCCTPMessageTransmitter() {\n require(\n msg.sender == address(cctpMessageTransmitter),\n \"Caller is not CCTP transmitter\"\n );\n _;\n }\n\n modifier onlyOperator() {\n require(msg.sender == operator, \"Caller is not the Operator\");\n _;\n }\n\n /**\n * @notice Configuration for CCTP integration\n * @param cctpTokenMessenger Address of the CCTP token messenger contract\n * @param cctpMessageTransmitter Address of the CCTP message transmitter contract\n * @param peerDomainID Domain ID of the chain from which messages are accepted.\n * 0 for Ethereum, 6 for Base, etc.\n * Ref: https://developers.circle.com/cctp/cctp-supported-blockchains\n * @param peerStrategy Address of the master or remote strategy on the other chain\n * @param usdcToken USDC address on local chain\n */\n struct CCTPIntegrationConfig {\n address cctpTokenMessenger;\n address cctpMessageTransmitter;\n uint32 peerDomainID;\n address peerStrategy;\n address usdcToken;\n address peerUsdcToken;\n }\n\n constructor(CCTPIntegrationConfig memory _config) {\n require(_config.usdcToken != address(0), \"Invalid USDC address\");\n require(\n _config.peerUsdcToken != address(0),\n \"Invalid peer USDC address\"\n );\n require(\n _config.cctpTokenMessenger != address(0),\n \"Invalid CCTP config\"\n );\n require(\n _config.cctpMessageTransmitter != address(0),\n \"Invalid CCTP config\"\n );\n require(\n _config.peerStrategy != address(0),\n \"Invalid peer strategy address\"\n );\n\n cctpMessageTransmitter = ICCTPMessageTransmitter(\n _config.cctpMessageTransmitter\n );\n cctpTokenMessenger = ICCTPTokenMessenger(_config.cctpTokenMessenger);\n\n // Domain ID of the chain from which messages are accepted\n peerDomainID = _config.peerDomainID;\n\n // Strategy address on other chain, should\n // always be same as the proxy of this strategy\n peerStrategy = _config.peerStrategy;\n\n // USDC address on local chain\n usdcToken = _config.usdcToken;\n\n // Just a sanity check to ensure the base token is USDC\n uint256 _usdcTokenDecimals = Helpers.getDecimals(_config.usdcToken);\n string memory _usdcTokenSymbol = Helpers.getSymbol(_config.usdcToken);\n require(_usdcTokenDecimals == 6, \"Base token decimals must be 6\");\n require(\n keccak256(abi.encodePacked(_usdcTokenSymbol)) ==\n keccak256(abi.encodePacked(\"USDC\")),\n \"Token symbol must be USDC\"\n );\n\n // USDC address on remote chain\n peerUsdcToken = _config.peerUsdcToken;\n }\n\n /**\n * @dev Initialize the implementation contract\n * @param _operator Operator address\n * @param _minFinalityThreshold Minimum finality threshold\n * @param _feePremiumBps Fee premium in basis points\n */\n function _initialize(\n address _operator,\n uint16 _minFinalityThreshold,\n uint16 _feePremiumBps\n ) internal {\n _setOperator(_operator);\n _setMinFinalityThreshold(_minFinalityThreshold);\n _setFeePremiumBps(_feePremiumBps);\n\n // Nonce starts at 1, so assume nonce 0 as processed.\n // NOTE: This will cause the deposit/withdraw to fail if the\n // strategy is not initialized properly (which is expected).\n nonceProcessed[0] = true;\n }\n\n /***************************************\n Settings\n ****************************************/\n /**\n * @dev Set the operator address\n * @param _operator Operator address\n */\n function setOperator(address _operator) external onlyGovernor {\n _setOperator(_operator);\n }\n\n /**\n * @dev Set the operator address\n * @param _operator Operator address\n */\n function _setOperator(address _operator) internal {\n operator = _operator;\n emit OperatorChanged(_operator);\n }\n\n /**\n * @dev Set the minimum finality threshold at which\n * the message is considered to be finalized to relay.\n * Only accepts a value of 1000 (Safe, after 1 epoch) or\n * 2000 (Finalized, after 2 epochs).\n * @param _minFinalityThreshold Minimum finality threshold\n */\n function setMinFinalityThreshold(uint16 _minFinalityThreshold)\n external\n onlyGovernor\n {\n _setMinFinalityThreshold(_minFinalityThreshold);\n }\n\n /**\n * @dev Set the minimum finality threshold\n * @param _minFinalityThreshold Minimum finality threshold\n */\n function _setMinFinalityThreshold(uint16 _minFinalityThreshold) internal {\n // 1000 for fast transfer and 2000 for standard transfer\n require(\n _minFinalityThreshold == 1000 || _minFinalityThreshold == 2000,\n \"Invalid threshold\"\n );\n\n minFinalityThreshold = _minFinalityThreshold;\n emit CCTPMinFinalityThresholdSet(_minFinalityThreshold);\n }\n\n /**\n * @dev Set the fee premium in basis points.\n * Cannot be higher than 30% (3000 basis points).\n * @param _feePremiumBps Fee premium in basis points\n */\n function setFeePremiumBps(uint16 _feePremiumBps) external onlyGovernor {\n _setFeePremiumBps(_feePremiumBps);\n }\n\n /**\n * @dev Set the fee premium in basis points\n * Cannot be higher than 30% (3000 basis points).\n * Ref: https://developers.circle.com/cctp/technical-guide#fees\n * @param _feePremiumBps Fee premium in basis points\n */\n function _setFeePremiumBps(uint16 _feePremiumBps) internal {\n require(_feePremiumBps <= 3000, \"Fee premium too high\"); // 30%\n\n feePremiumBps = _feePremiumBps;\n emit CCTPFeePremiumBpsSet(_feePremiumBps);\n }\n\n /***************************************\n CCTP message handling\n ****************************************/\n\n /**\n * @dev Handles a finalized CCTP message\n * @param sourceDomain Source domain of the message\n * @param sender Sender of the message\n * @param finalityThresholdExecuted Fidelity threshold executed\n * @param messageBody Message body\n */\n function handleReceiveFinalizedMessage(\n uint32 sourceDomain,\n bytes32 sender,\n uint32 finalityThresholdExecuted,\n bytes memory messageBody\n ) external override onlyCCTPMessageTransmitter returns (bool) {\n // Make sure the finality threshold at execution is at least 2000\n require(\n finalityThresholdExecuted >= 2000,\n \"Finality threshold too low\"\n );\n\n return _handleReceivedMessage(sourceDomain, sender, messageBody);\n }\n\n /**\n * @dev Handles an unfinalized but safe CCTP message\n * @param sourceDomain Source domain of the message\n * @param sender Sender of the message\n * @param finalityThresholdExecuted Fidelity threshold executed\n * @param messageBody Message body\n */\n function handleReceiveUnfinalizedMessage(\n uint32 sourceDomain,\n bytes32 sender,\n uint32 finalityThresholdExecuted,\n bytes memory messageBody\n ) external override onlyCCTPMessageTransmitter returns (bool) {\n // Make sure the contract is configured to handle unfinalized messages\n require(\n minFinalityThreshold == 1000,\n \"Unfinalized messages are not supported\"\n );\n // Make sure the finality threshold at execution is at least 1000\n require(\n finalityThresholdExecuted >= 1000,\n \"Finality threshold too low\"\n );\n\n return _handleReceivedMessage(sourceDomain, sender, messageBody);\n }\n\n /**\n * @dev Handles a CCTP message\n * @param sourceDomain Source domain of the message\n * @param sender Sender of the message\n * @param messageBody Message body\n */\n function _handleReceivedMessage(\n uint32 sourceDomain,\n bytes32 sender,\n bytes memory messageBody\n ) internal returns (bool) {\n require(sourceDomain == peerDomainID, \"Unknown Source Domain\");\n\n // Extract address from bytes32 (CCTP stores addresses as right-padded bytes32)\n address senderAddress = address(uint160(uint256(sender)));\n require(senderAddress == peerStrategy, \"Unknown Sender\");\n\n _onMessageReceived(messageBody);\n\n return true;\n }\n\n /**\n * @dev Sends tokens to the peer strategy using CCTP Token Messenger\n * @param tokenAmount Amount of tokens to send\n * @param hookData Hook data\n */\n function _sendTokens(uint256 tokenAmount, bytes memory hookData)\n internal\n virtual\n {\n // CCTP has a maximum transfer amount of 10M USDC per tx\n require(tokenAmount <= MAX_TRANSFER_AMOUNT, \"Token amount too high\");\n\n // Approve only what needs to be transferred\n IERC20(usdcToken).safeApprove(address(cctpTokenMessenger), tokenAmount);\n\n // Compute the max fee to be paid.\n // Ref: https://developers.circle.com/cctp/evm-smart-contracts#getminfeeamount\n // The right way to compute fees would be to use CCTP's getMinFeeAmount function.\n // The issue is that the getMinFeeAmount is not present on v2.0 contracts, but is on\n // v2.1. Some of CCTP's deployed contracts are v2.0, some are v2.1.\n // We will only be using standard transfers and fee on those is 0 for now. If they\n // ever start implementing fee for standard transfers or if we decide to use fast\n // trasnfer, we can use feePremiumBps as a workaround.\n uint256 maxFee = feePremiumBps > 0\n ? (tokenAmount * feePremiumBps) / 10000\n : 0;\n\n // Send tokens to the peer strategy using CCTP Token Messenger\n cctpTokenMessenger.depositForBurnWithHook(\n tokenAmount,\n peerDomainID,\n bytes32(uint256(uint160(peerStrategy))),\n address(usdcToken),\n bytes32(uint256(uint160(peerStrategy))),\n maxFee,\n uint32(minFinalityThreshold),\n hookData\n );\n\n emit TokensBridged(\n peerDomainID,\n peerStrategy,\n usdcToken,\n tokenAmount,\n maxFee,\n uint32(minFinalityThreshold),\n hookData\n );\n }\n\n /**\n * @dev Sends a message to the peer strategy using CCTP Message Transmitter\n * @param message Payload of the message to send\n */\n function _sendMessage(bytes memory message) internal virtual {\n cctpMessageTransmitter.sendMessage(\n peerDomainID,\n bytes32(uint256(uint160(peerStrategy))),\n bytes32(uint256(uint160(peerStrategy))),\n uint32(minFinalityThreshold),\n message\n );\n\n emit MessageTransmitted(\n peerDomainID,\n peerStrategy,\n uint32(minFinalityThreshold),\n message\n );\n }\n\n /**\n * @dev Receives a message from the peer strategy on the other chain,\n * does some basic checks and relays it to the local MessageTransmitterV2.\n * If the message is a burn message, it will also handle the hook data\n * and call the _onTokenReceived function.\n * @param message Payload of the message to send\n * @param attestation Attestation of the message\n */\n function relay(bytes memory message, bytes memory attestation)\n external\n onlyOperator\n {\n (\n uint32 version,\n uint32 sourceDomainID,\n address sender,\n address recipient,\n bytes memory messageBody\n ) = message.decodeMessageHeader();\n\n // Ensure that it's a CCTP message\n require(\n version == CrossChainStrategyHelper.CCTP_MESSAGE_VERSION,\n \"Invalid CCTP message version\"\n );\n\n // Ensure that the source domain is the peer domain\n require(sourceDomainID == peerDomainID, \"Unknown Source Domain\");\n\n // Ensure message body version\n version = messageBody.extractUint32(BURN_MESSAGE_V2_VERSION_INDEX);\n\n // NOTE: There's a possibility that the CCTP Token Messenger might\n // send other types of messages in future, not just the burn message.\n // If it ever comes to that, this shouldn't cause us any problems\n // because it has to still go through the followign checks:\n // - version check\n // - message body length check\n // - sender and recipient (which should be in the same slots and same as address(this))\n // - hook data handling (which will revert even if all the above checks pass)\n bool isBurnMessageV1 = sender == address(cctpTokenMessenger);\n\n if (isBurnMessageV1) {\n // Handle burn message\n require(\n version == 1 &&\n messageBody.length >= BURN_MESSAGE_V2_HOOK_DATA_INDEX,\n \"Invalid burn message\"\n );\n\n // Ensure the burn token is USDC\n address burnToken = messageBody.extractAddress(\n BURN_MESSAGE_V2_BURN_TOKEN_INDEX\n );\n require(burnToken == peerUsdcToken, \"Invalid burn token\");\n\n // Address of caller of depositForBurn (or depositForBurnWithCaller) on source domain\n sender = messageBody.extractAddress(\n BURN_MESSAGE_V2_MESSAGE_SENDER_INDEX\n );\n\n recipient = messageBody.extractAddress(\n BURN_MESSAGE_V2_RECIPIENT_INDEX\n );\n } else {\n // We handle only Burn message or our custom messagee\n require(\n version == CrossChainStrategyHelper.ORIGIN_MESSAGE_VERSION,\n \"Unsupported message version\"\n );\n }\n\n // Ensure the recipient is this contract\n // Both sender and recipient should be deployed to same address on both chains.\n require(address(this) == recipient, \"Unexpected recipient address\");\n require(sender == peerStrategy, \"Incorrect sender/recipient address\");\n\n // Relay the message\n // This step also mints USDC and transfers it to the recipient wallet\n bool relaySuccess = cctpMessageTransmitter.receiveMessage(\n message,\n attestation\n );\n require(relaySuccess, \"Receive message failed\");\n\n if (isBurnMessageV1) {\n // Extract the hook data from the message body\n bytes memory hookData = messageBody.extractSlice(\n BURN_MESSAGE_V2_HOOK_DATA_INDEX,\n messageBody.length\n );\n\n // Extract the token amount from the message body\n uint256 tokenAmount = messageBody.extractUint256(\n BURN_MESSAGE_V2_AMOUNT_INDEX\n );\n\n // Extract the fee executed from the message body\n uint256 feeExecuted = messageBody.extractUint256(\n BURN_MESSAGE_V2_FEE_EXECUTED_INDEX\n );\n\n // Call the _onTokenReceived function\n _onTokenReceived(tokenAmount - feeExecuted, feeExecuted, hookData);\n }\n }\n\n /***************************************\n Message utils\n ****************************************/\n\n /***************************************\n Nonce Handling\n ****************************************/\n /**\n * @dev Checks if the last known transfer is pending.\n * Nonce starts at 1, so 0 is disregarded.\n * @return True if a transfer is pending, false otherwise\n */\n function isTransferPending() public view returns (bool) {\n return !nonceProcessed[lastTransferNonce];\n }\n\n /**\n * @dev Checks if a given nonce is processed.\n * Nonce starts at 1, so 0 is disregarded.\n * @param nonce Nonce to check\n * @return True if the nonce is processed, false otherwise\n */\n function isNonceProcessed(uint64 nonce) public view returns (bool) {\n return nonceProcessed[nonce];\n }\n\n /**\n * @dev Marks a given nonce as processed.\n * Can only mark nonce as processed once. New nonce should\n * always be greater than the last known nonce. Also updates\n * the last known nonce.\n * @param nonce Nonce to mark as processed\n */\n function _markNonceAsProcessed(uint64 nonce) internal {\n uint64 lastNonce = lastTransferNonce;\n\n // Can only mark latest nonce as processed\n // Master strategy when receiving a message from the remote strategy\n // will have lastNone == nonce, as the nonce is increase at the start\n // of deposit / withdrawal flow.\n // Remote strategy will have lastNonce < nonce, as a new nonce initiated\n // from master will be greater than the last one.\n require(nonce >= lastNonce, \"Nonce too low\");\n // Can only mark nonce as processed once\n require(!nonceProcessed[nonce], \"Nonce already processed\");\n\n nonceProcessed[nonce] = true;\n emit NonceProcessed(nonce);\n\n if (nonce != lastNonce) {\n // Update last known nonce\n lastTransferNonce = nonce;\n emit LastTransferNonceUpdated(nonce);\n }\n }\n\n /**\n * @dev Gets the next nonce to use.\n * Nonce starts at 1, so 0 is disregarded.\n * Reverts if last nonce hasn't been processed yet.\n * @return Next nonce\n */\n function _getNextNonce() internal returns (uint64) {\n uint64 nonce = lastTransferNonce;\n\n require(nonceProcessed[nonce], \"Pending token transfer\");\n\n nonce = nonce + 1;\n lastTransferNonce = nonce;\n emit LastTransferNonceUpdated(nonce);\n\n return nonce;\n }\n\n /***************************************\n Inheritence overrides\n ****************************************/\n\n /**\n * @dev Called when the USDC is received from the CCTP\n * @param tokenAmount The actual amount of USDC received (amount sent - fee executed)\n * @param feeExecuted The fee executed\n * @param payload The payload of the message (hook data)\n */\n function _onTokenReceived(\n uint256 tokenAmount,\n uint256 feeExecuted,\n bytes memory payload\n ) internal virtual;\n\n /**\n * @dev Called when the message is received\n * @param payload The payload of the message\n */\n function _onMessageReceived(bytes memory payload) internal virtual;\n}\n" + }, + "contracts/strategies/crosschain/CrossChainMasterStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Yearn V3 Master Strategy - the Mainnet part\n * @author Origin Protocol Inc\n *\n * @dev This strategy can only perform 1 deposit or withdrawal at a time. For that\n * reason it shouldn't be configured as an asset default strategy.\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { AbstractCCTPIntegrator } from \"./AbstractCCTPIntegrator.sol\";\nimport { CrossChainStrategyHelper } from \"./CrossChainStrategyHelper.sol\";\n\ncontract CrossChainMasterStrategy is\n AbstractCCTPIntegrator,\n InitializableAbstractStrategy\n{\n using SafeERC20 for IERC20;\n using CrossChainStrategyHelper for bytes;\n\n /**\n * @notice Remote strategy balance\n * @dev The remote balance is cached and might not reflect the actual\n * real-time balance of the remote strategy.\n */\n uint256 public remoteStrategyBalance;\n\n /// @notice Amount that's bridged due to a pending Deposit process\n /// but with no acknowledgement from the remote strategy yet\n uint256 public pendingAmount;\n\n uint256 internal constant MAX_BALANCE_CHECK_AGE = 1 days;\n\n event RemoteStrategyBalanceUpdated(uint256 balance);\n event WithdrawRequested(address indexed asset, uint256 amount);\n event WithdrawAllSkipped();\n event BalanceCheckIgnored(uint64 nonce, uint256 timestamp, bool isTooOld);\n\n /**\n * @param _stratConfig The platform and OToken vault addresses\n */\n constructor(\n BaseStrategyConfig memory _stratConfig,\n CCTPIntegrationConfig memory _cctpConfig\n )\n InitializableAbstractStrategy(_stratConfig)\n AbstractCCTPIntegrator(_cctpConfig)\n {\n require(\n _stratConfig.platformAddress == address(0),\n \"Invalid platform address\"\n );\n require(\n _stratConfig.vaultAddress != address(0),\n \"Invalid Vault address\"\n );\n }\n\n /**\n * @dev Initialize the strategy implementation\n * @param _operator Address of the operator\n * @param _minFinalityThreshold Minimum finality threshold\n * @param _feePremiumBps Fee premium in basis points\n */\n function initialize(\n address _operator,\n uint16 _minFinalityThreshold,\n uint16 _feePremiumBps\n ) external virtual onlyGovernor initializer {\n _initialize(_operator, _minFinalityThreshold, _feePremiumBps);\n\n address[] memory rewardTokens = new address[](0);\n address[] memory assets = new address[](0);\n address[] memory pTokens = new address[](0);\n\n InitializableAbstractStrategy._initialize(\n rewardTokens,\n assets,\n pTokens\n );\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function depositAll() external override onlyVault nonReentrant {\n uint256 balance = IERC20(usdcToken).balanceOf(address(this));\n // Deposit if balance is greater than 1 USDC\n if (balance >= MIN_TRANSFER_AMOUNT) {\n _deposit(usdcToken, balance);\n }\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_recipient == vaultAddress, \"Only Vault can withdraw\");\n _withdraw(_asset, _amount);\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n if (isTransferPending()) {\n // Do nothing if there is a pending transfer\n // Note: We never want withdrawAll to fail, so\n // emit an event to indicate that the withdrawal was skipped\n emit WithdrawAllSkipped();\n return;\n }\n\n // Withdraw everything in Remote strategy\n uint256 _remoteBalance = remoteStrategyBalance;\n if (_remoteBalance < MIN_TRANSFER_AMOUNT) {\n // Do nothing if there is less than 1 USDC in the Remote strategy\n return;\n }\n\n _withdraw(\n usdcToken,\n _remoteBalance > MAX_TRANSFER_AMOUNT\n ? MAX_TRANSFER_AMOUNT\n : _remoteBalance\n );\n }\n\n /**\n * @notice Check the balance of the strategy that includes\n * the balance of the asset on this contract,\n * the amount of the asset being bridged,\n * and the balance reported by the Remote strategy.\n * @param _asset Address of the asset to check\n * @return balance Total balance of the asset\n */\n function checkBalance(address _asset)\n public\n view\n override\n returns (uint256 balance)\n {\n require(_asset == usdcToken, \"Unsupported asset\");\n\n // USDC balance on this contract\n // + USDC being bridged\n // + USDC cached in the corresponding Remote part of this contract\n return\n IERC20(usdcToken).balanceOf(address(this)) +\n pendingAmount +\n remoteStrategyBalance;\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == usdcToken;\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {}\n\n /// @inheritdoc InitializableAbstractStrategy\n function _abstractSetPToken(address, address) internal override {}\n\n /// @inheritdoc InitializableAbstractStrategy\n function collectRewardTokens()\n external\n override\n onlyHarvesterOrStrategist\n nonReentrant\n {}\n\n /// @inheritdoc AbstractCCTPIntegrator\n function _onMessageReceived(bytes memory payload) internal override {\n if (\n payload.getMessageType() ==\n CrossChainStrategyHelper.BALANCE_CHECK_MESSAGE\n ) {\n // Received when Remote strategy checks the balance\n _processBalanceCheckMessage(payload);\n return;\n }\n\n revert(\"Unknown message type\");\n }\n\n /// @inheritdoc AbstractCCTPIntegrator\n function _onTokenReceived(\n uint256 tokenAmount,\n // solhint-disable-next-line no-unused-vars\n uint256 feeExecuted,\n bytes memory payload\n ) internal override {\n uint64 _nonce = lastTransferNonce;\n\n // Should be expecting an acknowledgement\n require(!isNonceProcessed(_nonce), \"Nonce already processed\");\n\n // Now relay to the regular flow\n // NOTE: Calling _onMessageReceived would mean that we are bypassing a\n // few checks that the regular flow does (like sourceDomainID check\n // and sender check in `handleReceiveFinalizedMessage`). However,\n // CCTPMessageRelayer relays the message first (which will go through\n // all the checks) and not update balance and then finally calls this\n // `_onTokenReceived` which will update the balance.\n // So, if any of the checks fail during the first no-balance-update flow,\n // this won't happen either, since the tx would revert.\n _onMessageReceived(payload);\n\n // Send any tokens in the contract to the Vault\n uint256 usdcBalance = IERC20(usdcToken).balanceOf(address(this));\n // Should always have enough tokens\n require(usdcBalance >= tokenAmount, \"Insufficient balance\");\n // Transfer all tokens to the Vault to not leave any dust\n IERC20(usdcToken).safeTransfer(vaultAddress, usdcBalance);\n\n // Emit withdrawal amount\n emit Withdrawal(usdcToken, usdcToken, usdcBalance);\n }\n\n /**\n * @dev Bridge and deposit asset into the remote strategy\n * @param _asset Address of the asset to deposit\n * @param depositAmount Amount of the asset to deposit\n */\n function _deposit(address _asset, uint256 depositAmount) internal virtual {\n require(_asset == usdcToken, \"Unsupported asset\");\n require(pendingAmount == 0, \"Unexpected pending amount\");\n // Deposit at least 1 USDC\n require(\n depositAmount >= MIN_TRANSFER_AMOUNT,\n \"Deposit amount too small\"\n );\n require(\n depositAmount <= MAX_TRANSFER_AMOUNT,\n \"Deposit amount too high\"\n );\n\n // Get the next nonce\n // Note: reverts if a transfer is pending\n uint64 nonce = _getNextNonce();\n\n // Set pending amount\n pendingAmount = depositAmount;\n\n // Build deposit message payload\n bytes memory message = CrossChainStrategyHelper.encodeDepositMessage(\n nonce,\n depositAmount\n );\n\n // Send deposit message to the remote strategy\n _sendTokens(depositAmount, message);\n\n // Emit deposit event\n emit Deposit(_asset, _asset, depositAmount);\n }\n\n /**\n * @dev Send a withdraw request to the remote strategy\n * @param _asset Address of the asset to withdraw\n * @param _amount Amount of the asset to withdraw\n */\n function _withdraw(address _asset, uint256 _amount) internal virtual {\n require(_asset == usdcToken, \"Unsupported asset\");\n // Withdraw at least 1 USDC\n require(_amount >= MIN_TRANSFER_AMOUNT, \"Withdraw amount too small\");\n require(\n _amount <= remoteStrategyBalance,\n \"Withdraw amount exceeds remote strategy balance\"\n );\n require(\n _amount <= MAX_TRANSFER_AMOUNT,\n \"Withdraw amount exceeds max transfer amount\"\n );\n\n // Get the next nonce\n // Note: reverts if a transfer is pending\n uint64 nonce = _getNextNonce();\n\n // Build and send withdrawal message with payload\n bytes memory message = CrossChainStrategyHelper.encodeWithdrawMessage(\n nonce,\n _amount\n );\n _sendMessage(message);\n\n // Emit WithdrawRequested event here,\n // Withdraw will be emitted in _onTokenReceived\n emit WithdrawRequested(usdcToken, _amount);\n }\n\n /**\n * @dev Process balance check:\n * - Confirms a deposit to the remote strategy\n * - Skips balance update if there's a pending withdrawal\n * - Updates the remote strategy balance\n * @param message The message containing the nonce and balance\n */\n function _processBalanceCheckMessage(bytes memory message)\n internal\n virtual\n {\n // Decode the message\n // When transferConfirmation is true, it means that the message is a result of a deposit or a withdrawal\n // process.\n (\n uint64 nonce,\n uint256 balance,\n bool transferConfirmation,\n uint256 timestamp\n ) = message.decodeBalanceCheckMessage();\n // Get the last cached nonce\n uint64 _lastCachedNonce = lastTransferNonce;\n\n if (nonce != _lastCachedNonce) {\n // If nonce is not the last cached nonce, it is an outdated message\n // Ignore it\n return;\n }\n\n // A received message nonce not yet processed indicates there is a\n // deposit or withdrawal in progress.\n bool transferInProgress = isTransferPending();\n\n if (transferInProgress) {\n if (transferConfirmation) {\n // Apply the effects of the deposit / withdrawal completion\n _markNonceAsProcessed(nonce);\n pendingAmount = 0;\n } else {\n // A balanceCheck arrived that is not part of the deposit / withdrawal process\n // that has been generated on the Remote contract after the deposit / withdrawal which is\n // still pending. This can happen when the CCTP bridge delivers the messages out of order.\n // Ignore it, since the pending deposit / withdrawal must first be cofirmed.\n emit BalanceCheckIgnored(nonce, timestamp, false);\n return;\n }\n } else {\n if (block.timestamp > timestamp + MAX_BALANCE_CHECK_AGE) {\n // Balance check is too old, ignore it\n emit BalanceCheckIgnored(nonce, timestamp, true);\n return;\n }\n }\n\n // At this point update the strategy balance the balanceCheck message is either:\n // - a confirmation of a deposit / withdrawal\n // - a message that updates balances when no deposit / withdrawal is in progress\n remoteStrategyBalance = balance;\n emit RemoteStrategyBalanceUpdated(balance);\n }\n}\n" + }, + "contracts/strategies/crosschain/CrossChainRemoteStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title CrossChainRemoteStrategy\n * @author Origin Protocol Inc\n *\n * @dev Part of the cross-chain strategy that lives on the remote chain.\n * Handles deposits and withdrawals from the master strategy on peer chain\n * and locally deposits the funds to a 4626 compatible vault.\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IERC4626 } from \"../../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IVaultV2 } from \"../../interfaces/morpho/IVaultV2.sol\";\nimport { Generalized4626Strategy } from \"../Generalized4626Strategy.sol\";\nimport { AbstractCCTPIntegrator } from \"./AbstractCCTPIntegrator.sol\";\nimport { CrossChainStrategyHelper } from \"./CrossChainStrategyHelper.sol\";\nimport { InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { Strategizable } from \"../../governance/Strategizable.sol\";\nimport { MorphoV2VaultUtils } from \"../MorphoV2VaultUtils.sol\";\n\ncontract CrossChainRemoteStrategy is\n AbstractCCTPIntegrator,\n Generalized4626Strategy,\n Strategizable\n{\n using SafeERC20 for IERC20;\n using CrossChainStrategyHelper for bytes;\n\n event DepositUnderlyingFailed(string reason);\n event WithdrawalFailed(uint256 amountRequested, uint256 amountAvailable);\n event WithdrawUnderlyingFailed(string reason);\n\n modifier onlyOperatorOrStrategistOrGovernor() {\n require(\n msg.sender == operator ||\n msg.sender == strategistAddr ||\n isGovernor(),\n \"Caller is not the Operator, Strategist or the Governor\"\n );\n _;\n }\n\n modifier onlyGovernorOrStrategist()\n override(InitializableAbstractStrategy, Strategizable) {\n require(\n msg.sender == strategistAddr || isGovernor(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n CCTPIntegrationConfig memory _cctpConfig\n )\n AbstractCCTPIntegrator(_cctpConfig)\n Generalized4626Strategy(_baseConfig, _cctpConfig.usdcToken)\n {\n require(usdcToken == address(assetToken), \"Token mismatch\");\n require(\n _baseConfig.platformAddress != address(0),\n \"Invalid platform address\"\n );\n // Vault address must always be address(0) for the remote strategy\n require(\n _baseConfig.vaultAddress == address(0),\n \"Invalid vault address\"\n );\n }\n\n /**\n * @dev Initialize the strategy implementation\n * @param _strategist Address of the strategist\n * @param _operator Address of the operator\n * @param _minFinalityThreshold Minimum finality threshold\n * @param _feePremiumBps Fee premium in basis points\n */\n function initialize(\n address _strategist,\n address _operator,\n uint16 _minFinalityThreshold,\n uint16 _feePremiumBps\n ) external virtual onlyGovernor initializer {\n _initialize(_operator, _minFinalityThreshold, _feePremiumBps);\n _setStrategistAddr(_strategist);\n\n address[] memory rewardTokens = new address[](0);\n address[] memory assets = new address[](1);\n address[] memory pTokens = new address[](1);\n\n assets[0] = address(usdcToken);\n pTokens[0] = address(platformAddress);\n\n InitializableAbstractStrategy._initialize(\n rewardTokens,\n assets,\n pTokens\n );\n }\n\n /// @inheritdoc Generalized4626Strategy\n function deposit(address _asset, uint256 _amount)\n external\n virtual\n override\n onlyGovernorOrStrategist\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /// @inheritdoc Generalized4626Strategy\n function depositAll()\n external\n virtual\n override\n onlyGovernorOrStrategist\n nonReentrant\n {\n _deposit(usdcToken, IERC20(usdcToken).balanceOf(address(this)));\n }\n\n /// @inheritdoc Generalized4626Strategy\n /// @dev Interface requires a recipient, but for compatibility it must be address(this).\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external virtual override onlyGovernorOrStrategist nonReentrant {\n _withdraw(_recipient, _asset, _amount);\n }\n\n /// @inheritdoc Generalized4626Strategy\n function withdrawAll()\n external\n virtual\n override\n onlyGovernorOrStrategist\n nonReentrant\n {\n IERC4626 platform = IERC4626(platformAddress);\n uint256 availableMorphoVault = MorphoV2VaultUtils.maxWithdrawableAssets(\n platformAddress,\n usdcToken\n );\n uint256 amountToWithdraw = Math.min(\n availableMorphoVault,\n platform.previewRedeem(platform.balanceOf(address(this)))\n );\n\n if (amountToWithdraw > 0) {\n _withdraw(address(this), usdcToken, amountToWithdraw);\n }\n }\n\n /// @inheritdoc AbstractCCTPIntegrator\n function _onMessageReceived(bytes memory payload) internal override {\n uint32 messageType = payload.getMessageType();\n if (messageType == CrossChainStrategyHelper.DEPOSIT_MESSAGE) {\n // Received when Master strategy sends tokens to the remote strategy\n // Do nothing because we receive acknowledgement with token transfer,\n // so _onTokenReceived will handle it\n } else if (messageType == CrossChainStrategyHelper.WITHDRAW_MESSAGE) {\n // Received when Master strategy requests a withdrawal\n _processWithdrawMessage(payload);\n } else {\n revert(\"Unknown message type\");\n }\n }\n\n /**\n * @dev Process deposit message from peer strategy\n * @param tokenAmount Amount of tokens received\n * @param feeExecuted Fee executed\n * @param payload Payload of the message\n */\n function _processDepositMessage(\n // solhint-disable-next-line no-unused-vars\n uint256 tokenAmount,\n // solhint-disable-next-line no-unused-vars\n uint256 feeExecuted,\n bytes memory payload\n ) internal virtual {\n (uint64 nonce, ) = payload.decodeDepositMessage();\n\n // Replay protection is part of the _markNonceAsProcessed function\n _markNonceAsProcessed(nonce);\n\n // Deposit everything we got, not just what was bridged\n uint256 balance = IERC20(usdcToken).balanceOf(address(this));\n\n // Underlying call to deposit funds can fail. It mustn't affect the overall\n // flow as confirmation message should still be sent.\n if (balance >= MIN_TRANSFER_AMOUNT) {\n _deposit(usdcToken, balance);\n }\n\n // Send balance check message to the peer strategy\n bytes memory message = CrossChainStrategyHelper\n .encodeBalanceCheckMessage(\n lastTransferNonce,\n checkBalance(usdcToken),\n true,\n block.timestamp\n );\n _sendMessage(message);\n }\n\n /**\n * @dev Deposit assets by converting them to shares\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal override {\n // By design, this function should not revert. Otherwise, it'd\n // not be able to process messages and might freeze the contracts\n // state. However these two require statements would never fail\n // in every function invoking this. The same kind of checks should\n // be enforced in all the calling functions for these two and any\n // other require statements added to this function.\n require(_amount > 0, \"Must deposit something\");\n require(_asset == address(usdcToken), \"Unexpected asset address\");\n\n // This call can fail, and the failure doesn't need to bubble up to the _processDepositMessage function\n // as the flow is not affected by the failure.\n\n try IERC4626(platformAddress).deposit(_amount, address(this)) {\n emit Deposit(_asset, address(shareToken), _amount);\n } catch Error(string memory reason) {\n emit DepositUnderlyingFailed(\n string(abi.encodePacked(\"Deposit failed: \", reason))\n );\n } catch (bytes memory lowLevelData) {\n emit DepositUnderlyingFailed(\n string(\n abi.encodePacked(\n \"Deposit failed: low-level call failed with data \",\n lowLevelData\n )\n )\n );\n }\n }\n\n /**\n * @dev Process withdrawal message from peer strategy\n * @param payload Payload of the message\n */\n function _processWithdrawMessage(bytes memory payload) internal virtual {\n (uint64 nonce, uint256 withdrawAmount) = payload\n .decodeWithdrawMessage();\n\n // Replay protection is part of the _markNonceAsProcessed function\n _markNonceAsProcessed(nonce);\n\n uint256 usdcBalance = IERC20(usdcToken).balanceOf(address(this));\n\n if (usdcBalance < withdrawAmount) {\n // Withdraw the missing funds from the remote strategy. This call can fail and\n // the failure doesn't bubble up to the _processWithdrawMessage function\n _withdraw(address(this), usdcToken, withdrawAmount - usdcBalance);\n\n // Update the possible increase in the balance on the contract.\n usdcBalance = IERC20(usdcToken).balanceOf(address(this));\n }\n\n // Check balance after withdrawal\n uint256 strategyBalance = checkBalance(usdcToken);\n\n // If there are some tokens to be sent AND the balance is sufficient\n // to satisfy the withdrawal request then send the funds to the peer strategy.\n // In case a direct withdraw(All) has previously been called\n // there is a possibility of USDC funds remaining on the contract.\n // A separate withdraw to extract or deposit to the Morpho vault needs to be\n // initiated from the peer Master strategy to utilise USDC funds.\n if (\n withdrawAmount >= MIN_TRANSFER_AMOUNT &&\n usdcBalance >= withdrawAmount\n ) {\n // The new balance on the contract needs to have USDC subtracted from it as\n // that will be withdrawn in the next step\n bytes memory message = CrossChainStrategyHelper\n .encodeBalanceCheckMessage(\n lastTransferNonce,\n strategyBalance - withdrawAmount,\n true,\n block.timestamp\n );\n _sendTokens(withdrawAmount, message);\n } else {\n // Contract either:\n // - only has small dust amount of USDC\n // - doesn't have sufficient funds to satisfy the withdrawal request\n // In both cases send the balance update message to the peer strategy.\n bytes memory message = CrossChainStrategyHelper\n .encodeBalanceCheckMessage(\n lastTransferNonce,\n strategyBalance,\n true,\n block.timestamp\n );\n _sendMessage(message);\n emit WithdrawalFailed(withdrawAmount, usdcBalance);\n }\n }\n\n /**\n * @dev Withdraw asset by burning shares\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal override {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient == address(this), \"Invalid recipient\");\n require(_asset == address(usdcToken), \"Unexpected asset address\");\n\n // This call can fail, and the failure doesn't need to bubble up to the _processWithdrawMessage function\n // as the flow is not affected by the failure.\n try\n // slither-disable-next-line unused-return\n IERC4626(platformAddress).withdraw(\n _amount,\n address(this),\n address(this)\n )\n {\n emit Withdrawal(_asset, address(shareToken), _amount);\n } catch Error(string memory reason) {\n emit WithdrawUnderlyingFailed(\n string(abi.encodePacked(\"Withdrawal failed: \", reason))\n );\n } catch (bytes memory lowLevelData) {\n emit WithdrawUnderlyingFailed(\n string(\n abi.encodePacked(\n \"Withdrawal failed: low-level call failed with data \",\n lowLevelData\n )\n )\n );\n }\n }\n\n /**\n * @dev Process token received message from peer strategy\n * @param tokenAmount Amount of tokens received\n * @param feeExecuted Fee executed\n * @param payload Payload of the message\n */\n function _onTokenReceived(\n uint256 tokenAmount,\n uint256 feeExecuted,\n bytes memory payload\n ) internal override {\n uint32 messageType = payload.getMessageType();\n\n require(\n messageType == CrossChainStrategyHelper.DEPOSIT_MESSAGE,\n \"Invalid message type\"\n );\n\n _processDepositMessage(tokenAmount, feeExecuted, payload);\n }\n\n /**\n * @dev Send balance update message to the peer strategy\n */\n function sendBalanceUpdate()\n external\n virtual\n onlyOperatorOrStrategistOrGovernor\n {\n uint256 balance = checkBalance(usdcToken);\n bytes memory message = CrossChainStrategyHelper\n .encodeBalanceCheckMessage(\n lastTransferNonce,\n balance,\n false,\n block.timestamp\n );\n _sendMessage(message);\n }\n\n /**\n * @notice Get the total asset value held in the platform and contract\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform and contract\n */\n function checkBalance(address _asset)\n public\n view\n override\n returns (uint256)\n {\n require(_asset == usdcToken, \"Unexpected asset address\");\n /**\n * Balance of USDC on the contract is counted towards the total balance, since a deposit\n * to the Morpho V2 might fail and the USDC might remain on this contract as a result of a\n * bridged transfer.\n */\n uint256 balanceOnContract = IERC20(usdcToken).balanceOf(address(this));\n\n IERC4626 platform = IERC4626(platformAddress);\n return\n platform.previewRedeem(platform.balanceOf(address(this))) +\n balanceOnContract;\n }\n}\n" + }, + "contracts/strategies/crosschain/CrossChainStrategyHelper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title CrossChainStrategyHelper\n * @author Origin Protocol Inc\n * @dev This library is used to encode and decode the messages for the cross-chain strategy.\n * It is used to ensure that the messages are valid and to get the message version and type.\n */\n\nimport { BytesHelper } from \"../../utils/BytesHelper.sol\";\n\nlibrary CrossChainStrategyHelper {\n using BytesHelper for bytes;\n\n uint32 public constant DEPOSIT_MESSAGE = 1;\n uint32 public constant WITHDRAW_MESSAGE = 2;\n uint32 public constant BALANCE_CHECK_MESSAGE = 3;\n\n uint32 public constant CCTP_MESSAGE_VERSION = 1;\n uint32 public constant ORIGIN_MESSAGE_VERSION = 1010;\n\n // CCTP Message Header fields\n // Ref: https://developers.circle.com/cctp/technical-guide#message-header\n uint8 private constant VERSION_INDEX = 0;\n uint8 private constant SOURCE_DOMAIN_INDEX = 4;\n uint8 private constant SENDER_INDEX = 44;\n uint8 private constant RECIPIENT_INDEX = 76;\n uint8 private constant MESSAGE_BODY_INDEX = 148;\n\n /**\n * @dev Get the message version from the message.\n * It should always be 4 bytes long,\n * starting from the 0th index.\n * @param message The message to get the version from\n * @return The message version\n */\n function getMessageVersion(bytes memory message)\n internal\n pure\n returns (uint32)\n {\n // uint32 bytes 0 to 4 is Origin message version\n // uint32 bytes 4 to 8 is Message type\n return message.extractUint32(0);\n }\n\n /**\n * @dev Get the message type from the message.\n * It should always be 4 bytes long,\n * starting from the 4th index.\n * @param message The message to get the type from\n * @return The message type\n */\n function getMessageType(bytes memory message)\n internal\n pure\n returns (uint32)\n {\n // uint32 bytes 0 to 4 is Origin message version\n // uint32 bytes 4 to 8 is Message type\n return message.extractUint32(4);\n }\n\n /**\n * @dev Verify the message version and type.\n * The message version should be the same as the Origin message version,\n * and the message type should be the same as the expected message type.\n * @param _message The message to verify\n * @param _type The expected message type\n */\n function verifyMessageVersionAndType(bytes memory _message, uint32 _type)\n internal\n pure\n {\n require(\n getMessageVersion(_message) == ORIGIN_MESSAGE_VERSION,\n \"Invalid Origin Message Version\"\n );\n require(getMessageType(_message) == _type, \"Invalid Message type\");\n }\n\n /**\n * @dev Get the message payload from the message.\n * The payload starts at the 8th byte.\n * @param message The message to get the payload from\n * @return The message payload\n */\n function getMessagePayload(bytes memory message)\n internal\n pure\n returns (bytes memory)\n {\n // uint32 bytes 0 to 4 is Origin message version\n // uint32 bytes 4 to 8 is Message type\n // Payload starts at byte 8\n return message.extractSlice(8, message.length);\n }\n\n /**\n * @dev Encode the deposit message.\n * The message version and type are always encoded in the message.\n * @param nonce The nonce of the deposit\n * @param depositAmount The amount of the deposit\n * @return The encoded deposit message\n */\n function encodeDepositMessage(uint64 nonce, uint256 depositAmount)\n internal\n pure\n returns (bytes memory)\n {\n return\n abi.encodePacked(\n ORIGIN_MESSAGE_VERSION,\n DEPOSIT_MESSAGE,\n abi.encode(nonce, depositAmount)\n );\n }\n\n /**\n * @dev Decode the deposit message.\n * The message version and type are verified in the message.\n * @param message The message to decode\n * @return The nonce and the amount of the deposit\n */\n function decodeDepositMessage(bytes memory message)\n internal\n pure\n returns (uint64, uint256)\n {\n verifyMessageVersionAndType(message, DEPOSIT_MESSAGE);\n\n (uint64 nonce, uint256 depositAmount) = abi.decode(\n getMessagePayload(message),\n (uint64, uint256)\n );\n return (nonce, depositAmount);\n }\n\n /**\n * @dev Encode the withdrawal message.\n * The message version and type are always encoded in the message.\n * @param nonce The nonce of the withdrawal\n * @param withdrawAmount The amount of the withdrawal\n * @return The encoded withdrawal message\n */\n function encodeWithdrawMessage(uint64 nonce, uint256 withdrawAmount)\n internal\n pure\n returns (bytes memory)\n {\n return\n abi.encodePacked(\n ORIGIN_MESSAGE_VERSION,\n WITHDRAW_MESSAGE,\n abi.encode(nonce, withdrawAmount)\n );\n }\n\n /**\n * @dev Decode the withdrawal message.\n * The message version and type are verified in the message.\n * @param message The message to decode\n * @return The nonce and the amount of the withdrawal\n */\n function decodeWithdrawMessage(bytes memory message)\n internal\n pure\n returns (uint64, uint256)\n {\n verifyMessageVersionAndType(message, WITHDRAW_MESSAGE);\n\n (uint64 nonce, uint256 withdrawAmount) = abi.decode(\n getMessagePayload(message),\n (uint64, uint256)\n );\n return (nonce, withdrawAmount);\n }\n\n /**\n * @dev Encode the balance check message.\n * The message version and type are always encoded in the message.\n * @param nonce The nonce of the balance check\n * @param balance The balance to check\n * @param transferConfirmation Indicates if the message is a transfer confirmation. This is true\n * when the message is a result of a deposit or a withdrawal.\n * @return The encoded balance check message\n */\n function encodeBalanceCheckMessage(\n uint64 nonce,\n uint256 balance,\n bool transferConfirmation,\n uint256 timestamp\n ) internal pure returns (bytes memory) {\n return\n abi.encodePacked(\n ORIGIN_MESSAGE_VERSION,\n BALANCE_CHECK_MESSAGE,\n abi.encode(nonce, balance, transferConfirmation, timestamp)\n );\n }\n\n /**\n * @dev Decode the balance check message.\n * The message version and type are verified in the message.\n * @param message The message to decode\n * @return The nonce, the balance and indicates if the message is a transfer confirmation\n */\n function decodeBalanceCheckMessage(bytes memory message)\n internal\n pure\n returns (\n uint64,\n uint256,\n bool,\n uint256\n )\n {\n verifyMessageVersionAndType(message, BALANCE_CHECK_MESSAGE);\n\n (\n uint64 nonce,\n uint256 balance,\n bool transferConfirmation,\n uint256 timestamp\n ) = abi.decode(\n getMessagePayload(message),\n (uint64, uint256, bool, uint256)\n );\n return (nonce, balance, transferConfirmation, timestamp);\n }\n\n /**\n * @dev Decode the CCTP message header\n * @param message Message to decode\n * @return version Version of the message\n * @return sourceDomainID Source domain ID\n * @return sender Sender of the message\n * @return recipient Recipient of the message\n * @return messageBody Message body\n */\n function decodeMessageHeader(bytes memory message)\n internal\n pure\n returns (\n uint32 version,\n uint32 sourceDomainID,\n address sender,\n address recipient,\n bytes memory messageBody\n )\n {\n version = message.extractUint32(VERSION_INDEX);\n sourceDomainID = message.extractUint32(SOURCE_DOMAIN_INDEX);\n // Address of MessageTransmitterV2 caller on source domain\n sender = message.extractAddress(SENDER_INDEX);\n // Address to handle message body on destination domain\n recipient = message.extractAddress(RECIPIENT_INDEX);\n messageBody = message.extractSlice(MESSAGE_BODY_INDEX, message.length);\n }\n}\n" + }, + "contracts/strategies/CurveAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Curve Automated Market Maker (AMO) Strategy\n * @notice AMO strategy for a Curve pool using an OToken.\n * @author Origin Protocol Inc\n */\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { ICurveStableSwapNG } from \"../interfaces/ICurveStableSwapNG.sol\";\nimport { ICurveLiquidityGaugeV6 } from \"../interfaces/ICurveLiquidityGaugeV6.sol\";\nimport { IBasicToken } from \"../interfaces/IBasicToken.sol\";\nimport { ICurveMinter } from \"../interfaces/ICurveMinter.sol\";\n\ncontract CurveAMOStrategy is InitializableAbstractStrategy {\n using SafeCast for uint256;\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n /**\n * @dev a threshold under which the contract no longer allows for the protocol to manually rebalance.\n * Guarding against a strategist / guardian being taken over and with multiple transactions\n * draining the protocol funds.\n */\n uint256 public constant SOLVENCY_THRESHOLD = 0.998 ether;\n\n // New immutable variables that must be set in the constructor\n /**\n * @notice Address of the hard asset (weth, usdt, usdc).\n */\n IERC20 public immutable hardAsset;\n\n /**\n * @notice Address of the OTOKEN token contract.\n */\n IERC20 public immutable oToken;\n\n /**\n * @notice Address of the LP (Liquidity Provider) token contract.\n */\n IERC20 public immutable lpToken;\n\n /**\n * @notice Address of the Curve StableSwap NG pool contract.\n */\n ICurveStableSwapNG public immutable curvePool;\n\n /**\n * @notice Address of the Curve X-Chain Liquidity Gauge contract.\n */\n ICurveLiquidityGaugeV6 public immutable gauge;\n\n /**\n * @notice Address of the Curve Minter contract.\n */\n ICurveMinter public immutable minter;\n\n /**\n * @notice Index of the OTOKEN and hardAsset in the Curve pool.\n */\n uint128 public immutable otokenCoinIndex;\n uint128 public immutable hardAssetCoinIndex;\n\n /**\n * @notice Decimals of the OTOKEN and hardAsset.\n */\n uint8 public immutable decimalsOToken;\n uint8 public immutable decimalsHardAsset;\n\n /**\n * @notice Maximum slippage allowed for adding/removing liquidity from the Curve pool.\n */\n uint256 public maxSlippage;\n\n event MaxSlippageUpdated(uint256 newMaxSlippage);\n\n /**\n * @dev Verifies that the caller is the Strategist.\n */\n modifier onlyStrategist() {\n require(\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n _;\n }\n\n /**\n * @dev Checks the Curve pool's balances have improved and the balances\n * have not tipped to the other side.\n * This modifier is only applied to functions that do a single sided add or remove.\n * The standard deposit function adds to both sides of the pool in a way that\n * the pool's balance is not worsened.\n * Withdrawals are proportional so doesn't change the pools asset balance.\n */\n modifier improvePoolBalance() {\n // Get the hard asset and OToken balances in the Curve pool\n uint256[] memory balancesBefore = curvePool.get_balances();\n // diff = hardAsset balance - OTOKEN balance\n int256 diffBefore = (\n balancesBefore[hardAssetCoinIndex].scaleBy(\n decimalsOToken,\n decimalsHardAsset\n )\n ).toInt256() - balancesBefore[otokenCoinIndex].toInt256();\n\n _;\n\n // Get the hard asset and OToken balances in the Curve pool\n uint256[] memory balancesAfter = curvePool.get_balances();\n // diff = hardAsset balance - OTOKEN balance\n int256 diffAfter = (\n balancesAfter[hardAssetCoinIndex].scaleBy(\n decimalsOToken,\n decimalsHardAsset\n )\n ).toInt256() - balancesAfter[otokenCoinIndex].toInt256();\n\n if (diffBefore == 0) {\n require(diffAfter == 0, \"Position balance is worsened\");\n } else if (diffBefore < 0) {\n // If the pool was originally imbalanced in favor of OTOKEN, then\n // we want to check that the pool is now more balanced\n require(diffAfter <= 0, \"OTokens overshot peg\");\n require(diffBefore < diffAfter, \"OTokens balance worse\");\n } else if (diffBefore > 0) {\n // If the pool was originally imbalanced in favor of hardAsset, then\n // we want to check that the pool is now more balanced\n require(diffAfter >= 0, \"Assets overshot peg\");\n require(diffAfter < diffBefore, \"Assets balance worse\");\n }\n }\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _otoken,\n address _hardAsset,\n address _gauge,\n address _minter\n ) InitializableAbstractStrategy(_baseConfig) {\n lpToken = IERC20(_baseConfig.platformAddress);\n curvePool = ICurveStableSwapNG(_baseConfig.platformAddress);\n minter = ICurveMinter(_minter);\n\n oToken = IERC20(_otoken);\n hardAsset = IERC20(_hardAsset);\n gauge = ICurveLiquidityGaugeV6(_gauge);\n decimalsHardAsset = IBasicToken(_hardAsset).decimals();\n decimalsOToken = IBasicToken(_otoken).decimals();\n\n (hardAssetCoinIndex, otokenCoinIndex) = curvePool.coins(0) == _hardAsset\n ? (0, 1)\n : (1, 0);\n require(\n curvePool.coins(otokenCoinIndex) == _otoken &&\n curvePool.coins(hardAssetCoinIndex) == _hardAsset,\n \"Invalid coin indexes\"\n );\n require(gauge.lp_token() == address(curvePool), \"Invalid pool\");\n }\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Curve strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Address of CRV\n * @param _maxSlippage Maximum slippage allowed for adding/removing liquidity from the Curve pool.\n */\n function initialize(\n address[] calldata _rewardTokenAddresses, // CRV\n uint256 _maxSlippage\n ) external onlyGovernor initializer {\n address[] memory pTokens = new address[](1);\n pTokens[0] = address(curvePool);\n\n address[] memory _assets = new address[](1);\n _assets[0] = address(hardAsset);\n\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n pTokens\n );\n\n _approveBase();\n _setMaxSlippage(_maxSlippage);\n }\n\n /***************************************\n Deposit\n ****************************************/\n\n /**\n * @notice Deposit hard asset into the Curve pool\n * @param _hardAsset Address of hard asset contract.\n * @param _amount Amount of hard asset to deposit.\n */\n function deposit(address _hardAsset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_hardAsset, _amount);\n }\n\n function _deposit(address _hardAsset, uint256 _hardAssetAmount) internal {\n require(_hardAssetAmount > 0, \"Must deposit something\");\n require(_hardAsset == address(hardAsset), \"Unsupported asset\");\n\n emit Deposit(_hardAsset, address(lpToken), _hardAssetAmount);\n uint256 scaledHardAssetAmount = _hardAssetAmount.scaleBy(\n decimalsOToken,\n decimalsHardAsset\n );\n\n // Get the asset and OToken balances in the Curve pool\n uint256[] memory balances = curvePool.get_balances();\n // safe to cast since min value is at least 0\n uint256 otokenToAdd = uint256(\n _max(\n 0,\n (\n balances[hardAssetCoinIndex].scaleBy(\n decimalsOToken,\n decimalsHardAsset\n )\n ).toInt256() +\n scaledHardAssetAmount.toInt256() -\n balances[otokenCoinIndex].toInt256()\n )\n );\n\n /* Add so much OTOKEN so that the pool ends up being balanced. And at minimum\n * add as much OTOKEN as hard asset and at maximum twice as much OTOKEN.\n */\n otokenToAdd = Math.max(otokenToAdd, scaledHardAssetAmount);\n otokenToAdd = Math.min(otokenToAdd, scaledHardAssetAmount * 2);\n\n /* Mint OTOKEN with a strategy that attempts to contribute to stability of OTOKEN/hardAsset pool. Try\n * to mint so much OTOKEN that after deployment of liquidity pool ends up being balanced.\n *\n * To manage unpredictability minimal OTOKEN minted will always be at least equal or greater\n * to hardAsset amount deployed. And never larger than twice the hardAsset amount deployed even if\n * it would have a further beneficial effect on pool stability.\n */\n IVault(vaultAddress).mintForStrategy(otokenToAdd);\n\n emit Deposit(address(oToken), address(lpToken), otokenToAdd);\n\n uint256[] memory _amounts = new uint256[](2);\n _amounts[hardAssetCoinIndex] = _hardAssetAmount;\n _amounts[otokenCoinIndex] = otokenToAdd;\n\n uint256 valueInLpTokens = (scaledHardAssetAmount + otokenToAdd)\n .divPrecisely(curvePool.get_virtual_price());\n uint256 minMintAmount = valueInLpTokens.mulTruncate(\n uint256(1e18) - maxSlippage\n );\n\n // Do the deposit to the Curve pool\n uint256 lpDeposited = curvePool.add_liquidity(_amounts, minMintAmount);\n require(lpDeposited >= minMintAmount, \"Min LP amount error\");\n\n // Deposit the Curve pool's LP tokens into the Curve gauge\n gauge.deposit(lpDeposited);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n }\n\n /**\n * @notice Deposit the strategy's entire balance of hardAsset into the Curve pool\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 balance = hardAsset.balanceOf(address(this));\n if (balance > 0) {\n _deposit(address(hardAsset), balance);\n }\n }\n\n /***************************************\n Withdraw\n ****************************************/\n\n /**\n * @notice Withdraw hardAsset and OTOKEN from the Curve pool, burn the OTOKEN,\n * transfer hardAsset to the recipient.\n * @param _recipient Address to receive withdrawn asset which is normally the Vault.\n * @param _hardAsset Address of the hardAsset contract.\n * @param _amount Amount of hardAsset to withdraw.\n */\n function withdraw(\n address _recipient,\n address _hardAsset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(\n _hardAsset == address(hardAsset),\n \"Can only withdraw hard asset\"\n );\n\n emit Withdrawal(_hardAsset, address(lpToken), _amount);\n\n uint256 requiredLpTokens = calcTokenToBurn(\n _amount.scaleBy(decimalsOToken, decimalsHardAsset)\n );\n\n _lpWithdraw(requiredLpTokens);\n\n /* math in requiredLpTokens should correctly calculate the amount of LP to remove\n * in that the strategy receives enough hardAsset on balanced removal\n */\n uint256[] memory _minWithdrawalAmounts = new uint256[](2);\n _minWithdrawalAmounts[hardAssetCoinIndex] = _amount;\n // slither-disable-next-line unused-return\n curvePool.remove_liquidity(requiredLpTokens, _minWithdrawalAmounts);\n\n // Burn all the removed OTOKEN and any that was left in the strategy\n uint256 otokenToBurn = oToken.balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(otokenToBurn);\n\n emit Withdrawal(address(oToken), address(lpToken), otokenToBurn);\n\n // Transfer hardAsset to the recipient\n hardAsset.safeTransfer(_recipient, _amount);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n }\n\n function calcTokenToBurn(uint256 _hardAssetAmount)\n internal\n view\n returns (uint256 lpToBurn)\n {\n /* The rate between coins in the pool determines the rate at which pool returns\n * tokens when doing balanced removal (remove_liquidity call). And by knowing how much hardAsset\n * we want we can determine how much of OTOKEN we receive by removing liquidity.\n *\n * Because we are doing balanced removal we should be making profit when removing liquidity in a\n * pool tilted to either side.\n *\n * Important: A downside is that the Strategist / Governor needs to be\n * cognisant of not removing too much liquidity. And while the proposal to remove liquidity\n * is being voted on the pool tilt might change so much that the proposal that has been valid while\n * created is no longer valid.\n */\n\n uint256 poolHardAssetBalance = curvePool\n .balances(hardAssetCoinIndex)\n .scaleBy(decimalsOToken, decimalsHardAsset);\n /* K is multiplied by 1e36 which is used for higher precision calculation of required\n * pool LP tokens. Without it the end value can have rounding errors up to precision of\n * 10 digits. This way we move the decimal point by 36 places when doing the calculation\n * and again by 36 places when we are done with it.\n */\n uint256 k = (1e36 * lpToken.totalSupply()) / poolHardAssetBalance;\n // prettier-ignore\n // slither-disable-next-line divide-before-multiply\n uint256 diff = (_hardAssetAmount + 1) * k;\n lpToBurn = diff / 1e36;\n }\n\n /**\n * @notice Remove all hardAsset and OTOKEN from the Curve pool, burn the OTOKEN,\n * transfer hardAsset to the Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 gaugeTokens = gauge.balanceOf(address(this));\n _lpWithdraw(gaugeTokens);\n\n // Withdraws are proportional to assets held by 3Pool\n uint256[] memory minWithdrawAmounts = new uint256[](2);\n\n // Check balance of LP tokens in the strategy, if 0 return\n uint256 lpBalance = lpToken.balanceOf(address(this));\n\n // Remove liquidity\n // slither-disable-next-line unused-return\n if (lpBalance > 0) {\n curvePool.remove_liquidity(lpBalance, minWithdrawAmounts);\n }\n\n // Burn all OTOKEN\n uint256 otokenToBurn = oToken.balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(otokenToBurn);\n\n // Get the strategy contract's hardAsset balance.\n // This includes all that was removed from the Curve pool and\n // any hardAsset that was sitting in the strategy contract before the removal.\n uint256 hardAssetBalance = hardAsset.balanceOf(address(this));\n hardAsset.safeTransfer(vaultAddress, hardAssetBalance);\n\n if (hardAssetBalance > 0)\n emit Withdrawal(\n address(hardAsset),\n address(lpToken),\n hardAssetBalance\n );\n if (otokenToBurn > 0)\n emit Withdrawal(address(oToken), address(lpToken), otokenToBurn);\n }\n\n /***************************************\n Curve pool Rebalancing\n ****************************************/\n\n /**\n * @notice Mint OTokens and one-sided add to the Curve pool.\n * This is used when the Curve pool does not have enough OTokens and too many hardAsset.\n * The OToken/Asset, eg OTOKEN/hardAsset, price with increase.\n * The amount of assets in the vault is unchanged.\n * The total supply of OTokens is increased.\n * The asset value of the strategy and vault is increased.\n * @param _oTokens The amount of OTokens to be minted and added to the pool.\n */\n function mintAndAddOTokens(uint256 _oTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n IVault(vaultAddress).mintForStrategy(_oTokens);\n\n uint256[] memory amounts = new uint256[](2);\n amounts[otokenCoinIndex] = _oTokens;\n\n // Convert OTOKEN to Curve pool LP tokens\n uint256 valueInLpTokens = (_oTokens).divPrecisely(\n curvePool.get_virtual_price()\n );\n // Apply slippage to LP tokens\n uint256 minMintAmount = valueInLpTokens.mulTruncate(\n uint256(1e18) - maxSlippage\n );\n\n // Add the minted OTokens to the Curve pool\n uint256 lpDeposited = curvePool.add_liquidity(amounts, minMintAmount);\n require(lpDeposited >= minMintAmount, \"Min LP amount error\");\n\n // Deposit the Curve pool LP tokens to the Curve gauge\n gauge.deposit(lpDeposited);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Deposit(address(oToken), address(lpToken), _oTokens);\n }\n\n /**\n * @notice One-sided remove of OTokens from the Curve pool which are then burned.\n * This is used when the Curve pool has too many OTokens and not enough hardAsset.\n * The amount of assets in the vault is unchanged.\n * The total supply of OTokens is reduced.\n * The asset value of the strategy and vault is reduced.\n * @param _lpTokens The amount of Curve pool LP tokens to be burned for OTokens.\n */\n function removeAndBurnOTokens(uint256 _lpTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n // Withdraw Curve pool LP tokens from gauge and remove OTokens from the Curve pool\n uint256 otokenToBurn = _withdrawAndRemoveFromPool(\n _lpTokens,\n otokenCoinIndex\n );\n\n // The vault burns the OTokens from this strategy\n IVault(vaultAddress).burnForStrategy(otokenToBurn);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Withdrawal(address(oToken), address(lpToken), otokenToBurn);\n }\n\n /**\n * @notice One-sided remove of hardAsset from the Curve pool and transfer to the vault.\n * This is used when the Curve pool does not have enough OTokens and too many hardAsset.\n * The OToken/Asset, eg OTOKEN/hardAsset, price with decrease.\n * The amount of assets in the vault increases.\n * The total supply of OTokens does not change.\n * The asset value of the strategy reduces.\n * The asset value of the vault should be close to the same.\n * @param _lpTokens The amount of Curve pool LP tokens to be burned for hardAsset.\n * @dev Curve pool LP tokens is used rather than hardAsset assets as Curve does not\n * have a way to accurately calculate the amount of LP tokens for a required\n * amount of hardAsset. Curve's `calc_token_amount` function does not include fees.\n * A 3rd party library can be used that takes into account the fees, but this\n * is a gas intensive process. It's easier for the trusted strategist to\n * calculate the amount of Curve pool LP tokens required off-chain.\n */\n function removeOnlyAssets(uint256 _lpTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n // Withdraw Curve pool LP tokens from Curve gauge and remove hardAsset from the Curve pool\n uint256 hardAssetAmount = _withdrawAndRemoveFromPool(\n _lpTokens,\n hardAssetCoinIndex\n );\n\n // Transfer hardAsset to the vault\n hardAsset.safeTransfer(vaultAddress, hardAssetAmount);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Withdrawal(address(hardAsset), address(lpToken), hardAssetAmount);\n }\n\n /**\n * @dev Remove Curve pool LP tokens from the gauge and\n * do a one-sided remove of hardAsset or OTOKEN from the Curve pool.\n * @param _lpTokens The amount of Curve pool LP tokens to be removed from the gauge\n * @param coinIndex The index of the coin to be removed from the Curve pool. 0 = hardAsset, 1 = OTOKEN.\n * @return coinsRemoved The amount of hardAsset or OTOKEN removed from the Curve pool.\n */\n function _withdrawAndRemoveFromPool(uint256 _lpTokens, uint128 coinIndex)\n internal\n returns (uint256 coinsRemoved)\n {\n // Withdraw Curve pool LP tokens from Curve gauge\n _lpWithdraw(_lpTokens);\n\n // Convert Curve pool LP tokens to hardAsset value\n uint256 valueInEth = _lpTokens.mulTruncate(\n curvePool.get_virtual_price()\n );\n\n if (coinIndex == hardAssetCoinIndex) {\n valueInEth = valueInEth.scaleBy(decimalsHardAsset, decimalsOToken);\n }\n\n // Apply slippage to hardAsset value\n uint256 minAmount = valueInEth.mulTruncate(uint256(1e18) - maxSlippage);\n\n // Remove just the hardAsset from the Curve pool\n coinsRemoved = curvePool.remove_liquidity_one_coin(\n _lpTokens,\n int128(coinIndex),\n minAmount,\n address(this)\n );\n }\n\n /**\n * Checks that the protocol is solvent, protecting from a rogue Strategist / Guardian that can\n * keep rebalancing the pool in both directions making the protocol lose a tiny amount of\n * funds each time.\n *\n * Protocol must be at least SOLVENCY_THRESHOLD (99,8 %) backed in order for the rebalances to\n * function.\n */\n function _solvencyAssert() internal view {\n uint256 _totalVaultValue = IVault(vaultAddress).totalValue();\n uint256 _totalOtokenSupply = oToken.totalSupply();\n\n if (\n _totalVaultValue.divPrecisely(_totalOtokenSupply) <\n SOLVENCY_THRESHOLD\n ) {\n revert(\"Protocol insolvent\");\n }\n }\n\n /***************************************\n Assets and Rewards\n ****************************************/\n\n /**\n * @notice Collect accumulated CRV (and other) rewards and send to the Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvesterOrStrategist\n nonReentrant\n {\n // Collect CRV rewards from inflation\n minter.mint(address(gauge));\n\n // Collect extra gauge rewards (outside of CRV)\n gauge.claim_rewards();\n\n _collectRewardTokens();\n }\n\n function _lpWithdraw(uint256 _lpAmount) internal {\n require(\n gauge.balanceOf(address(this)) >= _lpAmount,\n \"Insufficient LP tokens\"\n );\n // withdraw lp tokens from the gauge without claiming rewards\n gauge.withdraw(_lpAmount);\n }\n\n /**\n * @notice Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == address(hardAsset), \"Unsupported asset\");\n\n // hardAsset balance needed here for the balance check that happens from vault during depositing.\n balance = hardAsset.balanceOf(address(this));\n uint256 lpTokens = gauge.balanceOf(address(this));\n if (lpTokens > 0) {\n balance += ((lpTokens * curvePool.get_virtual_price()) / 1e18)\n .scaleBy(decimalsHardAsset, decimalsOToken);\n }\n }\n\n /**\n * @notice Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == address(hardAsset);\n }\n\n /***************************************\n Approvals\n ****************************************/\n\n /**\n * @notice Sets the maximum slippage allowed for any swap/liquidity operation\n * @param _maxSlippage Maximum slippage allowed, 1e18 = 100%.\n */\n function setMaxSlippage(uint256 _maxSlippage) external onlyGovernor {\n _setMaxSlippage(_maxSlippage);\n }\n\n function _setMaxSlippage(uint256 _maxSlippage) internal {\n require(_maxSlippage <= 5e16, \"Slippage must be less than 100%\");\n maxSlippage = _maxSlippage;\n emit MaxSlippageUpdated(_maxSlippage);\n }\n\n /**\n * @notice Approve the spending of all assets by their corresponding pool tokens,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n _approveBase();\n }\n\n /**\n * @dev Since we are unwrapping WETH before depositing it to Curve\n * there is no need to set an approval for WETH on the Curve\n * pool\n * @param _asset Address of the asset\n * @param _pToken Address of the Curve LP token\n */\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {}\n\n function _approveBase() internal {\n // Approve Curve pool for OTOKEN (required for adding liquidity)\n // slither-disable-next-line unused-return\n oToken.approve(platformAddress, type(uint256).max);\n\n // Approve Curve pool for hardAsset (required for adding liquidity)\n // slither-disable-next-line unused-return\n hardAsset.safeApprove(platformAddress, type(uint256).max);\n\n // Approve Curve gauge contract to transfer Curve pool LP tokens\n // This is needed for deposits if Curve pool LP tokens into the Curve gauge.\n // slither-disable-next-line unused-return\n lpToken.approve(address(gauge), type(uint256).max);\n }\n\n /**\n * @dev Returns the largest of two numbers int256 version\n */\n function _max(int256 a, int256 b) internal pure returns (int256) {\n return a >= b ? a : b;\n }\n}\n" + }, + "contracts/strategies/Generalized4626Strategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Generalized 4626 Strategy\n * @notice Investment strategy for ERC-4626 Tokenized Vaults\n * @dev This strategy should not be used for the Morpho V2 Vaults as those are not\n * completley ERC-4626 compliant - they don't implement the maxWithdraw() and\n * maxRedeem() functions and rather return 0 when any of them is called.\n * @author Origin Protocol Inc\n */\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { IDistributor } from \"../interfaces/IMerkl.sol\";\n\ncontract Generalized4626Strategy is InitializableAbstractStrategy {\n /// @notice The address of the Merkle Distributor contract.\n IDistributor public constant merkleDistributor =\n IDistributor(0x3Ef3D8bA38EBe18DB133cEc108f4D14CE00Dd9Ae);\n\n /// @dev Replaced with an immutable variable\n // slither-disable-next-line constable-states\n address private _deprecate_shareToken;\n /// @dev Replaced with an immutable variable\n // slither-disable-next-line constable-states\n address private _deprecate_assetToken;\n\n IERC20 public immutable shareToken;\n IERC20 public immutable assetToken;\n\n // For future use\n uint256[50] private __gap;\n\n event ClaimedRewards(address indexed token, uint256 amount);\n\n /**\n * @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI,\n * and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\n * @param _assetToken Address of the ERC-4626 asset token. eg frxETH or DAI\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _assetToken)\n InitializableAbstractStrategy(_baseConfig)\n {\n shareToken = IERC20(_baseConfig.platformAddress);\n assetToken = IERC20(_assetToken);\n }\n\n function initialize() external virtual onlyGovernor initializer {\n address[] memory rewardTokens = new address[](0);\n address[] memory assets = new address[](1);\n address[] memory pTokens = new address[](1);\n\n assets[0] = address(assetToken);\n pTokens[0] = address(platformAddress);\n\n InitializableAbstractStrategy._initialize(\n rewardTokens,\n assets,\n pTokens\n );\n }\n\n /**\n * @dev Deposit assets by converting them to shares\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n virtual\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /**\n * @dev Deposit assets by converting them to shares\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal virtual {\n require(_amount > 0, \"Must deposit something\");\n require(_asset == address(assetToken), \"Unexpected asset address\");\n\n // slither-disable-next-line unused-return\n IERC4626(platformAddress).deposit(_amount, address(this));\n emit Deposit(_asset, address(shareToken), _amount);\n }\n\n /**\n * @dev Deposit the entire balance of assetToken to gain shareToken\n */\n function depositAll() external virtual override onlyVault nonReentrant {\n uint256 balance = assetToken.balanceOf(address(this));\n if (balance > 0) {\n _deposit(address(assetToken), balance);\n }\n }\n\n /**\n * @dev Withdraw asset by burning shares\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external virtual override onlyVault nonReentrant {\n _withdraw(_recipient, _asset, _amount);\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal virtual {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n require(_asset == address(assetToken), \"Unexpected asset address\");\n\n // slither-disable-next-line unused-return\n IERC4626(platformAddress).withdraw(_amount, _recipient, address(this));\n emit Withdrawal(_asset, address(shareToken), _amount);\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset / share tokens\n */\n function _abstractSetPToken(address, address) internal virtual override {\n _approveBase();\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll()\n external\n virtual\n override\n onlyVaultOrGovernor\n nonReentrant\n {\n // @dev Don't use for Morpho V2 Vaults as below line will return 0\n uint256 sharesToRedeem = IERC4626(platformAddress).maxRedeem(\n address(this)\n );\n\n uint256 assetAmount = 0;\n if (sharesToRedeem > 0) {\n assetAmount = IERC4626(platformAddress).redeem(\n sharesToRedeem,\n vaultAddress,\n address(this)\n );\n emit Withdrawal(\n address(assetToken),\n address(shareToken),\n assetAmount\n );\n }\n }\n\n /**\n * @notice Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n public\n view\n virtual\n override\n returns (uint256 balance)\n {\n require(_asset == address(assetToken), \"Unexpected asset address\");\n /* We are intentionally not counting the amount of assetToken parked on the\n * contract toward the checkBalance. The deposit and withdraw functions\n * should not result in assetToken being unused and owned by this strategy\n * contract.\n */\n IERC4626 platform = IERC4626(platformAddress);\n return platform.previewRedeem(platform.balanceOf(address(this)));\n }\n\n /**\n * @notice Governor approves the ERC-4626 Tokenized Vault to spend the asset.\n */\n function safeApproveAllTokens() external override onlyGovernor {\n _approveBase();\n }\n\n function _approveBase() internal virtual {\n // Approval the asset to be transferred to the ERC-4626 Tokenized Vault.\n // Used by the ERC-4626 deposit() and mint() functions\n // slither-disable-next-line unused-return\n assetToken.approve(platformAddress, type(uint256).max);\n }\n\n /**\n * @dev Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset)\n public\n view\n virtual\n override\n returns (bool)\n {\n return _asset == address(assetToken);\n }\n\n /**\n * @notice is not supported for this strategy as the asset and\n * ERC-4626 Tokenized Vault are set at deploy time.\n * @dev If the ERC-4626 Tokenized Vault needed to be changed, a new\n * contract would need to be deployed and the proxy updated.\n */\n function setPTokenAddress(address, address) external override onlyGovernor {\n revert(\"unsupported function\");\n }\n\n /**\n * @notice is not supported for this strategy as the asset and\n * ERC-4626 Tokenized Vault are set at deploy time.\n * @dev If the ERC-4626 Tokenized Vault needed to be changed, a new\n * contract would need to be deployed and the proxy updated.\n */\n function removePToken(uint256) external override onlyGovernor {\n revert(\"unsupported function\");\n }\n\n /// @notice Claim tokens from the Merkle Distributor\n /// @param token The address of the token to claim.\n /// @param amount The amount of tokens to claim.\n /// @param proof The Merkle proof to validate the claim.\n function merkleClaim(\n address token,\n uint256 amount,\n bytes32[] calldata proof\n ) external {\n address[] memory users = new address[](1);\n users[0] = address(this);\n\n address[] memory tokens = new address[](1);\n tokens[0] = token;\n\n uint256[] memory amounts = new uint256[](1);\n amounts[0] = amount;\n\n bytes32[][] memory proofs = new bytes32[][](1);\n proofs[0] = proof;\n\n merkleDistributor.claim(users, tokens, amounts, proofs);\n\n emit ClaimedRewards(token, amount);\n }\n}\n" + }, + "contracts/strategies/hydrex/OETHbHydrexAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OETHb Hydrex Algorithmic Market Maker (AMO) Strategy\n * @notice AMO strategy for the Hydrex superOETHb/WETH stable pool on Base\n * @author Origin Protocol Inc\n */\nimport { StableSwapAMMStrategy } from \"../algebra/StableSwapAMMStrategy.sol\";\nimport { IHydrexGauge } from \"../../interfaces/hydrex/IHydrexGauge.sol\";\n\ncontract OETHbHydrexAMOStrategy is StableSwapAMMStrategy {\n /**\n * @param _baseConfig The `platformAddress` is the address of the Hydrex superOETHb/WETH pool.\n * The `vaultAddress` is the address of the OETHBase Vault.\n * @param _gauge Address of the Hydrex gauge for the pool. Hydrex GaugeV2\n * (>= v2.5) renamed `TOKEN()` to `stakeToken()`, which is what we\n * resolve here and forward to the parent.\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _gauge)\n StableSwapAMMStrategy(\n _baseConfig,\n _gauge,\n IHydrexGauge(_gauge).stakeToken()\n )\n {}\n}\n" + }, + "contracts/strategies/ICurvePool.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface ICurvePool {\n function get_virtual_price() external view returns (uint256);\n\n function add_liquidity(uint256[3] calldata _amounts, uint256 _min) external;\n\n function balances(uint256) external view returns (uint256);\n\n function calc_token_amount(uint256[3] calldata _amounts, bool _deposit)\n external\n returns (uint256);\n\n function fee() external view returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _amount,\n int128 _index,\n uint256 _minAmount\n ) external;\n\n function remove_liquidity(\n uint256 _amount,\n uint256[3] calldata _minWithdrawAmounts\n ) external;\n\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n external\n view\n returns (uint256);\n\n function exchange(\n uint256 i,\n uint256 j,\n uint256 dx,\n uint256 min_dy\n ) external returns (uint256);\n\n function coins(uint256 _index) external view returns (address);\n\n function remove_liquidity_imbalance(\n uint256[3] calldata _amounts,\n uint256 maxBurnAmount\n ) external;\n}\n" + }, + "contracts/strategies/MorphoV2Strategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Generalized 4626 Strategy when the underlying platform is Morpho V2\n * @notice Investment strategy for ERC-4626 Tokenized Vaults for the Morpho V2 platform.\n * @author Origin Protocol Inc\n */\nimport { Generalized4626Strategy } from \"./Generalized4626Strategy.sol\";\nimport { MorphoV2VaultUtils } from \"./MorphoV2VaultUtils.sol\";\nimport { IVaultV2 } from \"../interfaces/morpho/IVaultV2.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\ncontract MorphoV2Strategy is Generalized4626Strategy {\n /**\n * @param _baseConfig Base strategy config with Morpho V2 Vault and\n * vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\n * @param _assetToken Address of the ERC-4626 asset token. e.g. USDC\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _assetToken)\n Generalized4626Strategy(_baseConfig, _assetToken)\n {}\n\n /**\n * @notice Remove all the liquidity that is available in the Morpho V2 vault.\n * Which might not be all of the liquidity owned by the strategy.\n * @dev Remove all the liquidity that is available in the Morpho V2 vault\n * The particular behaviour of the Morpho V2 vault is that it can hold\n * multiple Morpho V1 vaults as adapters but only one liquidity adapter.\n * The immediate available funds on the Morpho V2 vault are therfore any\n * liquid assets residing on the Vault V2 contract and the maxWithdraw\n * amount that the Morpho V1 contract can supply.\n */\n function withdrawAll()\n external\n virtual\n override\n onlyVaultOrGovernor\n nonReentrant\n {\n uint256 availableMorphoVault = _maxWithdraw();\n uint256 balanceToWithdraw = Math.min(\n availableMorphoVault,\n checkBalance(address(assetToken))\n );\n\n if (balanceToWithdraw > 0) {\n // slither-disable-next-line unused-return\n IVaultV2(platformAddress).withdraw(\n balanceToWithdraw,\n vaultAddress,\n address(this)\n );\n }\n\n emit Withdrawal(\n address(assetToken),\n address(shareToken),\n balanceToWithdraw\n );\n }\n\n function maxWithdraw() external view returns (uint256) {\n return _maxWithdraw();\n }\n\n function _maxWithdraw()\n internal\n view\n returns (uint256 availableAssetLiquidity)\n {\n availableAssetLiquidity = MorphoV2VaultUtils.maxWithdrawableAssets(\n platformAddress,\n address(assetToken)\n );\n }\n}\n" + }, + "contracts/strategies/MorphoV2VaultUtils.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IVaultV2 } from \"../interfaces/morpho/IVaultV2.sol\";\nimport { IMorphoV2Adapter } from \"../interfaces/morpho/IMorphoV2Adapter.sol\";\n\nlibrary MorphoV2VaultUtils {\n error IncompatibleAdapter(address adapter);\n\n /**\n * @notice Return maximum amount that can be safely withdrawn from a Morpho V2 vault.\n * @dev Available liquidity is:\n * 1) asset balance parked on Morpho V2 vault contract\n * 2) additional liquidity from the active adapter if it resolves to a Morpho V1 vault\n * and, when provided, matches the expected adapter\n */\n function maxWithdrawableAssets(address platformAddress, address assetToken)\n internal\n view\n returns (uint256 availableAssetLiquidity)\n {\n availableAssetLiquidity = IERC20(assetToken).balanceOf(platformAddress);\n\n address liquidityAdapter = IVaultV2(platformAddress).liquidityAdapter();\n // this is a sufficient check to ensure the adapter is Morpho V1\n try IMorphoV2Adapter(liquidityAdapter).morphoVaultV1() returns (\n address underlyingVault\n ) {\n availableAssetLiquidity += IERC4626(underlyingVault).maxWithdraw(\n liquidityAdapter\n );\n } catch {\n revert IncompatibleAdapter(liquidityAdapter);\n }\n }\n}\n" + }, + "contracts/strategies/NativeStaking/CompoundingStakingSSVStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { CompoundingValidatorManager } from \"./CompoundingValidatorManager.sol\";\n\n/// @title Compounding Staking SSV Strategy\n/// @notice Strategy to deploy funds into DVT validators powered by the SSV Network\n/// @author Origin Protocol Inc\ncontract CompoundingStakingSSVStrategy is\n CompoundingValidatorManager,\n InitializableAbstractStrategy\n{\n // For future use\n uint256[50] private __gap;\n\n /// @param _baseConfig Base strategy config with\n /// `platformAddress` not used so empty address\n /// `vaultAddress` the address of the OETH Vault contract\n /// @param _wethAddress Address of the WETH Token contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _beaconProofs Address of the Beacon Proofs contract that verifies beacon chain data\n /// @param _beaconGenesisTimestamp The timestamp of the Beacon chain's genesis.\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _wethAddress,\n address _ssvNetwork,\n address _beaconChainDepositContract,\n address _beaconProofs,\n uint64 _beaconGenesisTimestamp\n )\n InitializableAbstractStrategy(_baseConfig)\n CompoundingValidatorManager(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork,\n _beaconProofs,\n _beaconGenesisTimestamp\n )\n {\n // Make sure nobody owns the implementation contract\n _setGovernor(address(0));\n }\n\n /// @notice Set up initial internal state including\n /// 1. approving the SSVNetwork to transfer SSV tokens from this strategy contract\n /// @param _rewardTokenAddresses Not used so empty array\n /// @param _assets Not used so empty array\n /// @param _pTokens Not used so empty array\n function initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n }\n\n /// @notice Unlike other strategies, this does not deposit assets into the underlying platform.\n /// It just checks the asset is WETH and emits the Deposit event.\n /// To deposit WETH into validators, `registerSsvValidator` and `stakeEth` must be used.\n /// @param _asset Address of the WETH token.\n /// @param _amount Amount of WETH that was transferred to the strategy by the vault.\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n require(_asset == WETH, \"Unsupported asset\");\n require(_amount > 0, \"Must deposit something\");\n\n // Account for the new WETH\n depositedWethAccountedFor += _amount;\n\n emit Deposit(_asset, address(0), _amount);\n }\n\n /// @notice Unlike other strategies, this does not deposit assets into the underlying platform.\n /// It just emits the Deposit event.\n /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used.\n function depositAll() external override onlyVault nonReentrant {\n uint256 wethBalance = IERC20(WETH).balanceOf(address(this));\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\n\n if (newWeth > 0) {\n // Account for the new WETH\n depositedWethAccountedFor = wethBalance;\n\n emit Deposit(WETH, address(0), newWeth);\n }\n }\n\n /// @notice Withdraw ETH and WETH from this strategy contract.\n /// @param _recipient Address to receive withdrawn assets.\n /// @param _asset Address of the WETH token.\n /// @param _amount Amount of WETH to withdraw.\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override nonReentrant {\n require(_asset == WETH, \"Unsupported asset\");\n require(\n msg.sender == vaultAddress || msg.sender == validatorRegistrator,\n \"Caller not Vault or Registrator\"\n );\n\n _withdraw(_recipient, _amount, address(this).balance);\n }\n\n function _withdraw(\n address _recipient,\n uint256 _withdrawAmount,\n uint256 _ethBalance\n ) internal {\n require(_withdrawAmount > 0, \"Must withdraw something\");\n require(_recipient == vaultAddress, \"Recipient not Vault\");\n\n // Convert any ETH from validator partial withdrawals, exits\n // or execution rewards to WETH and do the necessary accounting.\n if (_ethBalance > 0) _convertEthToWeth(_ethBalance);\n\n // Transfer WETH to the recipient and do the necessary accounting.\n _transferWeth(_withdrawAmount, _recipient);\n\n emit Withdrawal(WETH, address(0), _withdrawAmount);\n }\n\n /// @notice Transfer all WETH deposits, ETH from validator withdrawals and ETH from\n /// execution rewards in this strategy to the vault.\n /// This does not withdraw from the validators. That has to be done separately with the\n /// `validatorWithdrawal` operation.\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 ethBalance = address(this).balance;\n uint256 withdrawAmount = IERC20(WETH).balanceOf(address(this)) +\n ethBalance;\n\n if (withdrawAmount > 0) {\n _withdraw(vaultAddress, withdrawAmount, ethBalance);\n }\n }\n\n /// @notice Accounts for all the assets managed by this strategy which includes:\n /// 1. The current WETH in this strategy contract\n /// 2. The last verified ETH balance, total deposits and total validator balances\n /// @param _asset Address of WETH asset.\n /// @return balance Total value in ETH\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == WETH, \"Unsupported asset\");\n\n // Load the last verified balance from the storage\n // and add to the latest WETH balance of this strategy.\n balance =\n lastVerifiedEthBalance +\n IWETH9(WETH).balanceOf(address(this));\n }\n\n /// @notice Returns bool indicating whether asset is supported by the strategy.\n /// @param _asset The address of the WETH token.\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == WETH;\n }\n\n /// @notice Does nothing but needed as this function is abstract on InitializableAbstractStrategy\n /// @dev Use to be used to approve SSV tokens but that is no longer used by the SSV Network.\n function safeApproveAllTokens() public override {}\n\n /**\n * @notice We can accept ETH directly to this contract from anyone as it does not impact our accounting\n * like it did in the legacy NativeStakingStrategy.\n * The new ETH will be accounted for in `checkBalance` after the next snapBalances and verifyBalances txs.\n */\n receive() external payable {}\n\n /***************************************\n Internal functions\n ****************************************/\n\n /// @notice is not supported for this strategy as there is no platform token.\n function setPTokenAddress(address, address) external pure override {\n revert(\"Unsupported function\");\n }\n\n /// @notice is not supported for this strategy as there is no platform token.\n function removePToken(uint256) external pure override {\n revert(\"Unsupported function\");\n }\n\n /// @dev This strategy does not use a platform token like the old Aave and Compound strategies.\n function _abstractSetPToken(address _asset, address) internal override {}\n\n /// @dev Consensus rewards are compounded to the validator's balance instead of being\n /// swept to this strategy contract.\n /// Execution rewards from MEV and tx priority accumulate as ETH in this strategy contract.\n /// Withdrawals from validators also accumulate as ETH in this strategy contract.\n /// It's too complex to separate the rewards from withdrawals so this function is not implemented.\n /// Besides, ETH rewards are not sent to the Dripper any more. The Vault can now regulate\n /// the increase in assets.\n function _collectRewardTokens() internal pure override {\n revert(\"Unsupported function\");\n }\n}\n" + }, + "contracts/strategies/NativeStaking/CompoundingValidatorManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { Governable } from \"../../governance/Governable.sol\";\nimport { IDepositContract } from \"../../interfaces/IDepositContract.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { ISSVNetwork, Cluster } from \"../../interfaces/ISSVNetwork.sol\";\nimport { BeaconRoots } from \"../../beacon/BeaconRoots.sol\";\nimport { PartialWithdrawal } from \"../../beacon/PartialWithdrawal.sol\";\nimport { IBeaconProofs } from \"../../interfaces/IBeaconProofs.sol\";\n\n/**\n * @title Validator lifecycle management contract\n * @notice This contract implements all the required functionality to\n * register, deposit, withdraw, exit and remove validators.\n * @author Origin Protocol Inc\n */\nabstract contract CompoundingValidatorManager is Governable, Pausable {\n using SafeERC20 for IERC20;\n\n /// @dev The amount of ETH in wei that is required for a deposit to a new validator.\n uint256 internal constant DEPOSIT_AMOUNT_WEI = 1 ether;\n /// @dev Validator balances over this amount will eventually become active on the beacon chain.\n /// Due to hysteresis, if the effective balance is 31 ETH, the actual balance\n /// must rise to 32.25 ETH to trigger an effective balance update to 32 ETH.\n /// https://eth2book.info/capella/part2/incentives/balances/#hysteresis\n uint256 internal constant MIN_ACTIVATION_BALANCE_GWEI = 32.25 ether / 1e9;\n /// @dev The maximum number of deposits that are waiting to be verified as processed on the beacon chain.\n uint256 internal constant MAX_DEPOSITS = 32;\n /// @dev The maximum number of validators that can be verified.\n uint256 internal constant MAX_VERIFIED_VALIDATORS = 48;\n /// @dev The default withdrawable epoch value on the Beacon chain.\n /// A value in the far future means the validator is not exiting.\n uint64 internal constant FAR_FUTURE_EPOCH = type(uint64).max;\n /// @dev The number of seconds between each beacon chain slot.\n uint64 internal constant SLOT_DURATION = 12;\n /// @dev The number of slots in each beacon chain epoch.\n uint64 internal constant SLOTS_PER_EPOCH = 32;\n /// @dev Minimum time in seconds to allow snapped balances to be verified.\n /// Set to 35 slots which is 3 slots more than 1 epoch (32 slots). Deposits get processed\n /// once per epoch. This larger than 1 epoch delay should achieve that `snapBalances` sometimes\n /// get called in the middle (or towards the end) of the epoch. Giving the off-chain script\n /// sufficient time after the end of the epoch to prepare the proofs and call `verifyBalances`.\n /// This is considering a malicious actor would keep calling `snapBalances` as frequent as possible\n /// to disturb our operations.\n uint64 public constant SNAP_BALANCES_DELAY = 35 * SLOT_DURATION;\n\n /// @notice The address of the Wrapped ETH (WETH) token contract\n address internal immutable WETH;\n /// @notice The address of the beacon chain deposit contract\n address internal immutable BEACON_CHAIN_DEPOSIT_CONTRACT;\n /// @notice The address of the SSV Network contract used to interface with\n address internal immutable SSV_NETWORK;\n /// @notice Address of the OETH Vault proxy contract\n address internal immutable VAULT_ADDRESS;\n /// @notice Address of the Beacon Proofs contract that verifies beacon chain data\n address public immutable BEACON_PROOFS;\n /// @notice The timestamp of the Beacon chain genesis.\n /// @dev this is different on Testnets like Hoodi so is set at deployment time.\n uint64 internal immutable BEACON_GENESIS_TIMESTAMP;\n\n /// @notice Address of the registrator - allowed to register, withdraw, exit and remove validators\n address public validatorRegistrator;\n\n /// @notice Deposit data for new compounding validators.\n /// @dev A `VERIFIED` deposit can mean 3 separate things:\n /// - a deposit has been processed by the beacon chain and shall be included in the\n /// balance of the next verifyBalances call\n /// - a deposit has been done to a slashed validator and has probably been recovered\n /// back to this strategy. Probably because we can not know for certain. This contract\n /// only detects when the validator has passed its withdrawal epoch. It is close to impossible\n /// to prove with Merkle Proofs that the postponed deposit this contract is responsible for\n /// creating is not present anymore in BeaconChain.state.pending_deposits. This in effect\n /// means that there might be a period where this contract thinks the deposit has been already\n /// returned as ETH balance before it happens. This will result in some days (or weeks)\n /// -> depending on the size of deposit queue of showing a deficit when calling `checkBalance`.\n /// As this only offsets the yield and doesn't cause a critical double-counting we are not addressing\n /// this issue.\n /// - A deposit has been done to the validator, but our deposit has been front run by a malicious\n /// actor. Funds in the deposit this contract makes are not recoverable.\n enum DepositStatus {\n UNKNOWN, // default value\n PENDING, // deposit is pending and waiting to be verified\n VERIFIED // deposit has been verified\n }\n\n /// @param pubKeyHash Hash of validator's public key using the Beacon Chain's format\n /// @param amountGwei Amount of ETH in gwei that has been deposited to the beacon chain deposit contract\n /// @param slot The beacon chain slot number when the deposit has been made\n /// @param depositIndex The index of the deposit in the list of active deposits\n /// @param status The status of the deposit, either UNKNOWN, PENDING or VERIFIED\n struct DepositData {\n bytes32 pubKeyHash;\n uint64 amountGwei;\n uint64 slot;\n uint32 depositIndex;\n DepositStatus status;\n }\n /// @notice Restricts to only one deposit to an unverified validator at a time.\n /// This is to limit front-running attacks of deposits to the beacon chain contract.\n ///\n /// @dev The value is set to true when a deposit to a new validator has been done that has\n /// not yet be verified.\n bool public firstDeposit;\n /// @notice Mapping of the pending deposit roots to the deposit data\n mapping(bytes32 => DepositData) public deposits;\n /// @notice List of strategy deposit IDs to a validator.\n /// The ID is the merkle root of the pending deposit data which is unique for each validator, amount and block.\n /// Duplicate pending deposit roots are prevented so can be used as an identifier to each strategy deposit.\n /// The list can be for deposits waiting to be verified as processed on the beacon chain,\n /// or deposits that have been verified to an exiting validator and is now waiting for the\n /// validator's balance to be swept.\n /// The list may not be ordered by time of deposit.\n /// Removed deposits will move the last deposit to the removed index.\n bytes32[] public depositList;\n\n enum ValidatorState {\n NON_REGISTERED, // validator is not registered on the SSV network\n REGISTERED, // validator is registered on the SSV network\n STAKED, // validator has funds staked\n VERIFIED, // validator has been verified to exist on the beacon chain\n ACTIVE, // The validator balance is at least 32 ETH. The validator may not yet be active on the beacon chain.\n EXITING, // The validator has been requested to exit\n EXITED, // The validator has been verified to have a zero balance\n REMOVED, // validator has funds withdrawn to this strategy contract and is removed from the SSV\n INVALID // The validator has been front-run and the withdrawal address is not this strategy\n }\n\n // Validator data\n struct ValidatorData {\n ValidatorState state; // The state of the validator known to this contract\n uint40 index; // The index of the validator on the beacon chain\n }\n /// @notice List of validator public key hashes that have been verified to exist on the beacon chain.\n /// These have had a deposit processed and the validator's balance increased.\n /// Validators will be removed from this list when its verified they have a zero balance.\n bytes32[] public verifiedValidators;\n /// @notice Mapping of the hash of the validator's public key to the validator state and index.\n /// Uses the Beacon chain hashing for BLSPubkey which is sha256(abi.encodePacked(validator.pubkey, bytes16(0)))\n mapping(bytes32 => ValidatorData) public validator;\n\n /// @param blockRoot Beacon chain block root of the snapshot\n /// @param timestamp Timestamp of the snapshot\n /// @param ethBalance The balance of ETH in the strategy contract at the snapshot\n struct Balances {\n bytes32 blockRoot;\n uint64 timestamp;\n uint128 ethBalance;\n }\n /// @notice Mapping of the block root to the balances at that slot\n Balances public snappedBalance;\n /// @notice The last verified ETH balance of the strategy\n uint256 public lastVerifiedEthBalance;\n\n /// @dev This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately\n /// deposit it to an underlying platform. Rather a special privilege account stakes it to the validators.\n /// For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been\n /// deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track\n /// of WETH that has already been accounted for.\n /// This value represents the amount of WETH balance of this contract that has already been accounted for by the\n /// deposit events.\n /// It is important to note that this variable is not concerned with WETH that is a result of full/partial\n /// withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to\n /// be staked.\n uint256 public depositedWethAccountedFor;\n\n // For future use\n uint256[41] private __gap;\n\n event RegistratorChanged(address indexed newAddress);\n event FirstDepositReset();\n event SSVValidatorRegistered(\n bytes32 indexed pubKeyHash,\n uint64[] operatorIds\n );\n event SSVValidatorRemoved(bytes32 indexed pubKeyHash, uint64[] operatorIds);\n event ETHStaked(\n bytes32 indexed pubKeyHash,\n bytes32 indexed pendingDepositRoot,\n bytes pubKey,\n uint256 amountWei\n );\n event ValidatorVerified(\n bytes32 indexed pubKeyHash,\n uint40 indexed validatorIndex\n );\n event ValidatorInvalid(bytes32 indexed pubKeyHash);\n event DepositVerified(\n bytes32 indexed pendingDepositRoot,\n uint256 amountWei\n );\n event ValidatorWithdraw(bytes32 indexed pubKeyHash, uint256 amountWei);\n event BalancesSnapped(bytes32 indexed blockRoot, uint256 ethBalance);\n event BalancesVerified(\n uint64 indexed timestamp,\n uint256 totalDepositsWei,\n uint256 totalValidatorBalance,\n uint256 ethBalance\n );\n\n /// @dev Throws if called by any account other than the Registrator\n modifier onlyRegistrator() {\n _onlyRegistrator();\n _;\n }\n\n /// @dev internal function used to reduce contract size\n function _onlyRegistrator() internal view {\n require(msg.sender == validatorRegistrator, \"Not Registrator\");\n }\n\n /// @dev Throws if called by any account other than the Registrator or Governor\n modifier onlyRegistratorOrGovernor() {\n require(\n msg.sender == validatorRegistrator || isGovernor(),\n \"Not Registrator or Governor\"\n );\n _;\n }\n\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _vaultAddress Address of the Vault\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _beaconProofs Address of the Beacon Proofs contract that verifies beacon chain data\n /// @param _beaconGenesisTimestamp The timestamp of the Beacon chain's genesis.\n constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork,\n address _beaconProofs,\n uint64 _beaconGenesisTimestamp\n ) {\n WETH = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK = _ssvNetwork;\n VAULT_ADDRESS = _vaultAddress;\n BEACON_PROOFS = _beaconProofs;\n BEACON_GENESIS_TIMESTAMP = _beaconGenesisTimestamp;\n\n require(\n block.timestamp > _beaconGenesisTimestamp,\n \"Invalid genesis timestamp\"\n );\n }\n\n /**\n *\n * Admin Functions\n *\n */\n\n /// @notice Set the address of the registrator which can register, exit and remove validators\n function setRegistrator(address _address) external onlyGovernor {\n validatorRegistrator = _address;\n emit RegistratorChanged(_address);\n }\n\n /// @notice Reset the `firstDeposit` flag to false so deposits to unverified validators can be made again.\n function resetFirstDeposit() external onlyGovernor {\n require(firstDeposit, \"No first deposit\");\n\n firstDeposit = false;\n\n emit FirstDepositReset();\n }\n\n function pause() external onlyRegistratorOrGovernor {\n _pause();\n }\n\n function unPause() external onlyGovernor {\n _unpause();\n }\n\n /**\n *\n * Validator Management\n *\n */\n\n /// @notice Registers a single validator in a SSV Cluster.\n /// Only the Registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param sharesData The shares data for the validator\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n // slither-disable-start reentrancy-no-eth\n function registerSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n bytes calldata sharesData,\n Cluster calldata cluster\n ) external payable onlyRegistrator whenNotPaused {\n // Hash the public key using the Beacon Chain's format\n bytes32 pubKeyHash = _hashPubKey(publicKey);\n // Check each public key has not already been used\n require(\n validator[pubKeyHash].state == ValidatorState.NON_REGISTERED,\n \"Validator already registered\"\n );\n\n // Store the validator state as registered\n validator[pubKeyHash].state = ValidatorState.REGISTERED;\n\n ISSVNetwork(SSV_NETWORK).registerValidator{ value: msg.value }(\n publicKey,\n operatorIds,\n sharesData,\n cluster\n );\n\n emit SSVValidatorRegistered(pubKeyHash, operatorIds);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n struct ValidatorStakeData {\n bytes pubkey;\n bytes signature;\n bytes32 depositDataRoot;\n }\n\n /// @notice Stakes WETH in this strategy to a compounding validator.\n /// The first deposit to a new validator, the amount must be 1 ETH.\n /// Another deposit of at least 31 ETH is required for the validator to be activated.\n /// This second deposit has to be done after the validator has been verified.\n /// Does not convert any ETH sitting in this strategy to WETH.\n /// There can not be two deposits to the same validator in the same block for the same amount.\n /// Function is pausable so in case a run-away Registrator can be prevented from continuing\n /// to deposit funds to slashed or undesired validators.\n /// @param validatorStakeData validator data needed to stake.\n /// The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot.\n /// Only the registrator can call this function.\n /// @param depositAmountGwei The amount of WETH to stake to the validator in Gwei.\n // slither-disable-start reentrancy-eth,reentrancy-no-eth\n function stakeEth(\n ValidatorStakeData calldata validatorStakeData,\n uint64 depositAmountGwei\n ) external onlyRegistrator whenNotPaused {\n uint256 depositAmountWei = uint256(depositAmountGwei) * 1 gwei;\n // Check there is enough WETH from the deposits sitting in this strategy contract\n // There could be ETH from withdrawals but we'll ignore that. If it's really needed\n // the ETH can be withdrawn and then deposited back to the strategy.\n require(\n depositAmountWei <= IWETH9(WETH).balanceOf(address(this)),\n \"Insufficient WETH\"\n );\n require(depositList.length < MAX_DEPOSITS, \"Max deposits\");\n\n // Convert required ETH from WETH and do the necessary accounting\n _convertWethToEth(depositAmountWei);\n\n // Hash the public key using the Beacon Chain's hashing for BLSPubkey\n bytes32 pubKeyHash = _hashPubKey(validatorStakeData.pubkey);\n ValidatorState currentState = validator[pubKeyHash].state;\n // Can only stake to a validator that has been registered, verified or active.\n // Can not stake to a validator that has been staked but not yet verified.\n require(\n (currentState == ValidatorState.REGISTERED ||\n currentState == ValidatorState.VERIFIED ||\n currentState == ValidatorState.ACTIVE),\n \"Not registered or verified\"\n );\n require(depositAmountWei >= 1 ether, \"Deposit too small\");\n if (currentState == ValidatorState.REGISTERED) {\n // Can only have one pending deposit to an unverified validator at a time.\n // This is to limit front-running deposit attacks to a single deposit.\n // The exiting deposit needs to be verified before another deposit can be made.\n // If there was a front-running attack, the validator needs to be verified as invalid\n // and the Governor calls `resetFirstDeposit` to set `firstDeposit` to false.\n require(!firstDeposit, \"Existing first deposit\");\n // Limits the amount of ETH that can be at risk from a front-running deposit attack.\n require(\n depositAmountWei == DEPOSIT_AMOUNT_WEI,\n \"Invalid first deposit amount\"\n );\n // Limits the number of validator balance proofs to verifyBalances\n require(\n verifiedValidators.length + 1 <= MAX_VERIFIED_VALIDATORS,\n \"Max validators\"\n );\n\n // Flag a deposit to an unverified validator so no other deposits can be made\n // to an unverified validator.\n firstDeposit = true;\n validator[pubKeyHash].state = ValidatorState.STAKED;\n }\n\n /* 0x02 to indicate that withdrawal credentials are for a compounding validator\n * that was introduced with the Pectra upgrade.\n * bytes11(0) to fill up the required zeros\n * remaining bytes20 are for the address\n */\n bytes memory withdrawalCredentials = abi.encodePacked(\n bytes1(0x02),\n bytes11(0),\n address(this)\n );\n\n /// After the Pectra upgrade the validators have a new restriction when proposing\n /// blocks. The timestamps are at strict intervals of 12 seconds from the genesis block\n /// forward. Each slot is created at strict 12 second intervals and those slots can\n /// either have blocks attached to them or not. This way using the block.timestamp\n /// the slot number can easily be calculated.\n uint64 depositSlot = (SafeCast.toUint64(block.timestamp) -\n BEACON_GENESIS_TIMESTAMP) / SLOT_DURATION;\n\n // Calculate the merkle root of the beacon chain pending deposit data.\n // This is used as the unique ID of the deposit.\n bytes32 pendingDepositRoot = IBeaconProofs(BEACON_PROOFS)\n .merkleizePendingDeposit(\n pubKeyHash,\n withdrawalCredentials,\n depositAmountGwei,\n validatorStakeData.signature,\n depositSlot\n );\n require(\n deposits[pendingDepositRoot].status == DepositStatus.UNKNOWN,\n \"Duplicate deposit\"\n );\n\n // Store the deposit data for verifyDeposit and verifyBalances\n deposits[pendingDepositRoot] = DepositData({\n pubKeyHash: pubKeyHash,\n amountGwei: depositAmountGwei,\n slot: depositSlot,\n depositIndex: SafeCast.toUint32(depositList.length),\n status: DepositStatus.PENDING\n });\n depositList.push(pendingDepositRoot);\n\n // Deposit to the Beacon Chain deposit contract.\n // This will create a deposit in the beacon chain's pending deposit queue.\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\n value: depositAmountWei\n }(\n validatorStakeData.pubkey,\n withdrawalCredentials,\n validatorStakeData.signature,\n validatorStakeData.depositDataRoot\n );\n\n emit ETHStaked(\n pubKeyHash,\n pendingDepositRoot,\n validatorStakeData.pubkey,\n depositAmountWei\n );\n }\n\n // slither-disable-end reentrancy-eth,reentrancy-no-eth\n\n /// @notice Request a full or partial withdrawal from a validator.\n /// A zero amount will trigger a full withdrawal.\n /// If the remaining balance is < 32 ETH then only the amount in excess of 32 ETH will be withdrawn.\n /// Only the Registrator can call this function.\n /// 1 wei of value should be sent with the tx to pay for the withdrawal request fee.\n /// If no value sent, 1 wei will be taken from the strategy's ETH balance if it has any.\n /// If no ETH balance, the tx will revert.\n /// @param publicKey The public key of the validator\n /// @param amountGwei The amount of ETH to be withdrawn from the validator in Gwei.\n /// A zero amount will trigger a full withdrawal.\n // slither-disable-start reentrancy-no-eth\n function validatorWithdrawal(bytes calldata publicKey, uint64 amountGwei)\n external\n payable\n onlyRegistrator\n {\n // Hash the public key using the Beacon Chain's format\n bytes32 pubKeyHash = _hashPubKey(publicKey);\n ValidatorData memory validatorDataMem = validator[pubKeyHash];\n // Validator full withdrawal could be denied due to multiple reasons:\n // - the validator has not been activated or active long enough\n // (current_epoch < activation_epoch + SHARD_COMMITTEE_PERIOD)\n // - the validator has pending balance to withdraw from a previous partial withdrawal request\n //\n // Meaning that the on-chain to beacon chain full withdrawal request could fail. Instead\n // of adding complexity of verifying if a validator is eligible for a full exit, we allow\n // multiple full withdrawal requests per validator.\n require(\n validatorDataMem.state == ValidatorState.ACTIVE ||\n validatorDataMem.state == ValidatorState.EXITING,\n \"Validator not active/exiting\"\n );\n\n // If a full withdrawal (validator exit)\n if (amountGwei == 0) {\n // For each staking strategy's deposits\n uint256 depositsCount = depositList.length;\n for (uint256 i = 0; i < depositsCount; ++i) {\n bytes32 pendingDepositRoot = depositList[i];\n // Check there is no pending deposits to the exiting validator\n require(\n pubKeyHash != deposits[pendingDepositRoot].pubKeyHash,\n \"Pending deposit\"\n );\n }\n\n // Store the validator state as exiting so no more deposits can be made to it.\n // This may already be EXITING if the previous exit request failed. eg the validator\n // was not active long enough.\n validator[pubKeyHash].state = ValidatorState.EXITING;\n }\n\n // Do not remove from the list of verified validators.\n // This is done in the verifyBalances function once the validator's balance has been verified to be zero.\n // The validator state will be set to EXITED in the verifyBalances function.\n\n PartialWithdrawal.request(publicKey, amountGwei);\n\n emit ValidatorWithdraw(pubKeyHash, uint256(amountGwei) * 1 gwei);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Remove the validator from the SSV Cluster after:\n /// - the validator has been exited from `validatorWithdrawal` or slashed\n /// - the validator has incorrectly registered and can not be staked to\n /// - the initial deposit was front-run and the withdrawal address is not this strategy's address.\n /// Make sure `validatorWithdrawal` is called with a zero amount and the validator has exited the Beacon chain.\n /// If removed before the validator has exited the beacon chain will result in the validator being slashed.\n /// Only the registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n // slither-disable-start reentrancy-no-eth\n function removeSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator {\n // Hash the public key using the Beacon Chain's format\n bytes32 pubKeyHash = _hashPubKey(publicKey);\n ValidatorState currentState = validator[pubKeyHash].state;\n // Can remove SSV validators that were incorrectly registered and can not be deposited to.\n require(\n currentState == ValidatorState.REGISTERED ||\n currentState == ValidatorState.EXITED ||\n currentState == ValidatorState.INVALID,\n \"Validator not regd or exited\"\n );\n\n validator[pubKeyHash].state = ValidatorState.REMOVED;\n\n ISSVNetwork(SSV_NETWORK).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n\n emit SSVValidatorRemoved(pubKeyHash, operatorIds);\n }\n\n /**\n *\n * SSV Management\n *\n */\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Migrate the SSV cluster to use ETH for payment instead of SSV tokens.\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n function migrateClusterToETH(\n uint64[] memory operatorIds,\n Cluster memory cluster\n ) external payable onlyGovernor {\n ISSVNetwork(SSV_NETWORK).migrateClusterToETH{ value: msg.value }(\n operatorIds,\n cluster\n );\n\n // The SSV Network emits\n // ClusterMigratedToETH(msg.sender, operatorIds, msg.value, ssvClusterBalance, effectiveBalance, cluster)\n }\n\n /**\n *\n * Beacon Chain Proofs\n *\n */\n\n /// @notice Verifies a validator's index to its public key.\n /// Adds to the list of verified validators if the validator's withdrawal address is this strategy's address.\n /// Marks the validator as invalid and removes the deposit if the withdrawal address is not this strategy's address.\n /// @param nextBlockTimestamp The timestamp of the execution layer block after the beacon chain slot\n /// we are verifying.\n /// The next one is needed as the Beacon Oracle returns the parent beacon block root for a block timestamp,\n /// which is the beacon block root of the previous block.\n /// @param validatorIndex The index of the validator on the beacon chain.\n /// @param pubKeyHash The hash of the validator's public key using the Beacon Chain's format\n /// @param withdrawalCredentials contain the validator type and withdrawal address. These can be incorrect and/or\n /// malformed. In case of incorrect withdrawalCredentials the validator deposit has been front run\n /// @param validatorPubKeyProof The merkle proof for the validator public key to the beacon block root.\n /// This is 53 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n /// BeaconBlock.state.validators[validatorIndex].pubkey\n function verifyValidator(\n uint64 nextBlockTimestamp,\n uint40 validatorIndex,\n bytes32 pubKeyHash,\n bytes32 withdrawalCredentials,\n bytes calldata validatorPubKeyProof\n ) external {\n require(\n validator[pubKeyHash].state == ValidatorState.STAKED,\n \"Validator not staked\"\n );\n\n // Get the beacon block root of the slot we are verifying the validator in.\n // The parent beacon block root of the next block is the beacon block root of the slot we are verifying.\n bytes32 blockRoot = BeaconRoots.parentBlockRoot(nextBlockTimestamp);\n\n // Verify the validator index is for the validator with the given public key.\n // Also verify the validator's withdrawal credentials\n IBeaconProofs(BEACON_PROOFS).verifyValidator(\n blockRoot,\n pubKeyHash,\n validatorPubKeyProof,\n validatorIndex,\n withdrawalCredentials\n );\n\n // Store the validator state as verified\n validator[pubKeyHash] = ValidatorData({\n state: ValidatorState.VERIFIED,\n index: validatorIndex\n });\n\n bytes32 expectedWithdrawalCredentials = bytes32(\n abi.encodePacked(bytes1(0x02), bytes11(0), address(this))\n );\n\n // If the initial deposit was front-run and the withdrawal address is not this strategy\n // or the validator type is not a compounding validator (0x02)\n if (expectedWithdrawalCredentials != withdrawalCredentials) {\n // override the validator state\n validator[pubKeyHash].state = ValidatorState.INVALID;\n\n // Find and remove the deposit as the funds can not be recovered\n uint256 depositCount = depositList.length;\n for (uint256 i = 0; i < depositCount; i++) {\n DepositData memory deposit = deposits[depositList[i]];\n if (deposit.pubKeyHash == pubKeyHash) {\n // next verifyBalances will correctly account for the loss of a front-run\n // deposit. Doing it here accounts for the loss as soon as possible\n lastVerifiedEthBalance -= Math.min(\n lastVerifiedEthBalance,\n uint256(deposit.amountGwei) * 1 gwei\n );\n _removeDeposit(depositList[i], deposit);\n break;\n }\n }\n\n // Leave the `firstDeposit` flag as true so no more deposits to unverified validators can be made.\n // The Governor has to reset the `firstDeposit` to false before another deposit to\n // an unverified validator can be made.\n // The Governor can set a new `validatorRegistrator` if they suspect it has been compromised.\n\n emit ValidatorInvalid(pubKeyHash);\n return;\n }\n\n // Add the new validator to the list of verified validators\n verifiedValidators.push(pubKeyHash);\n\n // Reset the firstDeposit flag as the first deposit to an unverified validator has been verified.\n firstDeposit = false;\n\n emit ValidatorVerified(pubKeyHash, validatorIndex);\n }\n\n struct FirstPendingDepositSlotProofData {\n uint64 slot;\n bytes proof;\n }\n\n struct StrategyValidatorProofData {\n uint64 withdrawableEpoch;\n bytes withdrawableEpochProof;\n }\n\n /// @notice Verifies a deposit on the execution layer has been processed by the beacon chain.\n /// This means the accounting of the strategy's ETH moves from a pending deposit to a validator balance.\n ///\n /// Important: this function has a limitation where `depositProcessedSlot` that is passed by the off-chain\n /// verifier requires a slot immediately after it to propose a block otherwise the `BeaconRoots.parentBlockRoot`\n /// will fail. This shouldn't be a problem, since by the current behaviour of beacon chain only 1%-3% slots\n /// don't propose a block.\n /// @param pendingDepositRoot The unique identifier of the deposit emitted in `ETHStaked` from\n /// the `stakeEth` function.\n /// @param depositProcessedSlot Any slot on or after the strategy's deposit was processed on the beacon chain.\n /// Can not be a slot with pending deposits with the same slot as the deposit being verified.\n /// Can not be a slot before a missed slot as the Beacon Root contract will have the parent block root\n /// set for the next block timestamp in 12 seconds time.\n /// @param firstPendingDeposit a `FirstPendingDepositSlotProofData` struct containing:\n /// - slot: The beacon chain slot of the first deposit in the beacon chain's deposit queue.\n /// Can be any non-zero value if the deposit queue is empty.\n /// - proof: The merkle proof of the first pending deposit's slot to the beacon block root.\n /// Can be either:\n /// * 40 witness hashes for BeaconBlock.state.PendingDeposits[0].slot when the deposit queue is not empty.\n /// * 37 witness hashes for BeaconBlock.state.PendingDeposits[0] when the deposit queue is empty.\n /// The 32 byte witness hashes are concatenated together starting from the leaf node.\n /// @param strategyValidatorData a `StrategyValidatorProofData` struct containing:\n /// - withdrawableEpoch: The withdrawable epoch of the validator the strategy is depositing to.\n /// - withdrawableEpochProof: The merkle proof for the withdrawable epoch of the validator the strategy\n /// is depositing to, to the beacon block root.\n /// This is 53 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n // slither-disable-start reentrancy-no-eth\n function verifyDeposit(\n bytes32 pendingDepositRoot,\n uint64 depositProcessedSlot,\n FirstPendingDepositSlotProofData calldata firstPendingDeposit,\n StrategyValidatorProofData calldata strategyValidatorData\n ) external {\n // Load into memory the previously saved deposit data\n DepositData memory deposit = deposits[pendingDepositRoot];\n ValidatorData memory strategyValidator = validator[deposit.pubKeyHash];\n require(deposit.status == DepositStatus.PENDING, \"Deposit not pending\");\n require(firstPendingDeposit.slot != 0, \"Zero 1st pending deposit slot\");\n\n // We should allow the verification of deposits for validators that have been marked as exiting\n // to cover this situation:\n // - there are 2 pending deposits\n // - beacon chain has slashed the validator\n // - when verifyDeposit is called for the first deposit it sets the Validator state to EXITING\n // - verifyDeposit should allow a secondary call for the other deposit to a slashed validator\n require(\n strategyValidator.state == ValidatorState.VERIFIED ||\n strategyValidator.state == ValidatorState.ACTIVE ||\n strategyValidator.state == ValidatorState.EXITING,\n \"Not verified/active/exiting\"\n );\n // The verification slot must be after the deposit's slot.\n // This is needed for when the deposit queue is empty.\n require(deposit.slot < depositProcessedSlot, \"Slot not after deposit\");\n\n uint64 snapTimestamp = snappedBalance.timestamp;\n\n // This check prevents an accounting error that can happen if:\n // - snapBalances are snapped at the time of T\n // - deposit is processed on the beacon chain after time T and before verifyBalances()\n // - verifyDeposit is called before verifyBalances which removes a deposit from depositList\n // and deposit balance from totalDepositsWei\n // - verifyBalances is called under-reporting the strategy's balance\n require(\n (_calcNextBlockTimestamp(depositProcessedSlot) <= snapTimestamp) ||\n snapTimestamp == 0,\n \"Deposit after balance snapshot\"\n );\n\n // Get the parent beacon block root of the next block which is the block root of the deposit verification slot.\n // This will revert if the slot after the verification slot was missed.\n bytes32 depositBlockRoot = BeaconRoots.parentBlockRoot(\n _calcNextBlockTimestamp(depositProcessedSlot)\n );\n\n // Verify the slot of the first pending deposit matches the beacon chain\n bool isDepositQueueEmpty = IBeaconProofs(BEACON_PROOFS)\n .verifyFirstPendingDeposit(\n depositBlockRoot,\n firstPendingDeposit.slot,\n firstPendingDeposit.proof\n );\n\n // Verify the withdrawableEpoch on the validator of the strategy's deposit\n IBeaconProofs(BEACON_PROOFS).verifyValidatorWithdrawable(\n depositBlockRoot,\n strategyValidator.index,\n strategyValidatorData.withdrawableEpoch,\n strategyValidatorData.withdrawableEpochProof\n );\n\n uint64 firstPendingDepositEpoch = firstPendingDeposit.slot /\n SLOTS_PER_EPOCH;\n\n // If deposit queue is empty all deposits have certainly been processed. If not\n // a validator can either be not exiting and no further checks are required.\n // Or a validator is exiting then this function needs to make sure that the\n // pending deposit to an exited validator has certainly been processed. The\n // slot/epoch of first pending deposit is the one that contains the transaction\n // where the deposit to the ETH Deposit Contract has been made.\n //\n // Once the firstPendingDepositEpoch becomes greater than the withdrawableEpoch of\n // the slashed validator then the deposit has certainly been processed. When the beacon\n // chain reaches the withdrawableEpoch of the validator the deposit will no longer be\n // postponed. And any new deposits created (and present in the deposit queue)\n // will have an equal or larger withdrawableEpoch.\n require(\n strategyValidatorData.withdrawableEpoch == FAR_FUTURE_EPOCH ||\n strategyValidatorData.withdrawableEpoch <=\n firstPendingDepositEpoch ||\n isDepositQueueEmpty,\n \"Exit Deposit likely not proc.\"\n );\n\n // solhint-disable max-line-length\n // Check the deposit slot is before the first pending deposit's slot on the beacon chain.\n // If this is not true then we can't guarantee the deposit has been processed by the beacon chain.\n // The deposit's slot can not be the same slot as the first pending deposit as there could be\n // many deposits in the same block, hence have the same pending deposit slot.\n // If the deposit queue is empty then our deposit must have been processed on the beacon chain.\n // The deposit slot can be zero for validators consolidating to a compounding validator or 0x01 validator\n // being promoted to a compounding one. Reference:\n // - [switch_to_compounding_validator](https://ethereum.github.io/consensus-specs/specs/electra/beacon-chain/#new-switch_to_compounding_validator\n // - [queue_excess_active_balance](https://ethereum.github.io/consensus-specs/specs/electra/beacon-chain/#new-queue_excess_active_balance)\n // - [process_consolidation_request](https://ethereum.github.io/consensus-specs/specs/electra/beacon-chain/#new-process_consolidation_request)\n // We can not guarantee that the deposit has been processed in that case.\n // solhint-enable max-line-length\n require(\n deposit.slot < firstPendingDeposit.slot || isDepositQueueEmpty,\n \"Deposit likely not processed\"\n );\n\n // Remove the deposit now it has been verified as processed on the beacon chain.\n _removeDeposit(pendingDepositRoot, deposit);\n\n emit DepositVerified(\n pendingDepositRoot,\n uint256(deposit.amountGwei) * 1 gwei\n );\n }\n\n function _removeDeposit(\n bytes32 pendingDepositRoot,\n DepositData memory deposit\n ) internal {\n // After verifying the proof, update the contract storage\n deposits[pendingDepositRoot].status = DepositStatus.VERIFIED;\n // Move the last deposit to the index of the verified deposit\n bytes32 lastDeposit = depositList[depositList.length - 1];\n depositList[deposit.depositIndex] = lastDeposit;\n deposits[lastDeposit].depositIndex = deposit.depositIndex;\n // Delete the last deposit from the list\n depositList.pop();\n }\n\n /// @dev Calculates the timestamp of the next execution block from the given slot.\n /// @param slot The beacon chain slot number used for merkle proof verification.\n function _calcNextBlockTimestamp(uint64 slot)\n internal\n view\n returns (uint64)\n {\n // Calculate the next block timestamp from the slot.\n return SLOT_DURATION * slot + BEACON_GENESIS_TIMESTAMP + SLOT_DURATION;\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Stores the current ETH balance at the current block and beacon block root\n /// of the slot that is associated with the previous block.\n ///\n /// When snapping / verifying balance it is of a high importance that there is no\n /// miss-match in respect to ETH that is held by the contract and balances that are\n /// verified on the validators.\n ///\n /// First some context on the beacon-chain block building behaviour. Relevant parts of\n /// constructing a block on the beacon chain consist of:\n /// - process_withdrawals: ETH is deducted from the validator's balance\n /// - process_execution_payload: immediately after the previous step executing all the\n /// transactions\n /// - apply the withdrawals: adding ETH to the recipient which is the withdrawal address\n /// contained in the withdrawal credentials of the exited validators\n ///\n /// That means that balance increases which are part of the post-block execution state are\n /// done within the block, but the transaction that are contained within that block can not\n /// see / interact with the balance from the exited validators. Only transactions in the\n /// next block can do that.\n ///\n /// When snap balances is performed the state of the chain is snapped across 2 separate\n /// chain states:\n /// - ETH balance of the contract is recorded on block X -> and corresponding slot Y\n /// - beacon chain block root is recorded of block X - 1 -> and corresponding slot Y - 1\n /// given there were no missed slots. It could also be Y - 2, Y - 3 depending on how\n /// many slots have not managed to propose a block. For the sake of simplicity this slot\n /// will be referred to as Y - 1 as it makes no difference in the argument\n ///\n /// Given these 2 separate chain states it is paramount that verify balances can not experience\n /// miss-counting ETH or much more dangerous double counting of the ETH.\n ///\n /// When verifyBalances is called it is performed on the current block Z where Z > X. Verify\n /// balances adds up all the ETH (omitting WETH) controlled by this contract:\n /// - ETH balance in the contract on block X\n /// - ETH balance in Deposits on block Z that haven't been yet processed in slot Y - 1\n /// - ETH balance in validators that are active in slot Y - 1\n /// - skips the ETH balance in validators that have withdrawn in slot Y - 1 (or sooner)\n /// and have their balance visible to transactions in slot Y and corresponding block X\n /// (or sooner)\n ///\n /// Lets verify the correctness of ETH accounting given the above described behaviour.\n ///\n /// *ETH balance in the contract on block X*\n ///\n /// This is an ETH balance of the contract on a non current X block. Any ETH leaving the\n /// contract as a result of a withdrawal subtracts from the ETH accounted for on block X\n /// if `verifyBalances` has already been called. It also invalidates a `snapBalances` in\n /// case `verifyBalances` has not been called yet. Not performing this would result in not\n /// accounting for the withdrawn ETH that has happened anywhere in the block interval [X + 1, Z].\n ///\n /// Similarly to withdrawals any `stakeEth` deposits to the deposit contract adds to the ETH\n /// accounted for since the last `verifyBalances` has been called. And it invalidates the\n /// `snapBalances` in case `verifyBalances` hasn't been yet called. Not performing this\n /// would result in double counting the `stakedEth` since it would be present once in the\n /// snapped contract balance and the second time in deposit storage variables.\n ///\n /// This behaviour is correct.\n ///\n /// *ETH balance in Deposits on block Z that haven't been yet processed in slot Y - 1*\n ///\n /// The contract sums up all the ETH that has been deposited to the Beacon chain deposit\n /// contract at block Z. The execution layer doesn't have direct access to the state of\n /// deposits on the beacon chain. And if it is to sum up all the ETH that is marked to be\n /// deposited it needs to be sure to not double count ETH that is in deposits (storage vars)\n /// and could also be part of the validator balances. It does that by verifying that at\n /// slot Y - 1 none of the deposits visible on block Z have been processed. Meaning since\n /// the last snap till now all are still in queue. Which ensures they can not be part of\n /// the validator balances in later steps.\n ///\n /// This behaviour is correct.\n ///\n /// *ETH balance in validators that are active in slot Y - 1*\n ///\n /// The contract is verifying none of the deposits on Y - 1 slot have been processed and\n /// for that reason it checks the validator balances in the same slot. Ensuring accounting\n /// correctness.\n ///\n /// This behaviour is correct.\n ///\n /// *The withdrawn validators*\n ///\n /// The withdrawn validators could have their balances deducted in any slot before slot\n /// Y - 1 and the execution layer sees the balance increase in the subsequent slot. Lets\n /// look at the \"worst case scenario\" where the validator withdrawal is processed in the\n /// slot Y - 1 (snapped slot) and see their balance increase (in execution layer) in slot\n /// Y -> block X. The ETH balance on the contract is snapped at block X meaning that\n /// even if the validator exits at the latest possible time it is paramount that the ETH\n /// balance on the execution layer is recorded in the next block. Correctly accounting\n /// for the withdrawn ETH.\n ///\n /// Worth mentioning if the validator exit is processed by the slot Y and balance increase\n /// seen on the execution layer on block X + 1 the withdrawal is ignored by both the\n /// validator balance verification as well as execution layer contract balance snap.\n ///\n /// This behaviour is correct.\n ///\n /// The validator balances on the beacon chain can then be proved with `verifyBalances`.\n function snapBalances() external onlyRegistrator {\n uint64 currentTimestamp = SafeCast.toUint64(block.timestamp);\n require(\n snappedBalance.timestamp + SNAP_BALANCES_DELAY < currentTimestamp,\n \"Snap too soon\"\n );\n\n bytes32 blockRoot = BeaconRoots.parentBlockRoot(currentTimestamp);\n // Get the current ETH balance\n uint256 ethBalance = address(this).balance;\n\n // Store the snapped balance\n snappedBalance = Balances({\n blockRoot: blockRoot,\n timestamp: currentTimestamp,\n ethBalance: SafeCast.toUint128(ethBalance)\n });\n\n emit BalancesSnapped(blockRoot, ethBalance);\n }\n\n // A struct is used to avoid stack too deep errors\n struct BalanceProofs {\n // BeaconBlock.state.balances\n bytes32 balancesContainerRoot;\n bytes balancesContainerProof;\n // BeaconBlock.state.balances[validatorIndex]\n bytes32[] validatorBalanceLeaves;\n bytes[] validatorBalanceProofs;\n }\n\n struct PendingDepositProofs {\n bytes32 pendingDepositContainerRoot;\n bytes pendingDepositContainerProof;\n uint32[] pendingDepositIndexes;\n bytes[] pendingDepositProofs;\n }\n\n /// @notice Verifies the balances of all active validators on the beacon chain\n /// and checks each of the strategy's deposits are still to be processed by the beacon chain.\n /// @param balanceProofs a `BalanceProofs` struct containing the following:\n /// - balancesContainerRoot: The merkle root of the balances container\n /// - balancesContainerProof: The merkle proof for the balances container to the beacon block root.\n /// This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n /// - validatorBalanceLeaves: Array of leaf nodes containing the validator balance with three other balances.\n /// - validatorBalanceProofs: Array of merkle proofs for the validator balance to the Balances container root.\n /// This is 39 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n /// @param pendingDepositProofs a `PendingDepositProofs` struct containing the following:\n /// - pendingDepositContainerRoot: The merkle root of the pending deposits list container\n /// - pendingDepositContainerProof: The merkle proof from the pending deposits list container\n /// to the beacon block root.\n /// This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n /// - pendingDepositIndexes: Array of indexes in the pending deposits list container for each\n /// of the strategy's deposits.\n /// - pendingDepositProofs: Array of merkle proofs for each strategy deposit in the\n /// beacon chain's pending deposit list container to the pending deposits list container root.\n /// These are 28 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n // slither-disable-start reentrancy-no-eth\n function verifyBalances(\n BalanceProofs calldata balanceProofs,\n PendingDepositProofs calldata pendingDepositProofs\n ) external onlyRegistrator {\n // Load previously snapped balances for the given block root\n Balances memory balancesMem = snappedBalance;\n // Check the balances are the latest\n require(balancesMem.timestamp > 0, \"No snapped balances\");\n\n uint256 verifiedValidatorsCount = verifiedValidators.length;\n uint256 totalValidatorBalance = 0;\n uint256 depositsCount = depositList.length;\n\n // If there are no verified validators then we can skip the balance verification\n if (verifiedValidatorsCount > 0) {\n require(\n balanceProofs.validatorBalanceProofs.length ==\n verifiedValidatorsCount,\n \"Invalid balance proofs\"\n );\n require(\n balanceProofs.validatorBalanceLeaves.length ==\n verifiedValidatorsCount,\n \"Invalid balance leaves\"\n );\n // verify beaconBlock.state.balances root to beacon block root\n IBeaconProofs(BEACON_PROOFS).verifyBalancesContainer(\n balancesMem.blockRoot,\n balanceProofs.balancesContainerRoot,\n balanceProofs.balancesContainerProof\n );\n\n bytes32[]\n memory validatorHashesMem = _getPendingDepositValidatorHashes(\n depositsCount\n );\n\n // for each validator in reverse order so we can pop off exited validators at the end\n for (uint256 i = verifiedValidatorsCount; i > 0; ) {\n --i;\n ValidatorData memory validatorDataMem = validator[\n verifiedValidators[i]\n ];\n // verify validator's balance in beaconBlock.state.balances to the\n // beaconBlock.state.balances container root\n uint256 validatorBalanceGwei = IBeaconProofs(BEACON_PROOFS)\n .verifyValidatorBalance(\n balanceProofs.balancesContainerRoot,\n balanceProofs.validatorBalanceLeaves[i],\n balanceProofs.validatorBalanceProofs[i],\n validatorDataMem.index\n );\n\n // If the validator has exited and the balance is now zero\n if (validatorBalanceGwei == 0) {\n // Check if there are any pending deposits to this validator\n bool depositPending = false;\n for (uint256 j = 0; j < validatorHashesMem.length; j++) {\n if (validatorHashesMem[j] == verifiedValidators[i]) {\n depositPending = true;\n break;\n }\n }\n\n // If validator has a pending deposit we can not remove due to\n // the following situation:\n // - validator has a pending deposit\n // - validator has been slashed\n // - sweep cycle has withdrawn all ETH from the validator. Balance is 0\n // - beacon chain has processed the deposit and set the validator balance\n // to deposit amount\n // - if validator is no longer in the list of verifiedValidators its\n // balance will not be considered and be under-counted.\n if (!depositPending) {\n // Store the validator state as exited\n // This could have been in VERIFIED, ACTIVE or EXITING state\n validator[verifiedValidators[i]].state = ValidatorState\n .EXITED;\n\n // Remove the validator with a zero balance from the list of verified validators\n\n // Reduce the count of verified validators which is the last index before the pop removes it.\n verifiedValidatorsCount -= 1;\n\n // Move the last validator that has already been verified to the current index.\n // There's an extra SSTORE if i is the last active validator but that's fine,\n // It's not a common case and the code is simpler this way.\n verifiedValidators[i] = verifiedValidators[\n verifiedValidatorsCount\n ];\n // Delete the last validator from the list\n verifiedValidators.pop();\n }\n\n // The validator balance is zero so not need to add to totalValidatorBalance\n continue;\n } else if (\n validatorDataMem.state == ValidatorState.VERIFIED &&\n validatorBalanceGwei > MIN_ACTIVATION_BALANCE_GWEI\n ) {\n // Store the validator state as active. This does not necessarily mean the\n // validator is active on the beacon chain yet. It just means the validator has\n // enough balance that it can become active.\n validator[verifiedValidators[i]].state = ValidatorState\n .ACTIVE;\n }\n\n // convert Gwei balance to Wei and add to the total validator balance\n totalValidatorBalance += validatorBalanceGwei * 1 gwei;\n }\n }\n\n uint256 totalDepositsWei = 0;\n\n // If there are no deposits then we can skip the deposit verification.\n // This section is after the validator balance verifications so an exited validator will be marked\n // as EXITED before the deposits are verified. If there was a deposit to an exited validator\n // then the deposit can only be removed once the validator is fully exited.\n // It is possible that validator fully exits and a postponed deposit to an exited validator increases\n // its balance again. In such case the contract will erroneously consider a deposit applied before it\n // has been applied on the beacon chain showing a smaller than real `totalValidatorBalance`.\n if (depositsCount > 0) {\n require(\n pendingDepositProofs.pendingDepositProofs.length ==\n depositsCount,\n \"Invalid deposit proofs\"\n );\n require(\n pendingDepositProofs.pendingDepositIndexes.length ==\n depositsCount,\n \"Invalid deposit indexes\"\n );\n\n // Verify from the root of the pending deposit list container to the beacon block root\n IBeaconProofs(BEACON_PROOFS).verifyPendingDepositsContainer(\n balancesMem.blockRoot,\n pendingDepositProofs.pendingDepositContainerRoot,\n pendingDepositProofs.pendingDepositContainerProof\n );\n\n // For each staking strategy's deposit.\n for (uint256 i = 0; i < depositsCount; ++i) {\n bytes32 pendingDepositRoot = depositList[i];\n\n // Verify the strategy's deposit is still pending on the beacon chain.\n IBeaconProofs(BEACON_PROOFS).verifyPendingDeposit(\n pendingDepositProofs.pendingDepositContainerRoot,\n pendingDepositRoot,\n pendingDepositProofs.pendingDepositProofs[i],\n pendingDepositProofs.pendingDepositIndexes[i]\n );\n\n // Convert the deposit amount from Gwei to Wei and add to the total\n totalDepositsWei +=\n uint256(deposits[pendingDepositRoot].amountGwei) *\n 1 gwei;\n }\n }\n\n // Store the verified balance in storage\n lastVerifiedEthBalance =\n totalDepositsWei +\n totalValidatorBalance +\n balancesMem.ethBalance;\n // Reset the last snap timestamp so a new snapBalances has to be made\n snappedBalance.timestamp = 0;\n\n emit BalancesVerified(\n balancesMem.timestamp,\n totalDepositsWei,\n totalValidatorBalance,\n balancesMem.ethBalance\n );\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice get a list of all validator hashes present in the pending deposits\n /// list can have duplicate entries\n function _getPendingDepositValidatorHashes(uint256 depositsCount)\n internal\n view\n returns (bytes32[] memory validatorHashes)\n {\n validatorHashes = new bytes32[](depositsCount);\n for (uint256 i = 0; i < depositsCount; i++) {\n validatorHashes[i] = deposits[depositList[i]].pubKeyHash;\n }\n }\n\n /// @notice Hash a validator public key using the Beacon Chain's format\n function _hashPubKey(bytes memory pubKey) internal pure returns (bytes32) {\n require(pubKey.length == 48, \"Invalid public key\");\n return sha256(abi.encodePacked(pubKey, bytes16(0)));\n }\n\n /**\n *\n * WETH and ETH Accounting\n *\n */\n\n /// @dev Called when WETH is transferred out of the strategy so\n /// the strategy knows how much WETH it has on deposit.\n /// This is so it can emit the correct amount in the Deposit event in depositAll().\n function _transferWeth(uint256 _amount, address _recipient) internal {\n IERC20(WETH).safeTransfer(_recipient, _amount);\n\n // The min is required as more WETH can be withdrawn than deposited\n // as the strategy earns consensus and execution rewards.\n uint256 deductAmount = Math.min(_amount, depositedWethAccountedFor);\n depositedWethAccountedFor -= deductAmount;\n\n // No change in ETH balance so no need to snapshot the balances\n }\n\n /// @dev Converts ETH to WETH and updates the accounting.\n /// @param _ethAmount The amount of ETH in wei.\n function _convertEthToWeth(uint256 _ethAmount) internal {\n // slither-disable-next-line arbitrary-send-eth\n IWETH9(WETH).deposit{ value: _ethAmount }();\n\n depositedWethAccountedFor += _ethAmount;\n\n // Store the reduced ETH balance.\n // The ETH balance in this strategy contract can be more than the last verified ETH balance\n // due to partial withdrawals or full exits being processed by the beacon chain since the last snapBalances.\n // It can also happen from execution rewards (MEV) or ETH donations.\n lastVerifiedEthBalance -= Math.min(lastVerifiedEthBalance, _ethAmount);\n\n // The ETH balance was decreased to WETH so we need to invalidate the last balances snap.\n snappedBalance.timestamp = 0;\n }\n\n /// @dev Converts WETH to ETH and updates the accounting.\n /// @param _wethAmount The amount of WETH in wei.\n function _convertWethToEth(uint256 _wethAmount) internal {\n IWETH9(WETH).withdraw(_wethAmount);\n\n uint256 deductAmount = Math.min(_wethAmount, depositedWethAccountedFor);\n depositedWethAccountedFor -= deductAmount;\n\n // Store the increased ETH balance\n lastVerifiedEthBalance += _wethAmount;\n\n // The ETH balance was increased from WETH so we need to invalidate the last balances snap.\n snappedBalance.timestamp = 0;\n }\n\n /**\n *\n * View Functions\n *\n */\n\n /// @notice Returns the number of deposits waiting to be verified as processed on the beacon chain,\n /// or deposits that have been verified to an exiting validator and is now waiting for the\n /// validator's balance to be swept.\n function depositListLength() external view returns (uint256) {\n return depositList.length;\n }\n\n /// @notice Returns the number of verified validators.\n function verifiedValidatorsLength() external view returns (uint256) {\n return verifiedValidators.length;\n }\n}\n" + }, + "contracts/strategies/NativeStaking/ConsolidationController.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\n\nimport { CompoundingStakingSSVStrategy, CompoundingValidatorManager } from \"./CompoundingStakingSSVStrategy.sol\";\nimport { ValidatorAccountant } from \"./ValidatorAccountant.sol\";\nimport { Cluster } from \"../../interfaces/ISSVNetwork.sol\";\n\n/// @title Consolidation Controller\n/// @notice Orchestrates the consolidation of validators from old Native Staking Strategies\n/// to the new Compounding Staking Strategy.\n/// @author Origin Protocol Inc\ncontract ConsolidationController is Ownable {\n /// @dev Minimum time that must pass before a consolidation request can be processed.\n /// 261 epochs * 32 slots/epoch * 12 seconds/slot = 100224 seconds (~27.8 hours)\n /// Includes 256 epochs minimum withdrawability delay + 5 epochs from\n /// compute_activation_exit_epoch (MAX_SEED_LOOKAHEAD + 1).\n /// The actual time can be a lot longer than this depending on the number of\n /// requests in the beacon chain's pending consolidation queue.\n uint256 internal constant MIN_CONSOLIDATION_PERIOD = 261 * 32 * 12;\n\n /// @notice Address of the validator registrator account\n address public immutable validatorRegistrator;\n /// @dev The old Native Staking Strategy connected to the second SSV cluster\n address internal immutable nativeStakingStrategy2;\n /// @dev The old Native Staking Strategy connected to the third SSV cluster\n address internal immutable nativeStakingStrategy3;\n /// @dev The new Compounding Staking Strategy\n CompoundingStakingSSVStrategy internal immutable targetStrategy;\n\n /// @notice Number of validators being consolidated\n uint64 public consolidationCount;\n /// @notice Timestamp when the consolidation process was requested\n uint64 public consolidationStartTimestamp;\n /// @notice The address of the source Native Staking Strategy being consolidated from\n address public sourceStrategy;\n /// @notice The public key hash of the target validator on the new Compounding Staking Strategy\n bytes32 public targetPubKeyHash;\n /// @dev Tracks source validators that were requested for a consolidation round.\n /// Keyed by keccak256(sourcePubKeyHash, consolidationStartTimestamp).\n mapping(bytes32 => bool) private pendingSourceInRound;\n\n /// @dev Throws if called by any account other than the Validator Registrator\n modifier onlyRegistrator() {\n require(\n msg.sender == validatorRegistrator,\n \"Caller is not the Registrator\"\n );\n _;\n }\n\n /// @param _owner The owner who can request, fail and confirm consolidations\n /// @param _validatorRegistrator The validator registrator who does operations on the old staking strategy\n constructor(\n address _owner,\n address _validatorRegistrator,\n address _nativeStakingStrategy2,\n address _nativeStakingStrategy3,\n address _targetStrategy\n ) {\n _transferOwnership(_owner);\n\n validatorRegistrator = _validatorRegistrator;\n nativeStakingStrategy2 = _nativeStakingStrategy2;\n nativeStakingStrategy3 = _nativeStakingStrategy3;\n targetStrategy = CompoundingStakingSSVStrategy(\n payable(_targetStrategy)\n );\n }\n\n /**\n * @notice Request consolidation of validators from an old Native Staking Strategy\n * to the new Compounding Staking Strategy\n * @param _sourceStrategy The address of the old Native Staking Strategy\n * @param sourcePubKeys The public keys of the validators to be consolidated from the old Native Staking Strategy\n * @param targetPubKey The public key of the target validator on the new Compounding Staking Strategy\n */\n function requestConsolidation(\n address _sourceStrategy,\n bytes[] calldata sourcePubKeys,\n bytes calldata targetPubKey\n ) external payable onlyOwner {\n // Check no consolidations are already in progress\n require(consolidationCount == 0, \"Consolidation in progress\");\n // Check at least one source validator is provided\n require(sourcePubKeys.length > 0, \"Empty source validators\");\n // Check sourceStrategy is a valid old Native Staking Strategy\n _checkSourceStrategy(_sourceStrategy);\n\n // Check target validator is Active on the new Compounding Staking Strategy\n bytes32 targetPubKeyHashMem = _hashPubKey(targetPubKey);\n (CompoundingStakingSSVStrategy.ValidatorState state, ) = targetStrategy\n .validator(targetPubKeyHashMem);\n require(\n state == CompoundingValidatorManager.ValidatorState.ACTIVE,\n \"Target validator not active\"\n );\n // Check no pending deposits in the new target validator\n require(\n _hasPendingDeposit(targetPubKeyHashMem) == false,\n \"Target has pending deposit\"\n );\n\n // Store the state at the start of the consolidation process\n consolidationCount = SafeCast.toUint64(sourcePubKeys.length);\n uint64 consolidationStartTimestampMem = uint64(block.timestamp);\n consolidationStartTimestamp = consolidationStartTimestampMem;\n sourceStrategy = _sourceStrategy;\n targetPubKeyHash = targetPubKeyHashMem;\n\n // Store source validators for this consolidation round.\n for (uint256 i = 0; i < sourcePubKeys.length; ++i) {\n bytes32 roundKey = _sourceValidatorRoundKey(\n sourcePubKeys[i],\n consolidationStartTimestampMem\n );\n require(\n pendingSourceInRound[roundKey] == false,\n \"Duplicate source validator\"\n );\n pendingSourceInRound[roundKey] = true;\n }\n\n // Call requestConsolidation on the old Native Staking Strategy\n // to initiate the consolidations\n ValidatorAccountant(_sourceStrategy).requestConsolidation{\n value: msg.value\n }(sourcePubKeys, targetPubKey);\n\n // Snap the balances for the last time on the new Compounding Staking Strategy\n // if it hasn't been called recently. Otherwise skip to prevent a DoS\n // attack where an attacker front-runs this call with the permissionless snapBalances().\n (, uint64 lastSnapTimestamp, ) = targetStrategy.snappedBalance();\n if (\n uint64(block.timestamp) >\n lastSnapTimestamp + targetStrategy.SNAP_BALANCES_DELAY()\n ) {\n targetStrategy.snapBalances();\n }\n\n // No event emitted as ConsolidationRequested is emitted from the old Native Staking Strategy\n }\n\n /**\n * @notice A consolidation request can fail to be processed on the beacon chain\n * for various reasons. For example, the pending consolidation queue is full with 262,144 requests.\n * Or the source validator has exited from a voluntary exit request.\n * This reduces the consolidation count and changes the validator state back to STAKED.\n * @param sourcePubKeys The public keys of the source validators that failed to be consolidated.\n */\n function failConsolidation(bytes[] calldata sourcePubKeys)\n external\n onlyOwner\n {\n // Check consolidations are in progress\n require(consolidationCount > 0, \"No consolidation in progress\");\n // There a min time before a failed consolidation can be unwound.\n // This gives the beacon chain time to process the request.\n require(\n block.timestamp >=\n consolidationStartTimestamp + MIN_CONSOLIDATION_PERIOD,\n \"Source not withdrawable\"\n );\n require(\n sourcePubKeys.length <= consolidationCount,\n \"Exceeds consolidation count\"\n );\n uint64 consolidationStartTimestampMem = consolidationStartTimestamp;\n\n for (uint256 i = 0; i < sourcePubKeys.length; ++i) {\n bytes32 roundKey = _sourceValidatorRoundKey(\n sourcePubKeys[i],\n consolidationStartTimestampMem\n );\n require(pendingSourceInRound[roundKey], \"Unknown source validator\");\n pendingSourceInRound[roundKey] = false;\n }\n\n // Read into memory in case it gets reset in storage before\n // the external call to the source strategy\n address sourceStrategyMem = sourceStrategy;\n\n // Store updated consolidation state\n consolidationCount -= SafeCast.toUint64(sourcePubKeys.length);\n if (consolidationCount == 0) {\n // Reset the rest of the consolidation state\n consolidationStartTimestamp = 0;\n sourceStrategy = address(0);\n targetPubKeyHash = bytes32(0);\n }\n\n ValidatorAccountant(sourceStrategyMem).failConsolidation(sourcePubKeys);\n\n // No event emitted as ConsolidationFailed is emitted from the old Native Staking Strategy\n }\n\n /**\n * @notice Confirm the consolidation of validators from an old Native Staking Strategy\n * to the new Compounding Staking Strategy has been completed.\n * @param balanceProofs a `BalanceProofs` struct containing the following:\n * - balancesContainerRoot: The merkle root of the balances container\n * - balancesContainerProof: The merkle proof for the balances container to the beacon block root.\n * This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * - validatorBalanceLeaves: Array of leaf nodes containing the validator balance with three other balances.\n * - validatorBalanceProofs: Array of merkle proofs for the validator balance to the Balances container root.\n * This is 39 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * @param pendingDepositProofs a `PendingDepositProofs` struct containing the following:\n * - pendingDepositContainerRoot: The merkle root of the pending deposits list container\n * - pendingDepositContainerProof: The merkle proof from the pending deposits list container\n * to the beacon block root.\n * This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * - pendingDepositIndexes: Array of indexes in the pending deposits list container for each\n * of the strategy's deposits.\n * - pendingDepositProofs: Array of merkle proofs for each strategy deposit in the\n * beacon chain's pending deposit list container to the pending deposits list container root.\n * These are 28 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n */\n function confirmConsolidation(\n CompoundingValidatorManager.BalanceProofs calldata balanceProofs,\n CompoundingValidatorManager.PendingDepositProofs\n calldata pendingDepositProofs\n ) external onlyOwner {\n // Check consolidations are in progress\n require(consolidationCount > 0, \"No consolidation in progress\");\n // There a min time before a consolidation can be processed on the beacon chain\n (, uint64 snappedTimestamp, ) = targetStrategy.snappedBalance();\n require(\n uint64(snappedTimestamp) >\n consolidationStartTimestamp + MIN_CONSOLIDATION_PERIOD,\n \"Source not withdrawable\"\n );\n\n // Load into memory as the storage is about to be reset.\n // These are used in the external contract calls\n address sourceStrategyMem = sourceStrategy;\n uint256 consolidationCountMem = consolidationCount;\n\n // Reset consolidation state before external calls\n consolidationCount = 0;\n consolidationStartTimestamp = 0;\n sourceStrategy = address(0);\n targetPubKeyHash = bytes32(0);\n\n // Verify balances on the new Compounding Staking Strategy and update the strategy's balance\n targetStrategy.verifyBalances(balanceProofs, pendingDepositProofs);\n\n // Reduce the balance of the old Native Staking Strategy\n ValidatorAccountant(sourceStrategyMem).confirmConsolidation(\n consolidationCountMem\n );\n\n // No event emitted as ConsolidationConfirmed is emitted from the old Native Staking Strategy\n }\n\n /**\n *\n * Functions that forward to the old Native Staking Strategy\n *\n */\n\n /// @notice The validator registrator of the old Native Staking Strategy can call doAccounting\n /// @param _sourceStrategy The address of the old Native Staking Strategy\n /// @return accountingValid true if accounting was successful, false if fuse is blown\n function doAccounting(address _sourceStrategy)\n external\n onlyRegistrator\n returns (bool accountingValid)\n {\n // Check sourceStrategy is a valid old Native Staking Strategy\n _checkSourceStrategy(_sourceStrategy);\n\n return ValidatorAccountant(_sourceStrategy).doAccounting();\n }\n\n /**\n * @notice Exit of source validators are allowed during the consolidation process\n * as consolidated validators will be in EXITING state hence can not be consolidated after exit.\n * Only callable by the validator registrator.\n * @param _sourceStrategy The address of the old Native Staking Strategy\n * @param publicKey The public key of the validator to exit which must have STAKED state.\n * @param operatorIds The operator IDs for the source SSV cluster\n */\n function exitSsvValidator(\n address _sourceStrategy,\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external onlyRegistrator {\n // Check sourceStrategy is a valid old Native Staking Strategy\n _checkSourceStrategy(_sourceStrategy);\n\n ValidatorAccountant(_sourceStrategy).exitSsvValidator(\n publicKey,\n operatorIds\n );\n }\n\n /**\n * @notice Removing source validators is not allowed during the consolidation process\n * as consolidated validators will be in EXITING state hence can not be consolidated after removal.\n * Only callable by the validator registrator.\n * @param _sourceStrategy The address of the old Native Staking Strategy\n * @param publicKey The public key of the validator to remove which must have EXITING or REGISTERED state.\n * @param operatorIds The operator IDs for the source SSV cluster\n * @param cluster The SSV cluster information for the source validator\n */\n function removeSsvValidator(\n address _sourceStrategy,\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator {\n // Check sourceStrategy is a valid old Native Staking Strategy\n _checkSourceStrategy(_sourceStrategy);\n // Prevent removing a validator from the SSV cluster before the consolidation\n // process has been completed for the source strategy being consolidated.\n // This prevents validators that have been exited rather than consolidated but that's ok.\n // The exited validator can be removed after the consolidation process is complete.\n require(_sourceStrategy != sourceStrategy, \"Consolidation in progress\");\n\n ValidatorAccountant(_sourceStrategy).removeSsvValidator(\n publicKey,\n operatorIds,\n cluster\n );\n }\n\n /**\n *\n * Functions that forward to the new Compounding Staking Strategy\n *\n */\n\n /// @notice Forwards to the new Compounding Staking Strategy.\n /// Is only callable by the validator registrator when a consolidation is in progress.\n /// Anyone can call when there are no consolidations in progress.\n function snapBalances() external {\n if (consolidationCount > 0 && msg.sender != validatorRegistrator) {\n revert(\"Consolidation in progress\");\n }\n if (consolidationCount > 0) {\n require(\n block.timestamp >\n consolidationStartTimestamp + MIN_CONSOLIDATION_PERIOD,\n \"Source not withdrawable\"\n );\n }\n\n targetStrategy.snapBalances();\n }\n\n /**\n * @notice Anyone can verify balances on the new Compounding Staking Strategy\n * as long as there are no consolidations in progress.\n * @param balanceProofs a `BalanceProofs` struct containing the following:\n * - balancesContainerRoot: The merkle root of the balances container\n * - balancesContainerProof: The merkle proof for the balances container to the beacon block root.\n * This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * - validatorBalanceLeaves: Array of leaf nodes containing the validator balance with three other balances.\n * - validatorBalanceProofs: Array of merkle proofs for the validator balance to the Balances container root.\n * This is 39 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * @param pendingDepositProofs a `PendingDepositProofs` struct containing the following:\n * - pendingDepositContainerRoot: The merkle root of the pending deposits list container\n * - pendingDepositContainerProof: The merkle proof from the pending deposits list container\n * to the beacon block root.\n * This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * - pendingDepositIndexes: Array of indexes in the pending deposits list container for each\n * of the strategy's deposits.\n * - pendingDepositProofs: Array of merkle proofs for each strategy deposit in the\n * beacon chain's pending deposit list container to the pending deposits list container root.\n * These are 28 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n */\n function verifyBalances(\n CompoundingValidatorManager.BalanceProofs calldata balanceProofs,\n CompoundingValidatorManager.PendingDepositProofs\n calldata pendingDepositProofs\n ) external {\n (, uint64 snappedTimestamp, ) = targetStrategy.snappedBalance();\n // Can not verify balances while consolidations are in progress\n // if the snap was taken after the consolidation process started.\n // This still allows verifying a pre-existing snap.\n if (\n consolidationCount > 0 &&\n snappedTimestamp > consolidationStartTimestamp\n ) {\n revert(\"Consolidation in progress\");\n }\n\n targetStrategy.verifyBalances(balanceProofs, pendingDepositProofs);\n }\n\n /// @notice Partial withdrawals are allowed during consolidation from the new Compounding Staking Strategy.\n /// This includes partial withdrawals from the target validator.\n // Full validator exits from any Compounding Staking Strategy validator are\n /// not allowed during the migration period.\n /// Only the registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param amountGwei The amount of ETH to be withdrawn from the validator in Gwei.\n /// A zero amount is not allowed.\n function validatorWithdrawal(bytes calldata publicKey, uint64 amountGwei)\n external\n payable\n onlyRegistrator\n {\n // Prevent full exits from any new compounding validators.\n // This includes when there is no consolidation in progress.\n // This reduces the risk of an exit request being processed before a consolidation request\n require(amountGwei > 0, \"No exit during migration\");\n targetStrategy.validatorWithdrawal{ value: msg.value }(\n publicKey,\n amountGwei\n );\n }\n\n /**\n * @notice Deposits to Compounding Staking Strategy validators that are\n * not the target of a consolidation are allowed.\n * Only the registrator can call this function.\n * @param validatorStakeData validator data needed to stake.\n * The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot.\n * @param depositAmountGwei The amount of WETH to stake to the validator in Gwei.\n */\n function stakeEth(\n CompoundingValidatorManager.ValidatorStakeData\n calldata validatorStakeData,\n uint64 depositAmountGwei\n ) external onlyRegistrator {\n require(\n _hashPubKey(validatorStakeData.pubkey) != targetPubKeyHash,\n \"Stake to consolidation target\"\n );\n\n targetStrategy.stakeEth(validatorStakeData, depositAmountGwei);\n }\n\n /// removeSsvValidator from the new Compounding Staking Strategy is not allowed until after\n /// all the validators have been consolidated. This is done by restoring the validator registrator\n /// back to the account used before the consolidation upgrades.\n\n /**\n *\n * Internal Functions\n *\n */\n\n /// @dev Check if there are any pending deposits for a validator with a given public key hash.\n /// Need to iterate over the target strategy’s `deposits`\n /// @return True if there is at least one pending deposit for the validator\n function _hasPendingDeposit(bytes32 _targetPubKeyHash)\n internal\n view\n returns (bool)\n {\n uint256 depositsCount = targetStrategy.depositListLength();\n for (uint256 i = 0; i < depositsCount; ++i) {\n (\n bytes32 depositPubKeyHash,\n ,\n ,\n ,\n CompoundingValidatorManager.DepositStatus status\n ) = targetStrategy.deposits(targetStrategy.depositList(i));\n if (\n depositPubKeyHash == _targetPubKeyHash &&\n status == CompoundingValidatorManager.DepositStatus.PENDING\n ) {\n return true;\n }\n }\n return false;\n }\n\n /// @dev Hash a validator public key using the Beacon Chain's format\n /// @param pubKey The full validator public key\n /// @return The hashed public key using the Beacon Chain's hashing for BLSPubkey\n function _hashPubKey(bytes memory pubKey) internal pure returns (bytes32) {\n require(pubKey.length == 48, \"Invalid public key\");\n return sha256(abi.encodePacked(pubKey, bytes16(0)));\n }\n\n /// @dev Build a key for tracking source validators in a consolidation round.\n function _sourceValidatorRoundKey(\n bytes memory sourcePubKey,\n uint64 roundTimestamp\n ) internal pure returns (bytes32) {\n return keccak256(abi.encode(_hashPubKey(sourcePubKey), roundTimestamp));\n }\n\n /// @dev Check source strategy is a valid old Native Staking Strategy\n /// @param _sourceStrategy The address of the old Native Staking Strategy\n function _checkSourceStrategy(address _sourceStrategy) internal view {\n require(\n _sourceStrategy == nativeStakingStrategy2 ||\n _sourceStrategy == nativeStakingStrategy3,\n \"Invalid source strategy\"\n );\n }\n}\n" + }, + "contracts/strategies/NativeStaking/FeeAccumulator.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\n/**\n * @title Fee Accumulator for Native Staking SSV Strategy\n * @notice Receives execution rewards which includes tx fees and\n * MEV rewards like tx priority and tx ordering.\n * It does NOT include swept ETH from beacon chain consensus rewards or full validator withdrawals.\n * @author Origin Protocol Inc\n */\ncontract FeeAccumulator {\n /// @notice The address of the Native Staking Strategy\n address public immutable STRATEGY;\n\n event ExecutionRewardsCollected(address indexed strategy, uint256 amount);\n\n /**\n * @param _strategy Address of the Native Staking Strategy\n */\n constructor(address _strategy) {\n STRATEGY = _strategy;\n }\n\n /**\n * @notice sends all ETH in this FeeAccumulator contract to the Native Staking Strategy.\n * @return eth The amount of execution rewards that were sent to the Native Staking Strategy\n */\n function collect() external returns (uint256 eth) {\n require(msg.sender == STRATEGY, \"Caller is not the Strategy\");\n\n eth = address(this).balance;\n if (eth > 0) {\n // Send the ETH to the Native Staking Strategy\n Address.sendValue(payable(STRATEGY), eth);\n\n emit ExecutionRewardsCollected(STRATEGY, eth);\n }\n }\n\n /**\n * @dev Accept ETH\n */\n receive() external payable {}\n}\n" + }, + "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { FeeAccumulator } from \"./FeeAccumulator.sol\";\nimport { ValidatorAccountant } from \"./ValidatorAccountant.sol\";\nimport { ISSVNetwork } from \"../../interfaces/ISSVNetwork.sol\";\n\nstruct ValidatorStakeData {\n bytes pubkey;\n bytes signature;\n bytes32 depositDataRoot;\n}\n\n/// @title Native Staking SSV Strategy\n/// @notice Strategy to deploy funds into DVT validators powered by the SSV Network\n/// @author Origin Protocol Inc\n/// @dev This contract handles WETH and ETH and in some operations interchanges between the two. Any WETH that\n/// is on the contract across multiple blocks (and not just transitory within a transaction) is considered an\n/// asset. Meaning deposits increase the balance of the asset and withdrawal decrease it. As opposed to all\n/// our other strategies the WETH doesn't immediately get deposited into an underlying strategy and can be present\n/// across multiple blocks waiting to be unwrapped to ETH and staked to validators. This separation of WETH and ETH is\n/// required since the rewards (reward token) is also in ETH.\n///\n/// To simplify the accounting of WETH there is another difference in behavior compared to the other strategies.\n/// To withdraw WETH asset - exit message is posted to validators and the ETH hits this contract with multiple days\n/// delay. In order to simplify the WETH accounting upon detection of such an event the ValidatorAccountant\n/// immediately wraps ETH to WETH and sends it to the Vault.\n///\n/// On the other hand any ETH on the contract (across multiple blocks) is there either:\n/// - as a result of already accounted for consensus rewards\n/// - as a result of not yet accounted for consensus rewards\n/// - as a results of not yet accounted for full validator withdrawals (or validator slashes)\n///\n/// Even though the strategy assets and rewards are a very similar asset the consensus layer rewards and the\n/// execution layer rewards are considered rewards and those are dripped to the Vault over a configurable time\n/// interval and not immediately.\ncontract NativeStakingSSVStrategy is\n ValidatorAccountant,\n InitializableAbstractStrategy\n{\n using SafeERC20 for IERC20;\n\n /// @notice SSV ERC20 token that serves as a payment for operating SSV validators\n address public immutable SSV_TOKEN;\n /// @notice Fee collector address\n /// @dev this address will receive maximal extractable value (MEV) rewards. These are\n /// rewards for arranging transactions in a way that benefits the validator.\n address payable public immutable FEE_ACCUMULATOR_ADDRESS;\n\n /// @dev This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately\n /// deposit it to an underlying platform. Rather a special privilege account stakes it to the validators.\n /// For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been\n /// deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track\n /// of WETH that has already been accounted for.\n /// This value represents the amount of WETH balance of this contract that has already been accounted for by the\n /// deposit events.\n /// It is important to note that this variable is not concerned with WETH that is a result of full/partial\n /// withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to\n /// be staked.\n uint256 public depositedWethAccountedFor;\n\n // For future use\n uint256[49] private __gap;\n\n /// @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI,\n /// and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _ssvToken Address of the Erc20 SSV Token contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _maxValidators Maximum number of validators that can be registered in the strategy\n /// @param _feeAccumulator Address of the fee accumulator receiving execution layer validator rewards\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _wethAddress,\n address _ssvToken,\n address _ssvNetwork,\n uint256 _maxValidators,\n address _feeAccumulator,\n address _beaconChainDepositContract\n )\n InitializableAbstractStrategy(_baseConfig)\n ValidatorAccountant(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork,\n _maxValidators\n )\n {\n SSV_TOKEN = _ssvToken;\n FEE_ACCUMULATOR_ADDRESS = payable(_feeAccumulator);\n }\n\n /// @notice Set up initial internal state including\n /// 1. approving the SSVNetwork to transfer SSV tokens from this strategy contract\n /// 2. setting the recipient of SSV validator MEV rewards to the FeeAccumulator contract.\n /// @param _rewardTokenAddresses Address of reward token for platform\n /// @param _assets Addresses of initial supported assets\n /// @param _pTokens Platform Token corresponding addresses\n function initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n\n // Approves the SSV Network contract to transfer SSV tokens for deposits\n IERC20(SSV_TOKEN).approve(SSV_NETWORK, type(uint256).max);\n\n // Set the FeeAccumulator as the address for SSV validators to send MEV rewards to\n ISSVNetwork(SSV_NETWORK).setFeeRecipientAddress(\n FEE_ACCUMULATOR_ADDRESS\n );\n }\n\n /// @notice Unlike other strategies, this does not deposit assets into the underlying platform.\n /// It just checks the asset is WETH and emits the Deposit event.\n /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used.\n /// Will NOT revert if the strategy is paused from an accounting failure.\n /// @param _asset Address of asset to deposit. Has to be WETH.\n /// @param _amount Amount of assets that were transferred to the strategy by the vault.\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n require(_asset == WETH, \"Unsupported asset\");\n depositedWethAccountedFor += _amount;\n _deposit(_asset, _amount);\n }\n\n /// @dev Deposit WETH to this strategy so it can later be staked into a validator.\n /// @param _asset Address of WETH\n /// @param _amount Amount of WETH to deposit\n function _deposit(address _asset, uint256 _amount) internal {\n require(_amount > 0, \"Must deposit something\");\n /*\n * We could do a check here that would revert when \"_amount % 32 ether != 0\". With the idea of\n * not allowing deposits that will result in WETH sitting on the strategy after all the possible batches\n * of 32ETH have been staked.\n * But someone could mess with our strategy by sending some WETH to it. And we might want to deposit just\n * enough WETH to add it up to 32 so it can be staked. For that reason the check is left out.\n *\n * WETH sitting on the strategy won't interfere with the accounting since accounting only operates on ETH.\n */\n emit Deposit(_asset, address(0), _amount);\n }\n\n /// @notice Unlike other strategies, this does not deposit assets into the underlying platform.\n /// It just emits the Deposit event.\n /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used.\n /// Will NOT revert if the strategy is paused from an accounting failure.\n function depositAll() external override onlyVault nonReentrant {\n uint256 wethBalance = IERC20(WETH).balanceOf(address(this));\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\n\n if (newWeth > 0) {\n depositedWethAccountedFor = wethBalance;\n\n _deposit(WETH, newWeth);\n }\n }\n\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract.\n /// That can happen when:\n /// - after mints if the strategy is the default\n /// - time between depositToStrategy and stakeEth\n /// - the deposit was not a multiple of 32 WETH\n /// - someone sent WETH directly to this contract\n /// Will NOT revert if the strategy is paused from an accounting failure.\n /// @param _recipient Address to receive withdrawn assets\n /// @param _asset WETH to withdraw\n /// @param _amount Amount of WETH to withdraw\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_asset == WETH, \"Unsupported asset\");\n _withdraw(_recipient, _asset, _amount);\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n _wethWithdrawn(_amount);\n\n IERC20(_asset).safeTransfer(_recipient, _amount);\n emit Withdrawal(_asset, address(0), _amount);\n }\n\n /// @notice transfer all WETH deposits back to the vault.\n /// This does not withdraw from the validators. That has to be done separately with the\n /// `exitSsvValidator` and `removeSsvValidator` operations.\n /// This does not withdraw any execution rewards from the FeeAccumulator or\n /// consensus rewards in this strategy.\n /// Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn.\n /// ETH from full validator withdrawals is sent to the Vault using `doAccounting`.\n /// Will NOT revert if the strategy is paused from an accounting failure.\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 wethBalance = IERC20(WETH).balanceOf(address(this));\n if (wethBalance > 0) {\n _withdraw(vaultAddress, WETH, wethBalance);\n }\n }\n\n /// @notice Returns the total value of (W)ETH that is staked to the validators\n /// and WETH deposits that are still to be staked.\n /// This does not include ETH from consensus rewards sitting in this strategy\n /// or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested\n /// and sent to the Dripper so will eventually be sent to the Vault as WETH.\n /// @param _asset Address of weth asset\n /// @return balance Total value of (W)ETH\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == WETH, \"Unsupported asset\");\n\n balance =\n // add the ETH that has been staked in validators\n activeDepositedValidators *\n FULL_STAKE +\n // add the WETH in the strategy from deposits that are still to be staked\n IERC20(WETH).balanceOf(address(this));\n }\n\n function pause() external onlyStrategist {\n _pause();\n }\n\n /// @notice Returns bool indicating whether asset is supported by strategy.\n /// @param _asset The address of the asset token.\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == WETH;\n }\n\n /// @notice Approves the SSV Network contract to transfer SSV tokens for deposits\n function safeApproveAllTokens() external override {\n // Approves the SSV Network contract to transfer SSV tokens for deposits\n IERC20(SSV_TOKEN).approve(SSV_NETWORK, type(uint256).max);\n }\n\n /// @notice Set the FeeAccumulator as the address for SSV validators to send MEV rewards to\n function setFeeRecipient() external {\n ISSVNetwork(SSV_NETWORK).setFeeRecipientAddress(\n FEE_ACCUMULATOR_ADDRESS\n );\n }\n\n /**\n * @notice Only accept ETH from the FeeAccumulator and the WETH contract - required when\n * unwrapping WETH just before staking it to the validator.\n * The strategy will also receive ETH from the priority fees of transactions when producing blocks\n * as defined in EIP-1559.\n * The tx fees come from the Beacon chain so do not need any EVM level permissions to receive ETH.\n * The tx fees are paid with each block produced. They are not included in the consensus rewards\n * which are periodically swept from the validators to this strategy.\n * For accounting purposes, the priority fees of transactions will be considered consensus rewards\n * and will be included in the AccountingConsensusRewards event.\n * @dev don't want to receive donations from anyone else as donations over the fuse limits will\n * mess with the accounting of the consensus rewards and validator full withdrawals.\n */\n receive() external payable {\n require(\n msg.sender == FEE_ACCUMULATOR_ADDRESS || msg.sender == WETH,\n \"Eth not from allowed contracts\"\n );\n }\n\n /***************************************\n Internal functions\n ****************************************/\n\n function _abstractSetPToken(address _asset, address) internal override {}\n\n /// @dev Convert accumulated ETH to WETH and send to the Harvester.\n /// Will revert if the strategy is paused for accounting.\n function _collectRewardTokens() internal override whenNotPaused {\n // collect ETH from execution rewards from the fee accumulator\n uint256 executionRewards = FeeAccumulator(FEE_ACCUMULATOR_ADDRESS)\n .collect();\n\n // total ETH rewards to be harvested = execution rewards + consensus rewards\n uint256 ethRewards = executionRewards + consensusRewards;\n\n require(\n address(this).balance >= ethRewards,\n \"Insufficient eth balance\"\n );\n\n if (ethRewards > 0) {\n // reset the counter keeping track of beacon chain consensus rewards\n consensusRewards = 0;\n\n // Convert ETH rewards to WETH\n IWETH9(WETH).deposit{ value: ethRewards }();\n\n IERC20(WETH).safeTransfer(harvesterAddress, ethRewards);\n emit RewardTokenCollected(harvesterAddress, WETH, ethRewards);\n }\n }\n\n /// @dev emits Withdrawal event from NativeStakingSSVStrategy\n function _wethWithdrawnToVault(uint256 _amount) internal override {\n emit Withdrawal(WETH, address(0), _amount);\n }\n\n /// @dev Called when WETH is withdrawn from the strategy or staked to a validator so\n /// the strategy knows how much WETH it has on deposit.\n /// This is so it can emit the correct amount in the Deposit event in depositAll().\n function _wethWithdrawn(uint256 _amount) internal override {\n /* In an ideal world we wouldn't need to reduce the deduction amount when the\n * depositedWethAccountedFor is smaller than the _amount.\n *\n * The reason this is required is that a malicious actor could sent WETH directly\n * to this contract and that would circumvent the increase of depositedWethAccountedFor\n * property. When the ETH would be staked the depositedWethAccountedFor amount could\n * be deducted so much that it would be negative.\n */\n uint256 deductAmount = Math.min(_amount, depositedWethAccountedFor);\n depositedWethAccountedFor -= deductAmount;\n }\n}\n" + }, + "contracts/strategies/NativeStaking/ValidatorAccountant.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ValidatorRegistrator } from \"./ValidatorRegistrator.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\n\n/// @title Validator Accountant\n/// @notice Attributes the ETH swept from beacon chain validators to this strategy contract\n/// as either full or partial withdrawals. Partial withdrawals being consensus rewards.\n/// Full withdrawals are from exited validators.\n/// @author Origin Protocol Inc\nabstract contract ValidatorAccountant is ValidatorRegistrator {\n /// @notice The minimum amount of blocks that need to pass between two calls to manuallyFixAccounting\n uint256 public constant MIN_FIX_ACCOUNTING_CADENCE = 7200; // 1 day\n\n /// @notice Keeps track of the total consensus rewards swept from the beacon chain\n uint256 public consensusRewards;\n\n /// @notice start of fuse interval\n uint256 public fuseIntervalStart;\n /// @notice end of fuse interval\n uint256 public fuseIntervalEnd;\n /// @notice last block number manuallyFixAccounting has been called\n uint256 public lastFixAccountingBlockNumber;\n\n uint256[49] private __gap;\n\n event FuseIntervalUpdated(uint256 start, uint256 end);\n event AccountingFullyWithdrawnValidator(\n uint256 noOfValidators,\n uint256 remainingValidators,\n uint256 wethSentToVault\n );\n event AccountingValidatorSlashed(\n uint256 remainingValidators,\n uint256 wethSentToVault\n );\n event AccountingConsensusRewards(uint256 amount);\n\n event AccountingManuallyFixed(\n int256 validatorsDelta,\n int256 consensusRewardsDelta,\n uint256 wethToVault\n );\n\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _vaultAddress Address of the Vault\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _maxValidators Maximum number of validators that can be registered in the strategy\n constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork,\n uint256 _maxValidators\n )\n ValidatorRegistrator(\n _wethAddress,\n _vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork,\n _maxValidators\n )\n {}\n\n /// @notice set fuse interval values\n function setFuseInterval(\n uint256 _fuseIntervalStart,\n uint256 _fuseIntervalEnd\n ) external onlyGovernor {\n require(\n _fuseIntervalStart < _fuseIntervalEnd &&\n _fuseIntervalEnd < 32 ether &&\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\n \"Incorrect fuse interval\"\n );\n\n fuseIntervalStart = _fuseIntervalStart;\n fuseIntervalEnd = _fuseIntervalEnd;\n\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\n }\n\n /* solhint-disable max-line-length */\n /// This notion page offers a good explanation of how the accounting functions\n /// https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d\n /// In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart,\n /// the accounting function will treat that ETH as Beacon chain consensus rewards.\n /// On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32,\n /// the accounting function will treat that as a validator slashing.\n /// @notice Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when\n /// accounting is valid and fuse isn't \"blown\". Returns false when fuse is blown.\n /// @dev This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it\n /// for now.\n /// @return accountingValid true if accounting was successful, false if fuse is blown\n /* solhint-enable max-line-length */\n function doAccounting()\n external\n onlyRegistrator\n whenNotPaused\n nonReentrant\n returns (bool accountingValid)\n {\n // pause the accounting on failure\n accountingValid = _doAccounting(true);\n }\n\n // slither-disable-start reentrancy-eth\n function _doAccounting(bool pauseOnFail)\n internal\n returns (bool accountingValid)\n {\n if (address(this).balance < consensusRewards) {\n return _failAccounting(pauseOnFail);\n }\n\n // Calculate all the new ETH that has been swept to the contract since the last accounting\n uint256 newSweptETH = address(this).balance - consensusRewards;\n accountingValid = true;\n\n // send the ETH that is from fully withdrawn validators to the Vault\n if (newSweptETH >= FULL_STAKE) {\n uint256 fullyWithdrawnValidators;\n // explicitly cast to uint256 as we want to round to a whole number of validators\n fullyWithdrawnValidators = uint256(newSweptETH / FULL_STAKE);\n activeDepositedValidators -= fullyWithdrawnValidators;\n\n uint256 wethToVault = FULL_STAKE * fullyWithdrawnValidators;\n IWETH9(WETH).deposit{ value: wethToVault }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH).transfer(VAULT_ADDRESS, wethToVault);\n _wethWithdrawnToVault(wethToVault);\n\n emit AccountingFullyWithdrawnValidator(\n fullyWithdrawnValidators,\n activeDepositedValidators,\n wethToVault\n );\n }\n\n uint256 ethRemaining = address(this).balance - consensusRewards;\n // should be less than a whole validator stake\n require(ethRemaining < FULL_STAKE, \"Unexpected accounting\");\n\n // If no Beacon chain consensus rewards swept\n if (ethRemaining == 0) {\n // do nothing\n return accountingValid;\n } else if (ethRemaining < fuseIntervalStart) {\n // Beacon chain consensus rewards swept (partial validator withdrawals)\n // solhint-disable-next-line reentrancy\n consensusRewards += ethRemaining;\n emit AccountingConsensusRewards(ethRemaining);\n } else if (ethRemaining > fuseIntervalEnd) {\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\n IWETH9(WETH).deposit{ value: ethRemaining }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH).transfer(VAULT_ADDRESS, ethRemaining);\n activeDepositedValidators -= 1;\n\n _wethWithdrawnToVault(ethRemaining);\n\n emit AccountingValidatorSlashed(\n activeDepositedValidators,\n ethRemaining\n );\n }\n // Oh no... Fuse is blown. The Strategist needs to adjust the accounting values.\n else {\n return _failAccounting(pauseOnFail);\n }\n }\n\n // slither-disable-end reentrancy-eth\n\n /// @dev pause any further accounting if required and return false\n function _failAccounting(bool pauseOnFail)\n internal\n returns (bool accountingValid)\n {\n // pause if not already\n if (pauseOnFail) {\n _pause();\n }\n // fail the accounting\n accountingValid = false;\n }\n\n /// @notice Allow the Strategist to fix the accounting of this strategy and unpause.\n /// @param _validatorsDelta adjust the active validators by up to plus three or minus three\n /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down\n /// @param _ethToVaultAmount the amount of ETH that gets wrapped into WETH and sent to the Vault\n /// @dev There is a case when a validator(s) gets slashed so much that the eth swept from\n /// the beacon chain enters the fuse area and there are no consensus rewards on the contract\n /// to \"dip into\"/use. To increase the amount of unaccounted ETH over the fuse end interval\n /// we need to reduce the amount of active deposited validators and immediately send WETH\n /// to the vault, so it doesn't interfere with further accounting.\n function manuallyFixAccounting(\n int256 _validatorsDelta,\n int256 _consensusRewardsDelta,\n uint256 _ethToVaultAmount\n ) external onlyStrategist whenPaused nonReentrant {\n require(\n lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE <\n block.number,\n \"Fix accounting called too soon\"\n );\n require(\n _validatorsDelta >= -3 &&\n _validatorsDelta <= 3 &&\n // new value must be positive\n int256(activeDepositedValidators) + _validatorsDelta >= 0,\n \"Invalid validatorsDelta\"\n );\n require(\n _consensusRewardsDelta >= -332 ether &&\n _consensusRewardsDelta <= 332 ether &&\n // new value must be positive\n int256(consensusRewards) + _consensusRewardsDelta >= 0,\n \"Invalid consensusRewardsDelta\"\n );\n require(_ethToVaultAmount <= 32 ether * 3, \"Invalid wethToVaultAmount\");\n\n activeDepositedValidators = uint256(\n int256(activeDepositedValidators) + _validatorsDelta\n );\n consensusRewards = uint256(\n int256(consensusRewards) + _consensusRewardsDelta\n );\n lastFixAccountingBlockNumber = block.number;\n if (_ethToVaultAmount > 0) {\n IWETH9(WETH).deposit{ value: _ethToVaultAmount }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH).transfer(VAULT_ADDRESS, _ethToVaultAmount);\n _wethWithdrawnToVault(_ethToVaultAmount);\n }\n\n emit AccountingManuallyFixed(\n _validatorsDelta,\n _consensusRewardsDelta,\n _ethToVaultAmount\n );\n\n // rerun the accounting to see if it has now been fixed.\n // Do not pause the accounting on failure as it is already paused\n require(_doAccounting(false), \"Fuse still blown\");\n\n // unpause since doAccounting was successful\n _unpause();\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n /// @dev allows for NativeStakingSSVStrategy contract to emit the Withdrawal event\n function _wethWithdrawnToVault(uint256 _amount) internal virtual;\n}\n" + }, + "contracts/strategies/NativeStaking/ValidatorRegistrator.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { Governable } from \"../../governance/Governable.sol\";\nimport { IDepositContract } from \"../../interfaces/IDepositContract.sol\";\nimport { IVault } from \"../../interfaces/IVault.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { ISSVNetwork, Cluster } from \"../../interfaces/ISSVNetwork.sol\";\nimport { BeaconConsolidation } from \"../../beacon/BeaconConsolidation.sol\";\n\nstruct ValidatorStakeData {\n bytes pubkey;\n bytes signature;\n bytes32 depositDataRoot;\n}\n\n/**\n * @title Registrator of the validators\n * @notice This contract implements all the required functionality to register, exit and remove validators.\n * @author Origin Protocol Inc\n */\nabstract contract ValidatorRegistrator is Governable, Pausable {\n /// @notice The maximum amount of ETH that can be staked by a validator\n /// @dev this can change in the future with EIP-7251, Increase the MAX_EFFECTIVE_BALANCE\n uint256 public constant FULL_STAKE = 32 ether;\n\n /// @notice The address of the Wrapped ETH (WETH) token contract\n address public immutable WETH;\n /// @notice The address of the beacon chain deposit contract\n address public immutable BEACON_CHAIN_DEPOSIT_CONTRACT;\n /// @notice The address of the SSV Network contract used to interface with\n address public immutable SSV_NETWORK;\n /// @notice Address of the OETH Vault proxy contract\n address public immutable VAULT_ADDRESS;\n /// @notice Maximum number of validators that can be registered in this strategy\n uint256 public immutable MAX_VALIDATORS;\n\n /// @notice Address of the registrator - allowed to register, exit and remove validators\n address public validatorRegistrator;\n /// @notice The number of validators that have 32 (!) ETH actively deposited. When a new deposit\n /// to a validator happens this number increases, when a validator exit is detected this number\n /// decreases.\n uint256 public activeDepositedValidators;\n /// @notice State of the validators keccak256(pubKey) => state\n mapping(bytes32 => VALIDATOR_STATE) public validatorsStates;\n /// @notice The account that is allowed to reset stakeETHTally\n address public stakingMonitor;\n /// @notice Amount of ETH that can be staked before staking on the contract is suspended\n /// and the `stakingMonitor` needs to approve further staking by calling `resetStakeETHTally`\n uint256 public stakeETHThreshold;\n /// @notice Amount of ETH that has been staked since the `stakingMonitor` last called `resetStakeETHTally`.\n /// This can not go above `stakeETHThreshold`.\n uint256 public stakeETHTally;\n // For future use\n uint256[47] private __gap;\n\n enum VALIDATOR_STATE {\n NON_REGISTERED, // validator is not registered on the SSV network\n REGISTERED, // validator is registered on the SSV network\n STAKED, // validator has funds staked\n EXITING, // exit message has been posted and validator is in the process of exiting\n EXIT_COMPLETE // validator has funds withdrawn to the EigenPod and is removed from the SSV\n }\n\n event RegistratorChanged(address indexed newAddress);\n event StakingMonitorChanged(address indexed newAddress);\n event ETHStaked(bytes32 indexed pubKeyHash, bytes pubKey, uint256 amount);\n event SSVValidatorRegistered(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint64[] operatorIds\n );\n event SSVValidatorExitInitiated(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint64[] operatorIds\n );\n event SSVValidatorExitCompleted(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint64[] operatorIds\n );\n event ConsolidationRequested(\n bytes[] sourcePubKeys,\n bytes targetPubKey,\n uint256 consolidationCount\n );\n event ConsolidationFailed(\n bytes[] sourcePubKeys,\n uint256 consolidationCount\n );\n event ConsolidationConfirmed(\n uint256 consolidationCount,\n uint256 activeDepositedValidators\n );\n event StakeETHThresholdChanged(uint256 amount);\n event StakeETHTallyReset();\n\n /// @dev Throws if called by any account other than the Registrator\n modifier onlyRegistrator() {\n require(\n msg.sender == validatorRegistrator,\n \"Caller is not the Registrator\"\n );\n _;\n }\n\n /// @dev Throws if called by any account other than the Staking monitor\n modifier onlyStakingMonitor() {\n require(msg.sender == stakingMonitor, \"Caller is not the Monitor\");\n _;\n }\n\n /// @dev Throws if called by any account other than the Strategist\n modifier onlyStrategist() {\n require(\n msg.sender == IVault(VAULT_ADDRESS).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n _;\n }\n\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _vaultAddress Address of the Vault\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _maxValidators Maximum number of validators that can be registered in the strategy\n constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork,\n uint256 _maxValidators\n ) {\n WETH = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK = _ssvNetwork;\n VAULT_ADDRESS = _vaultAddress;\n MAX_VALIDATORS = _maxValidators;\n }\n\n /// @notice Set the address of the registrator which can register, exit and remove validators\n function setRegistrator(address _address) external onlyGovernor {\n validatorRegistrator = _address;\n emit RegistratorChanged(_address);\n }\n\n /// @notice Set the address of the staking monitor that is allowed to reset stakeETHTally\n function setStakingMonitor(address _address) external onlyGovernor {\n stakingMonitor = _address;\n emit StakingMonitorChanged(_address);\n }\n\n /// @notice Set the amount of ETH that can be staked before staking monitor\n // needs to a approve further staking by resetting the stake ETH tally\n function setStakeETHThreshold(uint256 _amount) external onlyGovernor {\n stakeETHThreshold = _amount;\n emit StakeETHThresholdChanged(_amount);\n }\n\n /// @notice Reset the stakeETHTally\n function resetStakeETHTally() external onlyStakingMonitor {\n stakeETHTally = 0;\n emit StakeETHTallyReset();\n }\n\n /// @notice Stakes WETH to the node validators\n /// @param validators A list of validator data needed to stake.\n /// The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot.\n /// Only the registrator can call this function.\n // slither-disable-start reentrancy-eth\n function stakeEth(ValidatorStakeData[] calldata validators)\n external\n onlyRegistrator\n whenNotPaused\n nonReentrant\n {\n uint256 requiredETH = validators.length * FULL_STAKE;\n\n // Check there is enough WETH from the deposits sitting in this strategy contract\n require(\n requiredETH <= IWETH9(WETH).balanceOf(address(this)),\n \"Insufficient WETH\"\n );\n require(\n activeDepositedValidators + validators.length <= MAX_VALIDATORS,\n \"Max validators reached\"\n );\n\n require(\n stakeETHTally + requiredETH <= stakeETHThreshold,\n \"Staking ETH over threshold\"\n );\n stakeETHTally += requiredETH;\n\n // Convert required ETH from WETH\n IWETH9(WETH).withdraw(requiredETH);\n _wethWithdrawn(requiredETH);\n\n /* 0x01 to indicate that withdrawal credentials will contain an EOA address that the sweeping function\n * can sweep funds to.\n * bytes11(0) to fill up the required zeros\n * remaining bytes20 are for the address\n */\n bytes memory withdrawalCredentials = abi.encodePacked(\n bytes1(0x01),\n bytes11(0),\n address(this)\n );\n\n // For each validator\n for (uint256 i = 0; i < validators.length; ++i) {\n bytes32 pubKeyHash = keccak256(validators[i].pubkey);\n\n require(\n validatorsStates[pubKeyHash] == VALIDATOR_STATE.REGISTERED,\n \"Validator not registered\"\n );\n\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\n value: FULL_STAKE\n }(\n validators[i].pubkey,\n withdrawalCredentials,\n validators[i].signature,\n validators[i].depositDataRoot\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.STAKED;\n\n emit ETHStaked(pubKeyHash, validators[i].pubkey, FULL_STAKE);\n }\n // save gas by changing this storage variable only once rather each time in the loop.\n activeDepositedValidators += validators.length;\n }\n\n // slither-disable-end reentrancy-eth\n\n /// @notice Registers a new validator in the SSV Cluster.\n /// Only the registrator can call this function.\n /// @param publicKeys The public keys of the validators\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param sharesData The shares data for each validator\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n // slither-disable-start reentrancy-no-eth\n function registerSsvValidators(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds,\n bytes[] calldata sharesData,\n Cluster calldata cluster\n ) external payable onlyRegistrator whenNotPaused {\n require(\n publicKeys.length == sharesData.length,\n \"Pubkey sharesData mismatch\"\n );\n // Check each public key has not already been used\n bytes32 pubKeyHash;\n VALIDATOR_STATE currentState;\n for (uint256 i = 0; i < publicKeys.length; ++i) {\n pubKeyHash = keccak256(publicKeys[i]);\n currentState = validatorsStates[pubKeyHash];\n require(\n currentState == VALIDATOR_STATE.NON_REGISTERED,\n \"Validator already registered\"\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.REGISTERED;\n\n emit SSVValidatorRegistered(pubKeyHash, publicKeys[i], operatorIds);\n }\n\n ISSVNetwork(SSV_NETWORK).bulkRegisterValidator{ value: msg.value }(\n publicKeys,\n operatorIds,\n sharesData,\n cluster\n );\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Exit a validator from the Beacon chain.\n /// The staked ETH will eventually swept to this native staking strategy.\n /// Only the registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n // slither-disable-start reentrancy-no-eth\n function exitSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external onlyRegistrator whenNotPaused {\n bytes32 pubKeyHash = keccak256(publicKey);\n VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];\n require(currentState == VALIDATOR_STATE.STAKED, \"Validator not staked\");\n\n ISSVNetwork(SSV_NETWORK).exitValidator(publicKey, operatorIds);\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXITING;\n\n emit SSVValidatorExitInitiated(pubKeyHash, publicKey, operatorIds);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Remove a validator from the SSV Cluster.\n /// Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain.\n /// If removed before the validator has exited the beacon chain will result in the validator being slashed.\n /// Only the registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n // slither-disable-start reentrancy-no-eth\n function removeSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n bytes32 pubKeyHash = keccak256(publicKey);\n VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];\n // Can remove SSV validators that were incorrectly registered and can not be deposited to.\n require(\n currentState == VALIDATOR_STATE.EXITING ||\n currentState == VALIDATOR_STATE.REGISTERED,\n \"Validator not regd or exiting\"\n );\n\n ISSVNetwork(SSV_NETWORK).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXIT_COMPLETE;\n\n emit SSVValidatorExitCompleted(pubKeyHash, publicKey, operatorIds);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Migrate the SSV cluster to use ETH for payment instead of SSV tokens.\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n function migrateClusterToETH(\n uint64[] memory operatorIds,\n Cluster memory cluster\n ) external payable onlyGovernor {\n ISSVNetwork(SSV_NETWORK).migrateClusterToETH{ value: msg.value }(\n operatorIds,\n cluster\n );\n\n // The SSV Network emits\n // ClusterMigratedToETH(msg.sender, operatorIds, msg.value, ssvClusterBalance, effectiveBalance, cluster)\n }\n\n /***************************************\n Consolidation functions\n ****************************************/\n\n /**\n * @notice Initiates the consolidation of multiple source sweeping validators to a single compounding validator.\n * @dev The validator registrator should be set to the ConsolidationController contract which\n * has checks against the target validator.\n * @param sourcePubKeys The full public keys of the source validators to be consolidated.\n * @param targetPubKey The full public key of the target validator to consolidate into.\n */\n // slither-disable-start reentrancy-no-eth\n function requestConsolidation(\n bytes[] calldata sourcePubKeys,\n bytes calldata targetPubKey\n ) external payable nonReentrant whenNotPaused onlyRegistrator {\n // Hash using the Native Staking Strategy's hashing method.\n // This is different to the Beacon chain's method.\n bytes32 targetPubKeyHash = keccak256(targetPubKey);\n bytes32 sourcePubKeyHash;\n uint256 totalConsolidationFees = 0;\n\n // For each source validator\n for (uint256 i = 0; i < sourcePubKeys.length; ++i) {\n sourcePubKeyHash = keccak256(sourcePubKeys[i]);\n require(sourcePubKeys[i].length == 48, \"Invalid source public key\");\n require(sourcePubKeyHash != targetPubKeyHash, \"Self consolidation\");\n require(\n validatorsStates[sourcePubKeyHash] == VALIDATOR_STATE.STAKED,\n \"Source validator not staked\"\n );\n\n // Store the state of the source validator as exiting so it can be removed\n // after the consolidation is confirmed\n validatorsStates[sourcePubKeyHash] = VALIDATOR_STATE.EXITING;\n\n // Request consolidation from source to target validator\n totalConsolidationFees += BeaconConsolidation.request(\n sourcePubKeys[i],\n targetPubKey\n );\n }\n\n require(\n totalConsolidationFees <= msg.value,\n \"Insufficient consolidation fee\"\n );\n\n emit ConsolidationRequested(\n sourcePubKeys,\n targetPubKey,\n sourcePubKeys.length\n );\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /**\n * @notice A consolidation request can fail to be processed on the beacon chain\n * for various reasons. For example, the pending consolidation queue is full with 262,144 requests.\n * This restores the validator states back to STAKED so they can be consolidated again or exited.\n * @param sourcePubKeys The full public keys of the source validators that failed to be consolidated.\n */\n function failConsolidation(bytes[] calldata sourcePubKeys)\n external\n nonReentrant\n whenNotPaused\n onlyRegistrator\n {\n bytes32 sourcePubKeyHash;\n\n // For each failed source validator\n for (uint256 i = 0; i < sourcePubKeys.length; ++i) {\n require(sourcePubKeys[i].length == 48, \"Invalid source public key\");\n sourcePubKeyHash = keccak256(sourcePubKeys[i]);\n require(\n validatorsStates[sourcePubKeyHash] == VALIDATOR_STATE.EXITING,\n \"Source validator not exiting\"\n );\n\n // Store the state of the source validator back to staked\n validatorsStates[sourcePubKeyHash] = VALIDATOR_STATE.STAKED;\n }\n\n emit ConsolidationFailed(sourcePubKeys, sourcePubKeys.length);\n }\n\n /**\n * @notice Confirms that a consolidation has completed successfully on the beacon chain.\n * This reduces the number of active deposited validators managed by this strategy which\n * reduces the strategy's balance.\n * @param consolidationCount The number of source validators that were consolidated.\n */\n function confirmConsolidation(uint256 consolidationCount)\n external\n nonReentrant\n whenNotPaused\n onlyRegistrator\n {\n // Store the reduced number of active deposited validators\n // managed by this strategy\n activeDepositedValidators -= consolidationCount;\n\n emit ConsolidationConfirmed(\n consolidationCount,\n activeDepositedValidators\n );\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n /// @dev Called when WETH is withdrawn from the strategy or staked to a validator so\n /// the strategy knows how much WETH it has on deposit.\n /// This is so it can emit the correct amount in the Deposit event in depositAll().\n function _wethWithdrawn(uint256 _amount) internal virtual;\n}\n" + }, + "contracts/strategies/sonic/SonicStakingStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SonicValidatorDelegator } from \"./SonicValidatorDelegator.sol\";\nimport { IWrappedSonic } from \"../../interfaces/sonic/IWrappedSonic.sol\";\n\n/**\n * @title Staking Strategy for Sonic's native S currency\n * @author Origin Protocol Inc\n */\ncontract SonicStakingStrategy is SonicValidatorDelegator {\n // For future use\n uint256[50] private __gap;\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _wrappedSonic,\n address _sfc\n ) SonicValidatorDelegator(_baseConfig, _wrappedSonic, _sfc) {}\n\n /// @notice Deposit wrapped S asset into the underlying platform.\n /// @param _asset Address of asset to deposit. Has to be Wrapped Sonic (wS).\n /// @param _amount Amount of assets that were transferred to the strategy by the vault.\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n require(_asset == wrappedSonic, \"Unsupported asset\");\n _deposit(_asset, _amount);\n }\n\n /**\n * @notice Deposit Wrapped Sonic (wS) to this strategy and delegate to a validator.\n * @param _asset Address of Wrapped Sonic (wS) token\n * @param _amount Amount of Wrapped Sonic (wS) to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal virtual {\n require(_amount > 0, \"Must deposit something\");\n\n _delegate(_amount);\n emit Deposit(_asset, address(0), _amount);\n }\n\n /**\n * @notice Deposit the entire balance of wrapped S in this strategy contract into\n * the underlying platform.\n */\n function depositAll() external virtual override onlyVault nonReentrant {\n uint256 wSBalance = IERC20(wrappedSonic).balanceOf(address(this));\n\n if (wSBalance > 0) {\n _deposit(wrappedSonic, wSBalance);\n }\n }\n\n /// @notice Withdraw Wrapped Sonic (wS) from this strategy contract.\n /// Used only if some wS is lingering on the contract.\n /// That can happen only when someone sends wS directly to this contract\n /// @param _recipient Address to receive withdrawn assets\n /// @param _asset Address of the Wrapped Sonic (wS) token\n /// @param _amount Amount of Wrapped Sonic (wS) to withdraw\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_asset == wrappedSonic, \"Unsupported asset\");\n _withdraw(_recipient, _asset, _amount);\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal override {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n // slither-disable-next-line unchecked-transfer unused-return\n IERC20(_asset).transfer(_recipient, _amount);\n\n emit Withdrawal(wrappedSonic, address(0), _amount);\n }\n\n /// @notice Transfer all Wrapped Sonic (wS) deposits back to the vault.\n /// This does not withdraw from delegated validators. That has to be done separately with `undelegate`.\n /// Any native S in this strategy will be withdrawn.\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 balance = address(this).balance;\n if (balance > 0) {\n IWrappedSonic(wrappedSonic).deposit{ value: balance }();\n }\n uint256 wSBalance = IERC20(wrappedSonic).balanceOf(address(this));\n if (wSBalance > 0) {\n _withdraw(vaultAddress, wrappedSonic, wSBalance);\n }\n }\n\n /**\n * @dev Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset token\n */\n function supportsAsset(address _asset)\n public\n view\n virtual\n override\n returns (bool)\n {\n return _asset == wrappedSonic;\n }\n\n /**\n * @notice is not supported for this strategy as the\n * Wrapped Sonic (wS) token is set at deploy time.\n */\n function setPTokenAddress(address, address)\n external\n view\n override\n onlyGovernor\n {\n revert(\"unsupported function\");\n }\n\n /// @notice is not used by this strategy as all staking rewards are restaked\n function collectRewardTokens() external override nonReentrant {\n revert(\"unsupported function\");\n }\n\n /**\n * @notice is not supported for this strategy as the\n * Wrapped Sonic (wS) token is set at deploy time.\n */\n function removePToken(uint256) external view override onlyGovernor {\n revert(\"unsupported function\");\n }\n\n /// @dev is not used by this strategy but must be implemented as it's abstract\n /// in the inherited `InitializableAbstractStrategy` contract.\n function _abstractSetPToken(address, address) internal virtual override {}\n\n /// @notice is not used by this strategy\n function safeApproveAllTokens() external override onlyGovernor {}\n}\n" + }, + "contracts/strategies/sonic/SonicSwapXAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title SwapX Algorithmic Market Maker (AMO) Strategy\n * @notice AMO strategy for the SwapX OS/wS stable pool\n * @author Origin Protocol Inc\n */\nimport { StableSwapAMMStrategy } from \"../algebra/StableSwapAMMStrategy.sol\";\nimport { IGauge } from \"../../interfaces/algebra/IAlgebraGauge.sol\";\n\ncontract SonicSwapXAMOStrategy is StableSwapAMMStrategy {\n /**\n * @param _baseConfig The `platformAddress` is the address of the SwapX pool.\n * The `vaultAddress` is the address of the Origin Sonic Vault.\n * @param _gauge Address of the SwapX gauge for the pool.\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _gauge)\n StableSwapAMMStrategy(_baseConfig, _gauge, IGauge(_gauge).TOKEN())\n {}\n}\n" + }, + "contracts/strategies/sonic/SonicValidatorDelegator.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IVault } from \"../../interfaces/IVault.sol\";\nimport { ISFC } from \"../../interfaces/sonic/ISFC.sol\";\nimport { IWrappedSonic } from \"../../interfaces/sonic/IWrappedSonic.sol\";\n\n/**\n * @title Manages delegation to Sonic validators\n * @notice This contract implements all the required functionality to delegate to,\n undelegate from and withdraw from validators.\n * @author Origin Protocol Inc\n */\nabstract contract SonicValidatorDelegator is InitializableAbstractStrategy {\n /// @notice Address of Sonic's wrapped S token\n address public immutable wrappedSonic;\n /// @notice Sonic's Special Fee Contract (SFC)\n ISFC public immutable sfc;\n\n /// @notice a unique ID for each withdrawal request\n uint256 public nextWithdrawId;\n /// @notice Sonic (S) that is pending withdrawal after undelegating\n uint256 public pendingWithdrawals;\n\n /// @notice List of supported validator IDs that can be delegated to\n uint256[] public supportedValidators;\n\n /// @notice Default validator id to deposit to\n uint256 public defaultValidatorId;\n\n struct WithdrawRequest {\n uint256 validatorId;\n uint256 undelegatedAmount;\n uint256 timestamp;\n }\n /// @notice Mapping of withdrawIds to validatorIds and undelegatedAmounts\n mapping(uint256 => WithdrawRequest) public withdrawals;\n\n /// @notice Address of the registrator - allowed to register, exit and remove validators\n address public validatorRegistrator;\n\n // For future use\n uint256[44] private __gap;\n\n event Delegated(uint256 indexed validatorId, uint256 delegatedAmount);\n event Undelegated(\n uint256 indexed withdrawId,\n uint256 indexed validatorId,\n uint256 undelegatedAmount\n );\n event Withdrawn(\n uint256 indexed withdrawId,\n uint256 indexed validatorId,\n uint256 undelegatedAmount,\n uint256 withdrawnAmount\n );\n event RegistratorChanged(address indexed newAddress);\n event SupportedValidator(uint256 indexed validatorId);\n event UnsupportedValidator(uint256 indexed validatorId);\n event DefaultValidatorIdChanged(uint256 indexed validatorId);\n\n /// @dev Throws if called by any account other than the Registrator or Strategist\n modifier onlyRegistratorOrStrategist() {\n require(\n msg.sender == validatorRegistrator ||\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Registrator or Strategist\"\n );\n _;\n }\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _wrappedSonic,\n address _sfc\n ) InitializableAbstractStrategy(_baseConfig) {\n wrappedSonic = _wrappedSonic;\n sfc = ISFC(_sfc);\n }\n\n function initialize() external virtual onlyGovernor initializer {\n address[] memory rewardTokens = new address[](0);\n address[] memory assets = new address[](1);\n address[] memory pTokens = new address[](1);\n\n assets[0] = address(wrappedSonic);\n pTokens[0] = address(platformAddress);\n\n InitializableAbstractStrategy._initialize(\n rewardTokens,\n assets,\n pTokens\n );\n }\n\n /// @notice Returns the total value of Sonic (S) that is delegated validators.\n /// Wrapped Sonic (wS) deposits that are still to be delegated and any undelegated amounts\n /// still pending a withdrawal.\n /// @param _asset Address of Wrapped Sonic (wS) token\n /// @return balance Total value managed by the strategy\n function checkBalance(address _asset)\n external\n view\n virtual\n override\n returns (uint256 balance)\n {\n require(_asset == wrappedSonic, \"Unsupported asset\");\n\n // add the Wrapped Sonic (wS) in the strategy from deposits that are still to be delegated\n // and any undelegated amounts still pending a withdrawal\n balance =\n IERC20(wrappedSonic).balanceOf(address(this)) +\n pendingWithdrawals;\n\n // For each supported validator, get the staked amount and pending rewards\n uint256 validatorLen = supportedValidators.length;\n for (uint256 i = 0; i < validatorLen; i++) {\n uint256 validator = supportedValidators[i];\n balance += sfc.getStake(address(this), validator);\n balance += sfc.pendingRewards(address(this), validator);\n }\n }\n\n /**\n * @dev Delegate from this strategy to a specific Sonic validator. Called\n * automatically on asset deposit\n * @param _amount the amount of Sonic (S) to delegate.\n */\n function _delegate(uint256 _amount) internal {\n require(\n isSupportedValidator(defaultValidatorId),\n \"Validator not supported\"\n );\n\n // unwrap Wrapped Sonic (wS) to native Sonic (S)\n IWrappedSonic(wrappedSonic).withdraw(_amount);\n\n //slither-disable-next-line arbitrary-send-eth\n sfc.delegate{ value: _amount }(defaultValidatorId);\n\n emit Delegated(defaultValidatorId, _amount);\n }\n\n /**\n * @notice Undelegate from a specific Sonic validator.\n * This needs to be followed by a `withdrawFromSFC` two weeks later.\n * @param _validatorId The Sonic validator ID to undelegate from.\n * @param _undelegateAmount the amount of Sonic (S) to undelegate.\n * @return withdrawId The unique ID of the withdrawal request.\n */\n function undelegate(uint256 _validatorId, uint256 _undelegateAmount)\n external\n onlyRegistratorOrStrategist\n nonReentrant\n returns (uint256 withdrawId)\n {\n withdrawId = _undelegate(_validatorId, _undelegateAmount);\n }\n\n function _undelegate(uint256 _validatorId, uint256 _undelegateAmount)\n internal\n returns (uint256 withdrawId)\n {\n // Can still undelegate even if the validator is no longer supported\n require(_undelegateAmount > 0, \"Must undelegate something\");\n\n uint256 amountDelegated = sfc.getStake(address(this), _validatorId);\n require(\n _undelegateAmount <= amountDelegated,\n \"Insufficient delegation\"\n );\n\n withdrawId = nextWithdrawId++;\n\n withdrawals[withdrawId] = WithdrawRequest(\n _validatorId,\n _undelegateAmount,\n block.timestamp\n );\n pendingWithdrawals += _undelegateAmount;\n\n sfc.undelegate(_validatorId, withdrawId, _undelegateAmount);\n\n emit Undelegated(withdrawId, _validatorId, _undelegateAmount);\n }\n\n /**\n * @notice Withdraw native S from a previously undelegated validator.\n * The native S is wrapped wS and transferred to the Vault.\n * @param _withdrawId The unique withdraw ID used to `undelegate`\n * @return withdrawnAmount The amount of Sonic (S) withdrawn.\n * This can be less than the undelegated amount in the event of slashing.\n */\n function withdrawFromSFC(uint256 _withdrawId)\n external\n onlyRegistratorOrStrategist\n nonReentrant\n returns (uint256 withdrawnAmount)\n {\n require(_withdrawId < nextWithdrawId, \"Invalid withdrawId\");\n\n // Can still withdraw even if the validator is no longer supported\n // Load the withdrawal from storage into memory\n WithdrawRequest memory withdrawal = withdrawals[_withdrawId];\n require(!isWithdrawnFromSFC(_withdrawId), \"Already withdrawn\");\n\n withdrawals[_withdrawId].undelegatedAmount = 0;\n pendingWithdrawals -= withdrawal.undelegatedAmount;\n\n uint256 sBalanceBefore = address(this).balance;\n\n // Try to withdraw from SFC\n try sfc.withdraw(withdrawal.validatorId, _withdrawId) {\n // continue below\n } catch (bytes memory err) {\n bytes4 errorSelector = bytes4(err);\n\n // If the validator has been fully slashed, SFC's withdraw function will\n // revert with a StakeIsFullySlashed custom error.\n if (errorSelector == ISFC.StakeIsFullySlashed.selector) {\n // The validator was fully slashed, so all the delegated amounts were lost.\n // Will swallow the error as we still want to update the\n // withdrawals and pendingWithdrawals storage variables.\n\n // The return param defaults to zero but lets set it explicitly so it's clear\n withdrawnAmount = 0;\n\n emit Withdrawn(\n _withdrawId,\n withdrawal.validatorId,\n withdrawal.undelegatedAmount,\n withdrawnAmount\n );\n\n // Exit here as there is nothing to transfer to the Vault\n return withdrawnAmount;\n } else {\n // Bubble up any other SFC custom errors.\n // Inline assembly is currently the only way to generically rethrow the exact same custom error\n // from the raw bytes err in a catch block while preserving its original selector and parameters.\n // solhint-disable-next-line no-inline-assembly\n assembly {\n revert(add(32, err), mload(err))\n }\n }\n }\n\n // Set return parameter\n withdrawnAmount = address(this).balance - sBalanceBefore;\n\n // Wrap Sonic (S) to Wrapped Sonic (wS)\n IWrappedSonic(wrappedSonic).deposit{ value: withdrawnAmount }();\n\n // Transfer the Wrapped Sonic (wS) to the Vault\n _withdraw(vaultAddress, wrappedSonic, withdrawnAmount);\n\n // withdrawal.undelegatedAmount & withdrawnAmount can differ in case of slashing\n emit Withdrawn(\n _withdrawId,\n withdrawal.validatorId,\n withdrawal.undelegatedAmount,\n withdrawnAmount\n );\n }\n\n /// @notice returns a bool whether a withdrawalId has already been withdrawn or not\n /// @param _withdrawId The unique withdraw ID used to `undelegate`\n function isWithdrawnFromSFC(uint256 _withdrawId)\n public\n view\n returns (bool)\n {\n WithdrawRequest memory withdrawal = withdrawals[_withdrawId];\n require(withdrawal.validatorId > 0, \"Invalid withdrawId\");\n return withdrawal.undelegatedAmount == 0;\n }\n\n /**\n * @notice Restake any pending validator rewards for all supported validators\n * @param _validatorIds List of Sonic validator IDs to restake rewards\n */\n function restakeRewards(uint256[] calldata _validatorIds)\n external\n nonReentrant\n {\n for (uint256 i = 0; i < _validatorIds.length; ++i) {\n require(\n isSupportedValidator(_validatorIds[i]),\n \"Validator not supported\"\n );\n\n uint256 rewards = sfc.pendingRewards(\n address(this),\n _validatorIds[i]\n );\n\n if (rewards > 0) {\n sfc.restakeRewards(_validatorIds[i]);\n }\n }\n\n // The SFC contract will emit Delegated and RestakedRewards events.\n // The checkBalance function should not change as the pending rewards will moved to the staked amount.\n }\n\n /**\n * @notice Claim any pending rewards from validators\n * @param _validatorIds List of Sonic validator IDs to claim rewards\n */\n function collectRewards(uint256[] calldata _validatorIds)\n external\n onlyRegistratorOrStrategist\n nonReentrant\n {\n uint256 sBalanceBefore = address(this).balance;\n\n for (uint256 i = 0; i < _validatorIds.length; ++i) {\n uint256 rewards = sfc.pendingRewards(\n address(this),\n _validatorIds[i]\n );\n\n if (rewards > 0) {\n // The SFC contract will emit ClaimedRewards(delegator (this), validatorId, rewards)\n sfc.claimRewards(_validatorIds[i]);\n }\n }\n\n uint256 rewardsAmount = address(this).balance - sBalanceBefore;\n\n // Wrap Sonic (S) to Wrapped Sonic (wS)\n IWrappedSonic(wrappedSonic).deposit{ value: rewardsAmount }();\n\n // Transfer the Wrapped Sonic (wS) to the Vault\n _withdraw(vaultAddress, wrappedSonic, rewardsAmount);\n }\n\n /**\n * @notice To receive native S from SFC and Wrapped Sonic (wS)\n *\n * @dev This does not prevent donating S tokens to the contract\n * as wrappedSonic has a `withdrawTo` function where a third party\n * owner of wrappedSonic can withdraw to this contract.\n */\n receive() external payable {\n require(\n msg.sender == address(sfc) || msg.sender == wrappedSonic,\n \"S not from allowed contracts\"\n );\n }\n\n /***************************************\n Admin functions\n ****************************************/\n\n /// @notice Set the address of the Registrator which can undelegate, withdraw and collect rewards\n /// @param _validatorRegistrator The address of the Registrator\n function setRegistrator(address _validatorRegistrator)\n external\n onlyGovernor\n {\n validatorRegistrator = _validatorRegistrator;\n emit RegistratorChanged(_validatorRegistrator);\n }\n\n /// @notice Set the default validatorId to delegate to on deposit\n /// @param _validatorId The validator identifier. eg 18\n function setDefaultValidatorId(uint256 _validatorId)\n external\n onlyRegistratorOrStrategist\n {\n require(isSupportedValidator(_validatorId), \"Validator not supported\");\n defaultValidatorId = _validatorId;\n emit DefaultValidatorIdChanged(_validatorId);\n }\n\n /// @notice Allows a validator to be delegated to by the Registrator\n /// @param _validatorId The validator identifier. eg 18\n function supportValidator(uint256 _validatorId) external onlyGovernor {\n require(\n !isSupportedValidator(_validatorId),\n \"Validator already supported\"\n );\n\n supportedValidators.push(_validatorId);\n\n emit SupportedValidator(_validatorId);\n }\n\n /// @notice Removes a validator from the supported list.\n /// Unsupported validators can still be undelegated from, withdrawn from and rewards collected.\n /// @param _validatorId The validator identifier. eg 18\n function unsupportValidator(uint256 _validatorId) external onlyGovernor {\n require(isSupportedValidator(_validatorId), \"Validator not supported\");\n\n uint256 validatorLen = supportedValidators.length;\n for (uint256 i = 0; i < validatorLen; ++i) {\n if (supportedValidators[i] == _validatorId) {\n supportedValidators[i] = supportedValidators[validatorLen - 1];\n supportedValidators.pop();\n break;\n }\n }\n\n uint256 stake = sfc.getStake(address(this), _validatorId);\n\n // undelegate if validator still has funds staked\n if (stake > 0) {\n _undelegate(_validatorId, stake);\n }\n emit UnsupportedValidator(_validatorId);\n }\n\n /// @notice Returns the length of the supportedValidators array\n function supportedValidatorsLength() external view returns (uint256) {\n return supportedValidators.length;\n }\n\n /// @notice Returns whether a validator is supported by this strategy\n /// @param _validatorId The validator identifier\n function isSupportedValidator(uint256 _validatorId)\n public\n view\n returns (bool)\n {\n uint256 validatorLen = supportedValidators.length;\n for (uint256 i = 0; i < validatorLen; ++i) {\n if (supportedValidators[i] == _validatorId) {\n return true;\n }\n }\n return false;\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal virtual;\n}\n" + }, + "contracts/strategies/VaultValueChecker.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IOUSD } from \"../interfaces/IOUSD.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract VaultValueChecker {\n IVault public immutable vault;\n IOUSD public immutable ousd;\n // Snapshot expiration time in seconds.\n // Used to prevent accidental use of an old snapshot, but\n // is not zero to allow easy testing of strategist actions in fork testing\n uint256 constant SNAPSHOT_EXPIRES = 5 * 60;\n\n struct Snapshot {\n uint256 vaultValue;\n uint256 totalSupply;\n uint256 time;\n }\n // By doing per user snapshots, we prevent a reentrancy attack\n // from a third party that updates the snapshot in the middle\n // of an allocation process\n\n mapping(address => Snapshot) public snapshots;\n\n constructor(address _vault, address _ousd) {\n vault = IVault(_vault);\n ousd = IOUSD(_ousd);\n }\n\n function takeSnapshot() external {\n snapshots[msg.sender] = Snapshot({\n vaultValue: vault.totalValue(),\n totalSupply: ousd.totalSupply(),\n time: block.timestamp\n });\n }\n\n function checkDelta(\n int256 expectedProfit,\n int256 profitVariance,\n int256 expectedVaultChange,\n int256 vaultChangeVariance\n ) external {\n // Intentionaly not view so that this method shows up in TX builders\n Snapshot memory snapshot = snapshots[msg.sender];\n int256 vaultChange = toInt256(vault.totalValue()) -\n toInt256(snapshot.vaultValue);\n int256 supplyChange = toInt256(ousd.totalSupply()) -\n toInt256(snapshot.totalSupply);\n int256 profit = vaultChange - supplyChange;\n\n require(\n snapshot.time >= block.timestamp - SNAPSHOT_EXPIRES,\n \"Snapshot too old\"\n );\n require(snapshot.time <= block.timestamp, \"Snapshot too new\");\n require(profit >= expectedProfit - profitVariance, \"Profit too low\");\n require(profit <= expectedProfit + profitVariance, \"Profit too high\");\n require(\n vaultChange >= expectedVaultChange - vaultChangeVariance,\n \"Vault value change too low\"\n );\n require(\n vaultChange <= expectedVaultChange + vaultChangeVariance,\n \"Vault value change too high\"\n );\n }\n\n function toInt256(uint256 value) internal pure returns (int256) {\n // From openzeppelin math/SafeCast.sol\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(\n value <= uint256(type(int256).max),\n \"SafeCast: value doesn't fit in an int256\"\n );\n return int256(value);\n }\n}\n\ncontract OETHVaultValueChecker is VaultValueChecker {\n constructor(address _vault, address _ousd)\n VaultValueChecker(_vault, _ousd)\n {}\n}\n" + }, + "contracts/token/OETH.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { OUSD } from \"./OUSD.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\ncontract OETH is OUSD {\n function symbol() external pure override returns (string memory) {\n return \"OETH\";\n }\n\n function name() external pure override returns (string memory) {\n return \"Origin Ether\";\n }\n\n function decimals() external pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/token/OETHBase.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { OUSD } from \"./OUSD.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\ncontract OETHBase is OUSD {\n constructor() {\n // Nobody owns the implementation contract\n _setGovernor(address(0));\n }\n\n function symbol() external pure override returns (string memory) {\n return \"superOETHb\";\n }\n\n function name() external pure override returns (string memory) {\n return \"Super OETH\";\n }\n\n function decimals() external pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/token/OETHPlume.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { OUSD } from \"./OUSD.sol\";\n\n/**\n * @title Super OETH (Plume) Token Contract\n * @author Origin Protocol Inc\n */\ncontract OETHPlume is OUSD {\n constructor() {\n // Nobody owns the implementation contract\n _setGovernor(address(0));\n }\n\n function symbol() external pure override returns (string memory) {\n return \"superOETHp\";\n }\n\n function name() external pure override returns (string memory) {\n return \"Super OETH\";\n }\n\n function decimals() external pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/token/OSonic.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { OUSD } from \"./OUSD.sol\";\n\n/**\n * @title Origin Sonic (OS) token on Sonic\n * @author Origin Protocol Inc\n */\ncontract OSonic is OUSD {\n function symbol() external pure override returns (string memory) {\n return \"OS\";\n }\n\n function name() external pure override returns (string memory) {\n return \"Origin Sonic\";\n }\n}\n" + }, + "contracts/token/OUSD.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Token Contract\n * @dev ERC20 compatible contract for OUSD\n * @dev Implements an elastic supply\n * @author Origin Protocol Inc\n */\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\ncontract OUSD is Governable {\n using SafeCast for int256;\n using SafeCast for uint256;\n\n /// @dev Event triggered when the supply changes\n /// @param totalSupply Updated token total supply\n /// @param rebasingCredits Updated token rebasing credits\n /// @param rebasingCreditsPerToken Updated token rebasing credits per token\n event TotalSupplyUpdatedHighres(\n uint256 totalSupply,\n uint256 rebasingCredits,\n uint256 rebasingCreditsPerToken\n );\n /// @dev Event triggered when an account opts in for rebasing\n /// @param account Address of the account\n event AccountRebasingEnabled(address account);\n /// @dev Event triggered when an account opts out of rebasing\n /// @param account Address of the account\n event AccountRebasingDisabled(address account);\n /// @dev Emitted when `value` tokens are moved from one account `from` to\n /// another `to`.\n /// @param from Address of the account tokens are moved from\n /// @param to Address of the account tokens are moved to\n /// @param value Amount of tokens transferred\n event Transfer(address indexed from, address indexed to, uint256 value);\n /// @dev Emitted when the allowance of a `spender` for an `owner` is set by\n /// a call to {approve}. `value` is the new allowance.\n /// @param owner Address of the owner approving allowance\n /// @param spender Address of the spender allowance is granted to\n /// @param value Amount of tokens spender can transfer\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n /// @dev Yield resulting from {changeSupply} that a `source` account would\n /// receive is directed to `target` account.\n /// @param source Address of the source forwarding the yield\n /// @param target Address of the target receiving the yield\n event YieldDelegated(address source, address target);\n /// @dev Yield delegation from `source` account to the `target` account is\n /// suspended.\n /// @param source Address of the source suspending yield forwarding\n /// @param target Address of the target no longer receiving yield from `source`\n /// account\n event YieldUndelegated(address source, address target);\n\n enum RebaseOptions {\n NotSet,\n StdNonRebasing,\n StdRebasing,\n YieldDelegationSource,\n YieldDelegationTarget\n }\n\n uint256[154] private _gap; // Slots to align with deployed contract\n uint256 private constant MAX_SUPPLY = type(uint128).max;\n /// @dev The amount of tokens in existence\n uint256 public totalSupply;\n mapping(address => mapping(address => uint256)) private allowances;\n /// @dev The vault with privileges to execute {mint}, {burn}\n /// and {changeSupply}\n address public vaultAddress;\n mapping(address => uint256) internal creditBalances;\n // the 2 storage variables below need trailing underscores to not name collide with public functions\n uint256 private rebasingCredits_; // Sum of all rebasing credits (creditBalances for rebasing accounts)\n uint256 private rebasingCreditsPerToken_;\n /// @dev The amount of tokens that are not rebasing - receiving yield\n uint256 public nonRebasingSupply;\n mapping(address => uint256) internal alternativeCreditsPerToken;\n /// @dev A map of all addresses and their respective RebaseOptions\n mapping(address => RebaseOptions) public rebaseState;\n mapping(address => uint256) private __deprecated_isUpgraded;\n /// @dev A map of addresses that have yields forwarded to. This is an\n /// inverse mapping of {yieldFrom}\n /// Key Account forwarding yield\n /// Value Account receiving yield\n mapping(address => address) public yieldTo;\n /// @dev A map of addresses that are receiving the yield. This is an\n /// inverse mapping of {yieldTo}\n /// Key Account receiving yield\n /// Value Account forwarding yield\n mapping(address => address) public yieldFrom;\n\n uint256 private constant RESOLUTION_INCREASE = 1e9;\n uint256[34] private __gap; // including below gap totals up to 200\n\n /// @dev Verifies that the caller is the Governor or Strategist.\n modifier onlyGovernorOrStrategist() {\n require(\n isGovernor() || msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n /// @dev Initializes the contract and sets necessary variables.\n /// @param _vaultAddress Address of the vault contract\n /// @param _initialCreditsPerToken The starting rebasing credits per token.\n function initialize(address _vaultAddress, uint256 _initialCreditsPerToken)\n external\n onlyGovernor\n {\n require(_vaultAddress != address(0), \"Zero vault address\");\n require(vaultAddress == address(0), \"Already initialized\");\n\n rebasingCreditsPerToken_ = _initialCreditsPerToken;\n vaultAddress = _vaultAddress;\n }\n\n /// @dev Returns the symbol of the token, a shorter version\n /// of the name.\n function symbol() external pure virtual returns (string memory) {\n return \"OUSD\";\n }\n\n /// @dev Returns the name of the token.\n function name() external pure virtual returns (string memory) {\n return \"Origin Dollar\";\n }\n\n /// @dev Returns the number of decimals used to get its user representation.\n function decimals() external pure virtual returns (uint8) {\n return 18;\n }\n\n /**\n * @dev Verifies that the caller is the Vault contract\n */\n modifier onlyVault() {\n require(vaultAddress == msg.sender, \"Caller is not the Vault\");\n _;\n }\n\n /**\n * @return High resolution rebasingCreditsPerToken\n */\n function rebasingCreditsPerTokenHighres() external view returns (uint256) {\n return rebasingCreditsPerToken_;\n }\n\n /**\n * @return Low resolution rebasingCreditsPerToken\n */\n function rebasingCreditsPerToken() external view returns (uint256) {\n return rebasingCreditsPerToken_ / RESOLUTION_INCREASE;\n }\n\n /**\n * @return High resolution total number of rebasing credits\n */\n function rebasingCreditsHighres() external view returns (uint256) {\n return rebasingCredits_;\n }\n\n /**\n * @return Low resolution total number of rebasing credits\n */\n function rebasingCredits() external view returns (uint256) {\n return rebasingCredits_ / RESOLUTION_INCREASE;\n }\n\n /**\n * @notice Gets the balance of the specified address.\n * @param _account Address to query the balance of.\n * @return A uint256 representing the amount of base units owned by the\n * specified address.\n */\n function balanceOf(address _account) public view returns (uint256) {\n RebaseOptions state = rebaseState[_account];\n if (state == RebaseOptions.YieldDelegationSource) {\n // Saves a slot read when transferring to or from a yield delegating source\n // since we know creditBalances equals the balance.\n return creditBalances[_account];\n }\n uint256 baseBalance = (creditBalances[_account] * 1e18) /\n _creditsPerToken(_account);\n if (state == RebaseOptions.YieldDelegationTarget) {\n // creditBalances of yieldFrom accounts equals token balances\n return baseBalance - creditBalances[yieldFrom[_account]];\n }\n return baseBalance;\n }\n\n /**\n * @notice Gets the credits balance of the specified address.\n * @dev Backwards compatible with old low res credits per token.\n * @param _account The address to query the balance of.\n * @return (uint256, uint256) Credit balance and credits per token of the\n * address\n */\n function creditsBalanceOf(address _account)\n external\n view\n returns (uint256, uint256)\n {\n uint256 cpt = _creditsPerToken(_account);\n if (cpt == 1e27) {\n // For a period before the resolution upgrade, we created all new\n // contract accounts at high resolution. Since they are not changing\n // as a result of this upgrade, we will return their true values\n return (creditBalances[_account], cpt);\n } else {\n return (\n creditBalances[_account] / RESOLUTION_INCREASE,\n cpt / RESOLUTION_INCREASE\n );\n }\n }\n\n /**\n * @notice Gets the credits balance of the specified address.\n * @param _account The address to query the balance of.\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\n * address, and isUpgraded\n */\n function creditsBalanceOfHighres(address _account)\n external\n view\n returns (\n uint256,\n uint256,\n bool\n )\n {\n return (\n creditBalances[_account],\n _creditsPerToken(_account),\n true // all accounts have their resolution \"upgraded\"\n );\n }\n\n // Backwards compatible view\n function nonRebasingCreditsPerToken(address _account)\n external\n view\n returns (uint256)\n {\n return alternativeCreditsPerToken[_account];\n }\n\n /**\n * @notice Transfer tokens to a specified address.\n * @param _to the address to transfer to.\n * @param _value the amount to be transferred.\n * @return true on success.\n */\n function transfer(address _to, uint256 _value) external returns (bool) {\n require(_to != address(0), \"Transfer to zero address\");\n\n _executeTransfer(msg.sender, _to, _value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n /**\n * @notice Transfer tokens from one address to another.\n * @param _from The address you want to send tokens from.\n * @param _to The address you want to transfer to.\n * @param _value The amount of tokens to be transferred.\n * @return true on success.\n */\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool) {\n require(_to != address(0), \"Transfer to zero address\");\n uint256 userAllowance = allowances[_from][msg.sender];\n require(_value <= userAllowance, \"Allowance exceeded\");\n\n unchecked {\n allowances[_from][msg.sender] = userAllowance - _value;\n }\n\n _executeTransfer(_from, _to, _value);\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function _executeTransfer(\n address _from,\n address _to,\n uint256 _value\n ) internal {\n (\n int256 fromRebasingCreditsDiff,\n int256 fromNonRebasingSupplyDiff\n ) = _adjustAccount(_from, -_value.toInt256());\n (\n int256 toRebasingCreditsDiff,\n int256 toNonRebasingSupplyDiff\n ) = _adjustAccount(_to, _value.toInt256());\n\n _adjustGlobals(\n fromRebasingCreditsDiff + toRebasingCreditsDiff,\n fromNonRebasingSupplyDiff + toNonRebasingSupplyDiff\n );\n }\n\n function _adjustAccount(address _account, int256 _balanceChange)\n internal\n returns (int256 rebasingCreditsDiff, int256 nonRebasingSupplyDiff)\n {\n RebaseOptions state = rebaseState[_account];\n int256 currentBalance = balanceOf(_account).toInt256();\n if (currentBalance + _balanceChange < 0) {\n revert(\"Transfer amount exceeds balance\");\n }\n uint256 newBalance = (currentBalance + _balanceChange).toUint256();\n\n if (state == RebaseOptions.YieldDelegationSource) {\n address target = yieldTo[_account];\n uint256 targetOldBalance = balanceOf(target);\n uint256 targetNewCredits = _balanceToRebasingCredits(\n targetOldBalance + newBalance\n );\n rebasingCreditsDiff =\n targetNewCredits.toInt256() -\n creditBalances[target].toInt256();\n\n creditBalances[_account] = newBalance;\n creditBalances[target] = targetNewCredits;\n } else if (state == RebaseOptions.YieldDelegationTarget) {\n uint256 newCredits = _balanceToRebasingCredits(\n newBalance + creditBalances[yieldFrom[_account]]\n );\n rebasingCreditsDiff =\n newCredits.toInt256() -\n creditBalances[_account].toInt256();\n creditBalances[_account] = newCredits;\n } else {\n _autoMigrate(_account);\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\n _account\n ];\n if (alternativeCreditsPerTokenMem > 0) {\n nonRebasingSupplyDiff = _balanceChange;\n if (alternativeCreditsPerTokenMem != 1e18) {\n alternativeCreditsPerToken[_account] = 1e18;\n }\n creditBalances[_account] = newBalance;\n } else {\n uint256 newCredits = _balanceToRebasingCredits(newBalance);\n rebasingCreditsDiff =\n newCredits.toInt256() -\n creditBalances[_account].toInt256();\n creditBalances[_account] = newCredits;\n }\n }\n }\n\n function _adjustGlobals(\n int256 _rebasingCreditsDiff,\n int256 _nonRebasingSupplyDiff\n ) internal {\n if (_rebasingCreditsDiff != 0) {\n rebasingCredits_ = (rebasingCredits_.toInt256() +\n _rebasingCreditsDiff).toUint256();\n }\n if (_nonRebasingSupplyDiff != 0) {\n nonRebasingSupply = (nonRebasingSupply.toInt256() +\n _nonRebasingSupplyDiff).toUint256();\n }\n }\n\n /**\n * @notice Function to check the amount of tokens that _owner has allowed\n * to `_spender`.\n * @param _owner The address which owns the funds.\n * @param _spender The address which will spend the funds.\n * @return The number of tokens still available for the _spender.\n */\n function allowance(address _owner, address _spender)\n external\n view\n returns (uint256)\n {\n return allowances[_owner][_spender];\n }\n\n /**\n * @notice Approve the passed address to spend the specified amount of\n * tokens on behalf of msg.sender.\n * @param _spender The address which will spend the funds.\n * @param _value The amount of tokens to be spent.\n * @return true on success.\n */\n function approve(address _spender, uint256 _value) external returns (bool) {\n allowances[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n /**\n * @notice Creates `_amount` tokens and assigns them to `_account`,\n * increasing the total supply.\n */\n function mint(address _account, uint256 _amount) external onlyVault {\n require(_account != address(0), \"Mint to the zero address\");\n\n // Account\n (\n int256 toRebasingCreditsDiff,\n int256 toNonRebasingSupplyDiff\n ) = _adjustAccount(_account, _amount.toInt256());\n // Globals\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\n totalSupply = totalSupply + _amount;\n\n require(totalSupply < MAX_SUPPLY, \"Max supply\");\n emit Transfer(address(0), _account, _amount);\n }\n\n /**\n * @notice Destroys `_amount` tokens from `_account`,\n * reducing the total supply.\n */\n function burn(address _account, uint256 _amount) external onlyVault {\n require(_account != address(0), \"Burn from the zero address\");\n if (_amount == 0) {\n return;\n }\n\n // Account\n (\n int256 toRebasingCreditsDiff,\n int256 toNonRebasingSupplyDiff\n ) = _adjustAccount(_account, -_amount.toInt256());\n // Globals\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\n totalSupply = totalSupply - _amount;\n\n emit Transfer(_account, address(0), _amount);\n }\n\n /**\n * @dev Get the credits per token for an account. Returns a fixed amount\n * if the account is non-rebasing.\n * @param _account Address of the account.\n */\n function _creditsPerToken(address _account)\n internal\n view\n returns (uint256)\n {\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\n _account\n ];\n if (alternativeCreditsPerTokenMem != 0) {\n return alternativeCreditsPerTokenMem;\n } else {\n return rebasingCreditsPerToken_;\n }\n }\n\n /**\n * @dev Auto migrate contracts to be non rebasing,\n * unless they have opted into yield.\n * @param _account Address of the account.\n */\n function _autoMigrate(address _account) internal {\n uint256 codeLen = _account.code.length;\n bool isEOA = (codeLen == 0) ||\n (codeLen == 23 && bytes3(_account.code) == 0xef0100);\n // In previous code versions, contracts would not have had their\n // rebaseState[_account] set to RebaseOptions.NonRebasing when migrated\n // therefore we check the actual accounting used on the account as well.\n if (\n (!isEOA) &&\n rebaseState[_account] == RebaseOptions.NotSet &&\n alternativeCreditsPerToken[_account] == 0\n ) {\n _rebaseOptOut(_account);\n }\n }\n\n /**\n * @dev Calculates credits from contract's global rebasingCreditsPerToken_, and\n * also balance that corresponds to those credits. The latter is important\n * when adjusting the contract's global nonRebasingSupply to circumvent any\n * possible rounding errors.\n *\n * @param _balance Balance of the account.\n */\n function _balanceToRebasingCredits(uint256 _balance)\n internal\n view\n returns (uint256 rebasingCredits)\n {\n // Rounds up, because we need to ensure that accounts always have\n // at least the balance that they should have.\n // Note this should always be used on an absolute account value,\n // not on a possibly negative diff, because then the rounding would be wrong.\n return ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18;\n }\n\n /**\n * @notice The calling account will start receiving yield after a successful call.\n * @param _account Address of the account.\n */\n function governanceRebaseOptIn(address _account) external onlyGovernor {\n require(_account != address(0), \"Zero address not allowed\");\n _rebaseOptIn(_account);\n }\n\n /**\n * @notice The calling account will start receiving yield after a successful call.\n */\n function rebaseOptIn() external {\n _rebaseOptIn(msg.sender);\n }\n\n function _rebaseOptIn(address _account) internal {\n uint256 balance = balanceOf(_account);\n\n // prettier-ignore\n require(\n alternativeCreditsPerToken[_account] > 0 ||\n // Accounts may explicitly `rebaseOptIn` regardless of\n // accounting if they have a 0 balance.\n creditBalances[_account] == 0\n ,\n \"Account must be non-rebasing\"\n );\n RebaseOptions state = rebaseState[_account];\n // prettier-ignore\n require(\n state == RebaseOptions.StdNonRebasing ||\n state == RebaseOptions.NotSet,\n \"Only standard non-rebasing accounts can opt in\"\n );\n\n uint256 newCredits = _balanceToRebasingCredits(balance);\n\n // Account\n rebaseState[_account] = RebaseOptions.StdRebasing;\n alternativeCreditsPerToken[_account] = 0;\n creditBalances[_account] = newCredits;\n // Globals\n _adjustGlobals(newCredits.toInt256(), -balance.toInt256());\n\n emit AccountRebasingEnabled(_account);\n }\n\n /**\n * @notice The calling account will no longer receive yield\n */\n function rebaseOptOut() external {\n _rebaseOptOut(msg.sender);\n }\n\n function _rebaseOptOut(address _account) internal {\n require(\n alternativeCreditsPerToken[_account] == 0,\n \"Account must be rebasing\"\n );\n RebaseOptions state = rebaseState[_account];\n require(\n state == RebaseOptions.StdRebasing || state == RebaseOptions.NotSet,\n \"Only standard rebasing accounts can opt out\"\n );\n\n uint256 oldCredits = creditBalances[_account];\n uint256 balance = balanceOf(_account);\n\n // Account\n rebaseState[_account] = RebaseOptions.StdNonRebasing;\n alternativeCreditsPerToken[_account] = 1e18;\n creditBalances[_account] = balance;\n // Globals\n _adjustGlobals(-oldCredits.toInt256(), balance.toInt256());\n\n emit AccountRebasingDisabled(_account);\n }\n\n /**\n * @notice Distribute yield to users. This changes the exchange rate\n * between \"credits\" and OUSD tokens to change rebasing user's balances.\n * @param _newTotalSupply New total supply of OUSD.\n */\n function changeSupply(uint256 _newTotalSupply) external onlyVault {\n require(totalSupply > 0, \"Cannot increase 0 supply\");\n\n if (totalSupply == _newTotalSupply) {\n emit TotalSupplyUpdatedHighres(\n totalSupply,\n rebasingCredits_,\n rebasingCreditsPerToken_\n );\n return;\n }\n\n totalSupply = _newTotalSupply > MAX_SUPPLY\n ? MAX_SUPPLY\n : _newTotalSupply;\n\n uint256 rebasingSupply = totalSupply - nonRebasingSupply;\n // round up in the favour of the protocol\n rebasingCreditsPerToken_ =\n (rebasingCredits_ * 1e18 + rebasingSupply - 1) /\n rebasingSupply;\n\n require(rebasingCreditsPerToken_ > 0, \"Invalid change in supply\");\n\n emit TotalSupplyUpdatedHighres(\n totalSupply,\n rebasingCredits_,\n rebasingCreditsPerToken_\n );\n }\n\n /*\n * @notice Send the yield from one account to another account.\n * Each account keeps its own balances.\n */\n function delegateYield(address _from, address _to)\n external\n onlyGovernorOrStrategist\n {\n require(_from != address(0), \"Zero from address not allowed\");\n require(_to != address(0), \"Zero to address not allowed\");\n\n require(_from != _to, \"Cannot delegate to self\");\n require(\n yieldFrom[_to] == address(0) &&\n yieldTo[_to] == address(0) &&\n yieldFrom[_from] == address(0) &&\n yieldTo[_from] == address(0),\n \"Blocked by existing yield delegation\"\n );\n RebaseOptions stateFrom = rebaseState[_from];\n RebaseOptions stateTo = rebaseState[_to];\n\n require(\n stateFrom == RebaseOptions.NotSet ||\n stateFrom == RebaseOptions.StdNonRebasing ||\n stateFrom == RebaseOptions.StdRebasing,\n \"Invalid rebaseState from\"\n );\n\n require(\n stateTo == RebaseOptions.NotSet ||\n stateTo == RebaseOptions.StdNonRebasing ||\n stateTo == RebaseOptions.StdRebasing,\n \"Invalid rebaseState to\"\n );\n\n if (alternativeCreditsPerToken[_from] == 0) {\n _rebaseOptOut(_from);\n }\n if (alternativeCreditsPerToken[_to] > 0) {\n _rebaseOptIn(_to);\n }\n\n uint256 fromBalance = balanceOf(_from);\n uint256 toBalance = balanceOf(_to);\n uint256 oldToCredits = creditBalances[_to];\n uint256 newToCredits = _balanceToRebasingCredits(\n fromBalance + toBalance\n );\n\n // Set up the bidirectional links\n yieldTo[_from] = _to;\n yieldFrom[_to] = _from;\n\n // Local\n rebaseState[_from] = RebaseOptions.YieldDelegationSource;\n alternativeCreditsPerToken[_from] = 1e18;\n creditBalances[_from] = fromBalance;\n rebaseState[_to] = RebaseOptions.YieldDelegationTarget;\n creditBalances[_to] = newToCredits;\n\n // Global\n int256 creditsChange = newToCredits.toInt256() -\n oldToCredits.toInt256();\n _adjustGlobals(creditsChange, -(fromBalance).toInt256());\n emit YieldDelegated(_from, _to);\n }\n\n /*\n * @notice Stop sending the yield from one account to another account.\n */\n function undelegateYield(address _from) external onlyGovernorOrStrategist {\n // Require a delegation, which will also ensure a valid delegation\n require(yieldTo[_from] != address(0), \"Zero address not allowed\");\n\n address to = yieldTo[_from];\n uint256 fromBalance = balanceOf(_from);\n uint256 toBalance = balanceOf(to);\n uint256 oldToCredits = creditBalances[to];\n uint256 newToCredits = _balanceToRebasingCredits(toBalance);\n\n // Remove the bidirectional links\n yieldFrom[to] = address(0);\n yieldTo[_from] = address(0);\n\n // Local\n rebaseState[_from] = RebaseOptions.StdNonRebasing;\n // alternativeCreditsPerToken[from] already 1e18 from `delegateYield()`\n creditBalances[_from] = fromBalance;\n rebaseState[to] = RebaseOptions.StdRebasing;\n // alternativeCreditsPerToken[to] already 0 from `delegateYield()`\n creditBalances[to] = newToCredits;\n\n // Global\n int256 creditsChange = newToCredits.toInt256() -\n oldToCredits.toInt256();\n _adjustGlobals(creditsChange, fromBalance.toInt256());\n emit YieldUndelegated(_from, to);\n }\n}\n" + }, + "contracts/token/WOETH.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ERC4626 } from \"../../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { OETH } from \"./OETH.sol\";\n\n/**\n * @title Wrapped OETH Token Contract\n * @author Origin Protocol Inc\n *\n * @dev An important capability of this contract is that it isn't susceptible to changes of the\n * exchange rate of WOETH/OETH if/when someone sends the underlying asset (OETH) to the contract.\n * If OETH weren't rebasing this could be achieved by solely tracking the ERC20 transfers of the OETH\n * token on mint, deposit, redeem, withdraw. The issue is that OETH is rebasing and OETH balances\n * will change when the token rebases.\n * For that reason the contract logic checks the actual underlying OETH token balance only once\n * (either on a fresh contract creation or upgrade) and considering the WOETH supply and\n * rebasingCreditsPerToken calculates the _adjuster. Once the adjuster is calculated any donations\n * to the contract are ignored. The totalSupply (instead of querying OETH balance) works off of\n * adjuster the current WOETH supply and rebasingCreditsPerToken. This makes WOETH value accrual\n * completely follow OETH's value accrual.\n * WOETH is safe to use in lending markets as the VualtCore's _rebase contains safeguards preventing\n * any sudden large rebases.\n */\n\ncontract WOETH is ERC4626, Governable, Initializable {\n using SafeERC20 for IERC20;\n /* This is a 1e27 adjustment constant that expresses the difference in exchange rate between\n * OETH's rebase since inception (expressed with rebasingCreditsPerToken) and WOETH to OETH\n * conversion.\n *\n * If WOETH and OETH are deployed at the same time, the value of adjuster is a neutral 1e27\n */\n uint256 public adjuster;\n uint256[49] private __gap;\n\n // no need to set ERC20 name and symbol since they are overridden in WOETH & WOETHBase\n constructor(ERC20 underlying_) ERC20(\"\", \"\") ERC4626(underlying_) {}\n\n /**\n * @notice Enable OETH rebasing for this contract\n */\n function initialize() external onlyGovernor initializer {\n OETH(address(asset())).rebaseOptIn();\n\n initialize2();\n }\n\n /**\n * @notice secondary initializer that newly deployed contracts will execute as part\n * of primary initialize function and the existing contracts will have it called\n * as a governance operation.\n */\n function initialize2() public onlyGovernor {\n require(adjuster == 0, \"Initialize2 already called\");\n\n if (totalSupply() == 0) {\n adjuster = 1e27;\n } else {\n adjuster =\n (rebasingCreditsPerTokenHighres() *\n ERC20(asset()).balanceOf(address(this))) /\n totalSupply();\n }\n }\n\n function name()\n public\n view\n virtual\n override(ERC20, IERC20Metadata)\n returns (string memory)\n {\n return \"Wrapped OETH\";\n }\n\n function symbol()\n public\n view\n virtual\n override(ERC20, IERC20Metadata)\n returns (string memory)\n {\n return \"wOETH\";\n }\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends. Cannot transfer OETH\n * @param asset_ Address for the asset\n * @param amount_ Amount of the asset to transfer\n */\n function transferToken(address asset_, uint256 amount_)\n external\n onlyGovernor\n {\n require(asset_ != address(asset()), \"Cannot collect core asset\");\n IERC20(asset_).safeTransfer(governor(), amount_);\n }\n\n /// @inheritdoc ERC4626\n function convertToShares(uint256 assets)\n public\n view\n virtual\n override\n returns (uint256 shares)\n {\n return (assets * rebasingCreditsPerTokenHighres()) / adjuster;\n }\n\n /// @inheritdoc ERC4626\n function convertToAssets(uint256 shares)\n public\n view\n virtual\n override\n returns (uint256 assets)\n {\n return (shares * adjuster) / rebasingCreditsPerTokenHighres();\n }\n\n /// @inheritdoc ERC4626\n function totalAssets() public view override returns (uint256) {\n return (totalSupply() * adjuster) / rebasingCreditsPerTokenHighres();\n }\n\n function rebasingCreditsPerTokenHighres() internal view returns (uint256) {\n return OETH(asset()).rebasingCreditsPerTokenHighres();\n }\n}\n" + }, + "contracts/token/WOETHBase.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { WOETH } from \"./WOETH.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\n\ncontract WOETHBase is WOETH {\n constructor(ERC20 underlying_) WOETH(underlying_) {}\n\n function name() public view virtual override returns (string memory) {\n return \"Wrapped Super OETH\";\n }\n\n function symbol() public view virtual override returns (string memory) {\n return \"wsuperOETHb\";\n }\n}\n" + }, + "contracts/token/WOETHPlume.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { WOETH } from \"./WOETH.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\n/**\n * @title wOETH (Plume) Token Contract\n * @author Origin Protocol Inc\n */\n\ncontract WOETHPlume is WOETH {\n constructor(ERC20 underlying_) WOETH(underlying_) {}\n\n function name() public view virtual override returns (string memory) {\n return \"Wrapped Super OETH\";\n }\n\n function symbol() public view virtual override returns (string memory) {\n return \"wsuperOETHp\";\n }\n}\n" + }, + "contracts/token/WOSonic.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { WOETH } from \"./WOETH.sol\";\n\n/**\n * @title Wrapped Origin Sonic (wOS) token on Sonic\n * @author Origin Protocol Inc\n */\ncontract WOSonic is WOETH {\n constructor(ERC20 underlying_) WOETH(underlying_) {}\n\n function name()\n public\n view\n virtual\n override(WOETH)\n returns (string memory)\n {\n return \"Wrapped OS\";\n }\n\n function symbol()\n public\n view\n virtual\n override(WOETH)\n returns (string memory)\n {\n return \"wOS\";\n }\n}\n" + }, + "contracts/token/WrappedOusd.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { WOETH } from \"./WOETH.sol\";\n\n/**\n * @title Wrapped OUSD Token Contract\n * @author Origin Protocol Inc\n */\ncontract WrappedOusd is WOETH {\n constructor(ERC20 underlying_) WOETH(underlying_) {}\n\n function name()\n public\n view\n virtual\n override(WOETH)\n returns (string memory)\n {\n return \"Wrapped OUSD\";\n }\n\n function symbol()\n public\n view\n virtual\n override(WOETH)\n returns (string memory)\n {\n return \"WOUSD\";\n }\n}\n" + }, + "contracts/utils/BytesHelper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nuint256 constant UINT32_LENGTH = 4;\nuint256 constant UINT64_LENGTH = 8;\nuint256 constant UINT256_LENGTH = 32;\n// Address is 20 bytes, but we expect the data to be padded with 0s to 32 bytes\nuint256 constant ADDRESS_LENGTH = 32;\n\nlibrary BytesHelper {\n /**\n * @dev Extract a slice from bytes memory\n * @param data The bytes memory to slice\n * @param start The start index (inclusive)\n * @param end The end index (exclusive)\n * @return result A new bytes memory containing the slice\n */\n function extractSlice(\n bytes memory data,\n uint256 start,\n uint256 end\n ) internal pure returns (bytes memory) {\n require(end >= start, \"Invalid slice range\");\n require(end <= data.length, \"Slice end exceeds data length\");\n\n uint256 length = end - start;\n bytes memory result = new bytes(length);\n\n // Simple byte-by-byte copy\n for (uint256 i = 0; i < length; i++) {\n result[i] = data[start + i];\n }\n\n return result;\n }\n\n /**\n * @dev Decode a uint32 from a bytes memory\n * @param data The bytes memory to decode\n * @return uint32 The decoded uint32\n */\n function decodeUint32(bytes memory data) internal pure returns (uint32) {\n require(data.length == 4, \"Invalid data length\");\n return uint32(uint256(bytes32(data)) >> 224);\n }\n\n /**\n * @dev Extract a uint32 from a bytes memory\n * @param data The bytes memory to extract from\n * @param start The start index (inclusive)\n * @return uint32 The extracted uint32\n */\n function extractUint32(bytes memory data, uint256 start)\n internal\n pure\n returns (uint32)\n {\n return decodeUint32(extractSlice(data, start, start + UINT32_LENGTH));\n }\n\n /**\n * @dev Decode an address from a bytes memory.\n * Expects the data to be padded with 0s to 32 bytes.\n * @param data The bytes memory to decode\n * @return address The decoded address\n */\n function decodeAddress(bytes memory data) internal pure returns (address) {\n // We expect the data to be padded with 0s, so length is 32 not 20\n require(data.length == 32, \"Invalid data length\");\n return abi.decode(data, (address));\n }\n\n /**\n * @dev Extract an address from a bytes memory\n * @param data The bytes memory to extract from\n * @param start The start index (inclusive)\n * @return address The extracted address\n */\n function extractAddress(bytes memory data, uint256 start)\n internal\n pure\n returns (address)\n {\n return decodeAddress(extractSlice(data, start, start + ADDRESS_LENGTH));\n }\n\n /**\n * @dev Decode a uint256 from a bytes memory\n * @param data The bytes memory to decode\n * @return uint256 The decoded uint256\n */\n function decodeUint256(bytes memory data) internal pure returns (uint256) {\n require(data.length == 32, \"Invalid data length\");\n return abi.decode(data, (uint256));\n }\n\n /**\n * @dev Extract a uint256 from a bytes memory\n * @param data The bytes memory to extract from\n * @param start The start index (inclusive)\n * @return uint256 The extracted uint256\n */\n function extractUint256(bytes memory data, uint256 start)\n internal\n pure\n returns (uint256)\n {\n return decodeUint256(extractSlice(data, start, start + UINT256_LENGTH));\n }\n}\n" + }, + "contracts/utils/Helpers.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IBasicToken } from \"../interfaces/IBasicToken.sol\";\n\nlibrary Helpers {\n /**\n * @notice Fetch the `symbol()` from an ERC20 token\n * @dev Grabs the `symbol()` from a contract\n * @param _token Address of the ERC20 token\n * @return string Symbol of the ERC20 token\n */\n function getSymbol(address _token) internal view returns (string memory) {\n string memory symbol = IBasicToken(_token).symbol();\n return symbol;\n }\n\n /**\n * @notice Fetch the `decimals()` from an ERC20 token\n * @dev Grabs the `decimals()` from a contract and fails if\n * the decimal value does not live within a certain range\n * @param _token Address of the ERC20 token\n * @return uint256 Decimals of the ERC20 token\n */\n function getDecimals(address _token) internal view returns (uint256) {\n uint256 decimals = IBasicToken(_token).decimals();\n require(\n decimals >= 4 && decimals <= 18,\n \"Token must have sufficient decimal places\"\n );\n\n return decimals;\n }\n}\n" + }, + "contracts/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Base contract any contracts that need to initialize state after deployment.\n * @author Origin Protocol Inc\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private initializing;\n\n /**\n * @dev Modifier to protect an initializer function from being invoked twice.\n */\n modifier initializer() {\n require(\n initializing || !initialized,\n \"Initializable: contract is already initialized\"\n );\n\n bool isTopLevelCall = !initializing;\n if (isTopLevelCall) {\n initializing = true;\n initialized = true;\n }\n\n _;\n\n if (isTopLevelCall) {\n initializing = false;\n }\n }\n\n uint256[50] private ______gap;\n}\n" + }, + "contracts/utils/InitializableAbstractStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Base contract for vault strategies.\n * @author Origin Protocol Inc\n */\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nabstract contract InitializableAbstractStrategy is Initializable, Governable {\n using SafeERC20 for IERC20;\n\n event PTokenAdded(address indexed _asset, address _pToken);\n event PTokenRemoved(address indexed _asset, address _pToken);\n event Deposit(address indexed _asset, address _pToken, uint256 _amount);\n event Withdrawal(address indexed _asset, address _pToken, uint256 _amount);\n event RewardTokenCollected(\n address recipient,\n address rewardToken,\n uint256 amount\n );\n event RewardTokenAddressesUpdated(\n address[] _oldAddresses,\n address[] _newAddresses\n );\n event HarvesterAddressesUpdated(\n address _oldHarvesterAddress,\n address _newHarvesterAddress\n );\n\n /// @notice Address of the underlying platform\n address public immutable platformAddress;\n /// @notice Address of the OToken vault\n address public immutable vaultAddress;\n\n /// @dev Replaced with an immutable variable\n // slither-disable-next-line constable-states\n address private _deprecated_platformAddress;\n\n /// @dev Replaced with an immutable\n // slither-disable-next-line constable-states\n address private _deprecated_vaultAddress;\n\n /// @notice asset => pToken (Platform Specific Token Address)\n mapping(address => address) public assetToPToken;\n\n /// @notice Full list of all assets supported by the strategy\n address[] internal assetsMapped;\n\n // Deprecated: Reward token address\n // slither-disable-next-line constable-states\n address private _deprecated_rewardTokenAddress;\n\n // Deprecated: now resides in Harvester's rewardTokenConfigs\n // slither-disable-next-line constable-states\n uint256 private _deprecated_rewardLiquidationThreshold;\n\n /// @notice Address of the Harvester contract allowed to collect reward tokens\n address public harvesterAddress;\n\n /// @notice Address of the reward tokens. eg CRV, BAL, CVX, AURA\n address[] public rewardTokenAddresses;\n\n /* Reserved for future expansion. Used to be 100 storage slots\n * and has decreased to accommodate:\n * - harvesterAddress\n * - rewardTokenAddresses\n */\n int256[98] private _reserved;\n\n struct BaseStrategyConfig {\n address platformAddress; // Address of the underlying platform\n address vaultAddress; // Address of the OToken's Vault\n }\n\n /**\n * @dev Verifies that the caller is the Governor or Strategist.\n */\n modifier onlyGovernorOrStrategist() virtual {\n require(\n isGovernor() || msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n /**\n * @param _config The platform and OToken vault addresses\n */\n constructor(BaseStrategyConfig memory _config) {\n platformAddress = _config.platformAddress;\n vaultAddress = _config.vaultAddress;\n }\n\n /**\n * @dev Internal initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function _initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) internal {\n rewardTokenAddresses = _rewardTokenAddresses;\n\n uint256 assetCount = _assets.length;\n require(assetCount == _pTokens.length, \"Invalid input arrays\");\n for (uint256 i = 0; i < assetCount; ++i) {\n _setPTokenAddress(_assets[i], _pTokens[i]);\n }\n }\n\n /**\n * @notice Collect accumulated reward token and send to Vault.\n * No-ops when the harvester address is not set.\n */\n function collectRewardTokens()\n external\n virtual\n onlyHarvesterOrStrategist\n nonReentrant\n {\n if (harvesterAddress == address(0)) {\n return;\n }\n _collectRewardTokens();\n }\n\n /**\n * @dev Default implementation that transfers reward tokens to the Harvester.\n * Implementing strategies need to add custom logic to collect the rewards.\n */\n function _collectRewardTokens() internal virtual {\n if (harvesterAddress == address(0)) {\n return;\n }\n uint256 rewardTokenCount = rewardTokenAddresses.length;\n for (uint256 i = 0; i < rewardTokenCount; ++i) {\n IERC20 rewardToken = IERC20(rewardTokenAddresses[i]);\n uint256 balance = rewardToken.balanceOf(address(this));\n if (balance > 0) {\n emit RewardTokenCollected(\n harvesterAddress,\n address(rewardToken),\n balance\n );\n rewardToken.safeTransfer(harvesterAddress, balance);\n }\n }\n }\n\n /**\n * @dev Verifies that the caller is the Vault.\n */\n modifier onlyVault() {\n require(msg.sender == vaultAddress, \"Caller is not the Vault\");\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Harvester or Strategist.\n */\n modifier onlyHarvesterOrStrategist() {\n require(\n msg.sender == harvesterAddress ||\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Harvester or Strategist\"\n );\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Vault or Governor.\n */\n modifier onlyVaultOrGovernor() {\n require(\n msg.sender == vaultAddress || msg.sender == governor(),\n \"Caller is not the Vault or Governor\"\n );\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Vault, Governor, or Strategist.\n */\n modifier onlyVaultOrGovernorOrStrategist() {\n require(\n msg.sender == vaultAddress ||\n msg.sender == governor() ||\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Vault, Governor, or Strategist\"\n );\n _;\n }\n\n /**\n * @notice Set the reward token addresses. Any old addresses will be overwritten.\n * @param _rewardTokenAddresses Array of reward token addresses\n */\n function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\n external\n onlyGovernor\n {\n uint256 rewardTokenCount = _rewardTokenAddresses.length;\n for (uint256 i = 0; i < rewardTokenCount; ++i) {\n require(\n _rewardTokenAddresses[i] != address(0),\n \"Can not set an empty address as a reward token\"\n );\n }\n\n emit RewardTokenAddressesUpdated(\n rewardTokenAddresses,\n _rewardTokenAddresses\n );\n rewardTokenAddresses = _rewardTokenAddresses;\n }\n\n /**\n * @notice Get the reward token addresses.\n * @return address[] the reward token addresses.\n */\n function getRewardTokenAddresses()\n external\n view\n returns (address[] memory)\n {\n return rewardTokenAddresses;\n }\n\n /**\n * @notice Provide support for asset by passing its pToken address.\n * This method can only be called by the system Governor\n * @param _asset Address for the asset\n * @param _pToken Address for the corresponding platform token\n */\n function setPTokenAddress(address _asset, address _pToken)\n external\n virtual\n onlyGovernor\n {\n _setPTokenAddress(_asset, _pToken);\n }\n\n /**\n * @notice Remove a supported asset by passing its index.\n * This method can only be called by the system Governor\n * @param _assetIndex Index of the asset to be removed\n */\n function removePToken(uint256 _assetIndex) external virtual onlyGovernor {\n require(_assetIndex < assetsMapped.length, \"Invalid index\");\n address asset = assetsMapped[_assetIndex];\n address pToken = assetToPToken[asset];\n\n if (_assetIndex < assetsMapped.length - 1) {\n assetsMapped[_assetIndex] = assetsMapped[assetsMapped.length - 1];\n }\n assetsMapped.pop();\n assetToPToken[asset] = address(0);\n\n emit PTokenRemoved(asset, pToken);\n }\n\n /**\n * @notice Provide support for asset by passing its pToken address.\n * Add to internal mappings and execute the platform specific,\n * abstract method `_abstractSetPToken`\n * @param _asset Address for the asset\n * @param _pToken Address for the corresponding platform token\n */\n function _setPTokenAddress(address _asset, address _pToken) internal {\n require(assetToPToken[_asset] == address(0), \"pToken already set\");\n require(\n _asset != address(0) && _pToken != address(0),\n \"Invalid addresses\"\n );\n\n assetToPToken[_asset] = _pToken;\n assetsMapped.push(_asset);\n\n emit PTokenAdded(_asset, _pToken);\n\n _abstractSetPToken(_asset, _pToken);\n }\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * strategy contracts, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n public\n virtual\n onlyGovernor\n {\n require(!supportsAsset(_asset), \"Cannot transfer supported asset\");\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /**\n * @notice Set the Harvester contract that can collect rewards.\n * @param _harvesterAddress Address of the harvester contract.\n */\n function setHarvesterAddress(address _harvesterAddress)\n external\n onlyGovernorOrStrategist\n {\n emit HarvesterAddressesUpdated(harvesterAddress, _harvesterAddress);\n harvesterAddress = _harvesterAddress;\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n virtual;\n\n function safeApproveAllTokens() external virtual;\n\n /**\n * @notice Deposit an amount of assets into the platform\n * @param _asset Address for the asset\n * @param _amount Units of asset to deposit\n */\n function deposit(address _asset, uint256 _amount) external virtual;\n\n /**\n * @notice Deposit all supported assets in this strategy contract to the platform\n */\n function depositAll() external virtual;\n\n /**\n * @notice Withdraw an `amount` of assets from the platform and\n * send to the `_recipient`.\n * @param _recipient Address to which the asset should be sent\n * @param _asset Address of the asset\n * @param _amount Units of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external virtual;\n\n /**\n * @notice Withdraw all supported assets from platform and\n * sends to the OToken's Vault.\n */\n function withdrawAll() external virtual;\n\n /**\n * @notice Get the total asset value held in the platform.\n * This includes any interest that was generated since depositing.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n virtual\n returns (uint256 balance);\n\n /**\n * @notice Check if an asset is supported.\n * @param _asset Address of the asset\n * @return bool Whether asset is supported\n */\n function supportsAsset(address _asset) public view virtual returns (bool);\n}\n" + }, + "contracts/utils/PRBMath.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Copied from the PRBMath library\n// https://github.com/PaulRBerg/prb-math/blob/main/src/Common.sol\n\n/// @notice Calculates the square root of x using the Babylonian method.\n///\n/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n///\n/// Notes:\n/// - If x is not a perfect square, the result is rounded down.\n/// - Credits to OpenZeppelin for the explanations in comments below.\n///\n/// @param x The uint256 number for which to calculate the square root.\n/// @return result The result as a uint256.\n/// @custom:smtchecker abstract-function-nondet\nfunction sqrt(uint256 x) pure returns (uint256 result) {\n if (x == 0) {\n return 0;\n }\n\n // For our first guess, we calculate the biggest power of 2 which is smaller than the square root of x.\n //\n // We know that the \"msb\" (most significant bit) of x is a power of 2 such that we have:\n //\n // $$\n // msb(x) <= x <= 2*msb(x)$\n // $$\n //\n // We write $msb(x)$ as $2^k$, and we get:\n //\n // $$\n // k = log_2(x)\n // $$\n //\n // Thus, we can write the initial inequality as:\n //\n // $$\n // 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\\\\n // sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\\\\n // 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1}\n // $$\n //\n // Consequently, $2^{log_2(x) /2} is a good first approximation of sqrt(x) with at least one correct bit.\n uint256 xAux = uint256(x);\n result = 1;\n if (xAux >= 2**128) {\n xAux >>= 128;\n result <<= 64;\n }\n if (xAux >= 2**64) {\n xAux >>= 64;\n result <<= 32;\n }\n if (xAux >= 2**32) {\n xAux >>= 32;\n result <<= 16;\n }\n if (xAux >= 2**16) {\n xAux >>= 16;\n result <<= 8;\n }\n if (xAux >= 2**8) {\n xAux >>= 8;\n result <<= 4;\n }\n if (xAux >= 2**4) {\n xAux >>= 4;\n result <<= 2;\n }\n if (xAux >= 2**2) {\n result <<= 1;\n }\n\n // At this point, `result` is an estimation with at least one bit of precision. We know the true value has at\n // most 128 bits, since it is the square root of a uint256. Newton's method converges quadratically (precision\n // doubles at every iteration). We thus need at most 7 iteration to turn our partial result with one bit of\n // precision into the expected uint128 result.\n unchecked {\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n\n // If x is not a perfect square, round the result toward zero.\n uint256 roundedResult = x / result;\n if (result >= roundedResult) {\n result = roundedResult;\n }\n }\n}\n" + }, + "contracts/utils/StableMath.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\n// Based on StableMath from Stability Labs Pty. Ltd.\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\n\nlibrary StableMath {\n using SafeMath for uint256;\n\n /**\n * @dev Scaling unit for use in specific calculations,\n * where 1 * 10**18, or 1e18 represents a unit '1'\n */\n uint256 private constant FULL_SCALE = 1e18;\n\n /***************************************\n Helpers\n ****************************************/\n\n /**\n * @dev Adjust the scale of an integer\n * @param to Decimals to scale to\n * @param from Decimals to scale from\n */\n function scaleBy(\n uint256 x,\n uint256 to,\n uint256 from\n ) internal pure returns (uint256) {\n if (to > from) {\n x = x.mul(10**(to - from));\n } else if (to < from) {\n // slither-disable-next-line divide-before-multiply\n x = x.div(10**(from - to));\n }\n return x;\n }\n\n /***************************************\n Precise Arithmetic\n ****************************************/\n\n /**\n * @dev Multiplies two precise units, and then truncates by the full scale\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit\n */\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\n return mulTruncateScale(x, y, FULL_SCALE);\n }\n\n /**\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @param scale Scale unit\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit\n */\n function mulTruncateScale(\n uint256 x,\n uint256 y,\n uint256 scale\n ) internal pure returns (uint256) {\n // e.g. assume scale = fullScale\n // z = 10e18 * 9e17 = 9e36\n uint256 z = x.mul(y);\n // return 9e36 / 1e18 = 9e18\n return z.div(scale);\n }\n\n /**\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit, rounded up to the closest base unit.\n */\n function mulTruncateCeil(uint256 x, uint256 y)\n internal\n pure\n returns (uint256)\n {\n // e.g. 8e17 * 17268172638 = 138145381104e17\n uint256 scaled = x.mul(y);\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\n return ceil.div(FULL_SCALE);\n }\n\n /**\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\n * @param x Left hand input to division\n * @param y Right hand input to division\n * @return Result after multiplying the left operand by the scale, and\n * executing the division on the right hand input.\n */\n function divPrecisely(uint256 x, uint256 y)\n internal\n pure\n returns (uint256)\n {\n // e.g. 8e18 * 1e18 = 8e36\n uint256 z = x.mul(FULL_SCALE);\n // e.g. 8e36 / 10e18 = 8e17\n return z.div(y);\n }\n}\n" + }, + "contracts/vault/OETHBaseVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OETH Base VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OETHBaseVault is VaultAdmin {\n constructor(address _weth) VaultAdmin(_weth) {}\n}\n" + }, + "contracts/vault/OETHPlumeVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OETH Plume VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OETHPlumeVault is VaultAdmin {\n constructor(address _weth) VaultAdmin(_weth) {}\n\n // @inheritdoc VaultAdmin\n function _mint(\n address,\n uint256 _amount,\n uint256\n ) internal virtual {\n // Only Strategist or Governor can mint using the Vault for now.\n // This allows the strateigst to fund the Vault with WETH when\n // removing liquidi from wOETH strategy.\n require(\n msg.sender == strategistAddr || isGovernor(),\n \"Caller is not the Strategist or Governor\"\n );\n\n super._mint(_amount);\n }\n}\n" + }, + "contracts/vault/OETHVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OETH VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OETHVault is VaultAdmin {\n constructor(address _weth) VaultAdmin(_weth) {}\n}\n" + }, + "contracts/vault/OSVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title Origin Sonic VaultAdmin contract on Sonic\n * @author Origin Protocol Inc\n */\ncontract OSVault is VaultAdmin {\n constructor(address _wS) VaultAdmin(_wS) {}\n}\n" + }, + "contracts/vault/OUSDVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OUSD VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OUSDVault is VaultAdmin {\n constructor(address _usdc) VaultAdmin(_usdc) {}\n}\n" + }, + "contracts/vault/VaultAdmin.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultAdmin contract\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\n * @author Origin Protocol Inc\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport \"./VaultCore.sol\";\n\nabstract contract VaultAdmin is VaultCore {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n using SafeCast for uint256;\n\n /**\n * @dev Verifies that the caller is the Governor or Strategist.\n */\n modifier onlyGovernorOrStrategist() {\n require(\n msg.sender == strategistAddr || isGovernor(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n constructor(address _asset) VaultCore(_asset) {}\n\n /***************************************\n Configuration\n ****************************************/\n /**\n * @notice Set a buffer of asset to keep in the Vault to handle most\n * redemptions without needing to spend gas unwinding asset from a Strategy.\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\n */\n function setVaultBuffer(uint256 _vaultBuffer)\n external\n onlyGovernorOrStrategist\n {\n require(_vaultBuffer <= 1e18, \"Invalid value\");\n vaultBuffer = _vaultBuffer;\n emit VaultBufferUpdated(_vaultBuffer);\n }\n\n /**\n * @notice Sets the minimum amount of OTokens in a mint to trigger an\n * automatic allocation of funds afterwords.\n * @param _threshold OToken amount with 18 fixed decimals.\n */\n function setAutoAllocateThreshold(uint256 _threshold)\n external\n onlyGovernor\n {\n autoAllocateThreshold = _threshold;\n emit AllocateThresholdUpdated(_threshold);\n }\n\n /**\n * @notice Set address of Strategist\n * @param _address Address of Strategist\n */\n function setStrategistAddr(address _address) external onlyGovernor {\n strategistAddr = _address;\n emit StrategistUpdated(_address);\n }\n\n /**\n * @notice Set the address authorized to call `rebase()`.\n * @param _operator New operator address. May be set to the zero address\n * to disable operator-initiated rebases.\n */\n function setOperatorAddr(address _operator) external onlyGovernor {\n operatorAddr = _operator;\n emit OperatorUpdated(_operator);\n }\n\n /**\n * @notice Set the default Strategy for asset, i.e. the one which\n * the asset will be automatically allocated to and withdrawn from\n * @param _strategy Address of the Strategy\n */\n function setDefaultStrategy(address _strategy)\n external\n onlyGovernorOrStrategist\n {\n emit DefaultStrategyUpdated(_strategy);\n // If its a zero address being passed for the strategy we are removing\n // the default strategy\n if (_strategy != address(0)) {\n // Make sure the strategy meets some criteria\n require(strategies[_strategy].isSupported, \"Strategy not approved\");\n require(\n IStrategy(_strategy).supportsAsset(asset),\n \"Asset not supported by Strategy\"\n );\n }\n defaultStrategy = _strategy;\n }\n\n /**\n * @notice Changes the async withdrawal claim period for OETH & superOETHb\n * @param _delay Delay period (should be between 10 mins to 7 days).\n * Set to 0 to disable async withdrawals\n */\n function setWithdrawalClaimDelay(uint256 _delay) external onlyGovernor {\n require(\n _delay == 0 || (_delay >= 10 minutes && _delay <= 15 days),\n \"Invalid claim delay period\"\n );\n withdrawalClaimDelay = _delay;\n emit WithdrawalClaimDelayUpdated(_delay);\n }\n\n // slither-disable-start reentrancy-no-eth\n /**\n * @notice Set a yield streaming max rate. This spreads yield over\n * time if it is above the max rate. This is a per rebase APR which\n * due to compounding differs from the yearly APR. Governance should\n * consider this fact when picking a desired APR\n * @param apr in 1e18 notation. 3 * 1e18 = 3% APR\n */\n function setRebaseRateMax(uint256 apr) external onlyGovernorOrStrategist {\n // The old yield will be at the old rate\n _rebase();\n // Change the rate\n uint256 newPerSecond = apr / 100 / 365 days;\n require(newPerSecond <= MAX_REBASE_PER_SECOND, \"Rate too high\");\n rebasePerSecondMax = newPerSecond.toUint64();\n emit RebasePerSecondMaxChanged(newPerSecond);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n // slither-disable-start reentrancy-no-eth\n /**\n * @notice Set the drip duration period\n * @param _dripDuration Time in seconds to target a constant yield rate\n */\n function setDripDuration(uint256 _dripDuration)\n external\n onlyGovernorOrStrategist\n {\n // The old yield will be at the old rate\n _rebase();\n dripDuration = _dripDuration.toUint64();\n emit DripDurationChanged(_dripDuration);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /***************************************\n Strategy Config\n ****************************************/\n\n /**\n * @notice Add a strategy to the Vault.\n * @param _addr Address of the strategy to add\n */\n function approveStrategy(address _addr) external onlyGovernor {\n require(!strategies[_addr].isSupported, \"Strategy already approved\");\n require(\n IStrategy(_addr).supportsAsset(asset),\n \"Asset not supported by Strategy\"\n );\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\n allStrategies.push(_addr);\n emit StrategyApproved(_addr);\n }\n\n /**\n * @notice Remove a strategy from the Vault.\n * @param _addr Address of the strategy to remove\n */\n\n function removeStrategy(address _addr) external onlyGovernor {\n require(strategies[_addr].isSupported, \"Strategy not approved\");\n require(defaultStrategy != _addr, \"Strategy is default for asset\");\n\n // Initialize strategyIndex with out of bounds result so function will\n // revert if no valid index found\n uint256 stratCount = allStrategies.length;\n uint256 strategyIndex = stratCount;\n for (uint256 i = 0; i < stratCount; ++i) {\n if (allStrategies[i] == _addr) {\n strategyIndex = i;\n break;\n }\n }\n\n if (strategyIndex < stratCount) {\n allStrategies[strategyIndex] = allStrategies[stratCount - 1];\n allStrategies.pop();\n\n // Withdraw all assets BEFORE marking as unsupported so that AMO\n // strategies can call burnForStrategy/mintForStrategy during withdrawAll\n IStrategy strategy = IStrategy(_addr);\n // slither-disable-next-line reentrancy-no-eth\n strategy.withdrawAll();\n\n // Mark the strategy as not supported\n strategies[_addr].isSupported = false;\n isMintWhitelistedStrategy[_addr] = false;\n\n // 1e13 for 18 decimals. And 1e1(10) for 6 decimals\n uint256 maxDustBalance = uint256(1e13).scaleBy(assetDecimals, 18);\n\n /*\n * Some strategies are not able to withdraw all of their funds in a synchronous call.\n * Prevent the possible accidental removal of such strategies before their funds are withdrawn.\n */\n require(\n strategy.checkBalance(asset) < maxDustBalance,\n \"Strategy has funds\"\n );\n emit StrategyRemoved(_addr);\n }\n }\n\n /**\n * @notice Adds a strategy to the mint whitelist.\n * Reverts if strategy isn't approved on Vault.\n * @param strategyAddr Strategy address\n */\n function addStrategyToMintWhitelist(address strategyAddr)\n external\n onlyGovernor\n {\n require(strategies[strategyAddr].isSupported, \"Strategy not approved\");\n\n require(\n !isMintWhitelistedStrategy[strategyAddr],\n \"Already whitelisted\"\n );\n\n isMintWhitelistedStrategy[strategyAddr] = true;\n\n emit StrategyAddedToMintWhitelist(strategyAddr);\n }\n\n /**\n * @notice Removes a strategy from the mint whitelist.\n * @param strategyAddr Strategy address\n */\n function removeStrategyFromMintWhitelist(address strategyAddr)\n external\n onlyGovernor\n {\n // Intentionally skipping `strategies.isSupported` check since\n // we may wanna remove an address even after removing the strategy\n\n require(isMintWhitelistedStrategy[strategyAddr], \"Not whitelisted\");\n\n isMintWhitelistedStrategy[strategyAddr] = false;\n\n emit StrategyRemovedFromMintWhitelist(strategyAddr);\n }\n\n /***************************************\n Strategies\n ****************************************/\n\n /**\n * @notice Deposit multiple asset from the vault into the strategy.\n * @param _strategyToAddress Address of the Strategy to deposit asset into.\n * @param _assets Array of asset address that will be deposited into the strategy.\n * @param _amounts Array of amounts of each corresponding asset to deposit.\n */\n function depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external onlyGovernorOrStrategist nonReentrant {\n _depositToStrategy(_strategyToAddress, _assets, _amounts);\n }\n\n function _depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) internal virtual {\n require(\n strategies[_strategyToAddress].isSupported,\n \"Invalid to Strategy\"\n );\n require(\n _assets.length == 1 && _amounts.length == 1 && _assets[0] == asset,\n \"Only asset is supported\"\n );\n\n // Check the there is enough asset to transfer once the backing\n // asset reserved for the withdrawal queue is accounted for\n require(\n _amounts[0] <= _assetAvailable(),\n \"Not enough assets available\"\n );\n\n // Send required amount of funds to the strategy\n IERC20(asset).safeTransfer(_strategyToAddress, _amounts[0]);\n\n // Deposit all the funds that have been sent to the strategy\n IStrategy(_strategyToAddress).depositAll();\n }\n\n /**\n * @notice Withdraw multiple asset from the strategy to the vault.\n * @param _strategyFromAddress Address of the Strategy to withdraw asset from.\n * @param _assets Array of asset address that will be withdrawn from the strategy.\n * @param _amounts Array of amounts of each corresponding asset to withdraw.\n */\n function withdrawFromStrategy(\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external onlyGovernorOrStrategist nonReentrant {\n _withdrawFromStrategy(\n address(this),\n _strategyFromAddress,\n _assets,\n _amounts\n );\n }\n\n /**\n * @param _recipient can either be a strategy or the Vault\n */\n function _withdrawFromStrategy(\n address _recipient,\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) internal virtual {\n require(\n strategies[_strategyFromAddress].isSupported,\n \"Invalid from Strategy\"\n );\n require(_assets.length == _amounts.length, \"Parameter length mismatch\");\n\n uint256 assetCount = _assets.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n // Withdraw from Strategy to the recipient\n IStrategy(_strategyFromAddress).withdraw(\n _recipient,\n _assets[i],\n _amounts[i]\n );\n }\n\n _addWithdrawalQueueLiquidity();\n }\n\n /**\n * @notice Sets the maximum allowable difference between\n * total supply and asset' value.\n */\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\n maxSupplyDiff = _maxSupplyDiff;\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\n }\n\n /**\n * @notice Sets the trusteeAddress that can receive a portion of yield.\n * Setting to the zero address disables this feature.\n */\n function setTrusteeAddress(address _address) external onlyGovernor {\n trusteeAddress = _address;\n emit TrusteeAddressChanged(_address);\n }\n\n /**\n * @notice Sets the TrusteeFeeBps to the percentage of yield that should be\n * received in basis points.\n */\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\n require(_basis <= 5000, \"basis cannot exceed 50%\");\n trusteeFeeBps = _basis;\n emit TrusteeFeeBpsChanged(_basis);\n }\n\n /***************************************\n Pause\n ****************************************/\n\n /**\n * @notice Set the deposit paused flag to true to prevent rebasing.\n */\n function pauseRebase() external onlyGovernorOrStrategist {\n rebasePaused = true;\n emit RebasePaused();\n }\n\n /**\n * @notice Set the deposit paused flag to true to allow rebasing.\n */\n function unpauseRebase() external onlyGovernorOrStrategist {\n rebasePaused = false;\n emit RebaseUnpaused();\n }\n\n /**\n * @notice Set the deposit paused flag to true to prevent capital movement.\n */\n function pauseCapital() external onlyGovernorOrStrategist {\n capitalPaused = true;\n emit CapitalPaused();\n }\n\n /**\n * @notice Set the deposit paused flag to false to enable capital movement.\n */\n function unpauseCapital() external onlyGovernorOrStrategist {\n capitalPaused = false;\n emit CapitalUnpaused();\n }\n\n /***************************************\n Utils\n ****************************************/\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n require(asset != _asset, \"Only unsupported asset\");\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /***************************************\n Strategies Admin\n ****************************************/\n\n /**\n * @notice Withdraws all asset from the strategy and sends asset to the Vault.\n * @param _strategyAddr Strategy address.\n */\n function withdrawAllFromStrategy(address _strategyAddr)\n external\n onlyGovernorOrStrategist\n {\n _withdrawAllFromStrategy(_strategyAddr);\n }\n\n function _withdrawAllFromStrategy(address _strategyAddr) internal virtual {\n require(\n strategies[_strategyAddr].isSupported,\n \"Strategy is not supported\"\n );\n IStrategy strategy = IStrategy(_strategyAddr);\n strategy.withdrawAll();\n _addWithdrawalQueueLiquidity();\n }\n\n /**\n * @notice Withdraws all asset from all the strategies and sends asset to the Vault.\n */\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\n _withdrawAllFromStrategies();\n }\n\n function _withdrawAllFromStrategies() internal virtual {\n uint256 stratCount = allStrategies.length;\n for (uint256 i = 0; i < stratCount; ++i) {\n IStrategy(allStrategies[i]).withdrawAll();\n }\n _addWithdrawalQueueLiquidity();\n }\n}\n" + }, + "contracts/vault/VaultCore.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultCore contract\n * @notice The Vault contract stores asset. On a deposit, OTokens will be minted\n and sent to the depositor. On a withdrawal, OTokens will be burned and\n asset will be sent to the withdrawer. The Vault accepts deposits of\n interest from yield bearing strategies which will modify the supply\n of OTokens.\n * @author Origin Protocol Inc\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\n\nimport \"./VaultInitializer.sol\";\n\nabstract contract VaultCore is VaultInitializer {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n /**\n * @dev Verifies that the rebasing is not paused.\n */\n modifier whenNotRebasePaused() {\n require(!rebasePaused, \"Rebasing paused\");\n _;\n }\n\n /**\n * @dev Verifies that the deposits are not paused.\n */\n modifier whenNotCapitalPaused() {\n require(!capitalPaused, \"Capital paused\");\n _;\n }\n\n constructor(address _asset) VaultInitializer(_asset) {}\n\n ////////////////////////////////////////////////////\n /// MINT / BURN ///\n ////////////////////////////////////////////////////\n /**\n * @notice Deposit a supported asset and mint OTokens.\n * @dev Deprecated: use `mint(uint256 _amount)` instead.\n * @dev Deprecated: param _asset Address of the asset being deposited\n * @param _amount Amount of the asset being deposited\n * @dev Deprecated: param _minimumOusdAmount Minimum OTokens to mint\n */\n function mint(\n address,\n uint256 _amount,\n uint256\n ) external whenNotCapitalPaused nonReentrant {\n _mint(_amount);\n }\n\n /**\n * @notice Deposit a supported asset and mint OTokens.\n * @param _amount Amount of the asset being deposited\n */\n function mint(uint256 _amount) external whenNotCapitalPaused nonReentrant {\n _mint(_amount);\n }\n\n // slither-disable-start reentrancy-no-eth\n /**\n * @dev Deposit a supported asset and mint OTokens.\n * @param _amount Amount of the asset being deposited\n */\n function _mint(uint256 _amount) internal virtual {\n require(_amount > 0, \"Amount must be greater than 0\");\n\n // Scale amount to 18 decimals\n uint256 scaledAmount = _amount.scaleBy(18, assetDecimals);\n\n emit Mint(msg.sender, scaledAmount);\n\n // Mint oTokens\n oToken.mint(msg.sender, scaledAmount);\n\n IERC20(asset).safeTransferFrom(msg.sender, address(this), _amount);\n\n // Give priority to the withdrawal queue for the new asset liquidity\n _addWithdrawalQueueLiquidity();\n\n // Auto-allocate if necessary\n if (scaledAmount >= autoAllocateThreshold) {\n _allocate();\n }\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /**\n * @notice Mint OTokens for an allowed Strategy\n * @param _amount Amount of OToken to mint\n *\n * Notice: can't use `nonReentrant` modifier since the `mint` function can\n * call `allocate`, and that can trigger an AMO strategy to call this function\n * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision.\n *\n * Also important to understand is that this is a limitation imposed by the test suite.\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\n * that are moving funds between the Vault and end user wallets can influence strategies\n * utilizing this function.\n */\n function mintForStrategy(uint256 _amount)\n external\n virtual\n whenNotCapitalPaused\n {\n require(\n strategies[msg.sender].isSupported == true,\n \"Unsupported strategy\"\n );\n require(\n isMintWhitelistedStrategy[msg.sender] == true,\n \"Not whitelisted strategy\"\n );\n\n emit Mint(msg.sender, _amount);\n // Mint matching amount of OTokens\n oToken.mint(msg.sender, _amount);\n }\n\n /**\n * @notice Burn OTokens for an allowed Strategy\n * @param _amount Amount of OToken to burn\n *\n * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could\n * require withdrawal on an AMO strategy and that one can call `burnForStrategy`\n * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision.\n *\n * Also important to understand is that this is a limitation imposed by the test suite.\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\n * that are moving funds between the Vault and end user wallets can influence strategies\n * utilizing this function.\n */\n function burnForStrategy(uint256 _amount)\n external\n virtual\n whenNotCapitalPaused\n {\n require(\n strategies[msg.sender].isSupported == true,\n \"Unsupported strategy\"\n );\n require(\n isMintWhitelistedStrategy[msg.sender] == true,\n \"Not whitelisted strategy\"\n );\n\n emit Redeem(msg.sender, _amount);\n\n // Burn OTokens\n oToken.burn(msg.sender, _amount);\n }\n\n ////////////////////////////////////////////////////\n /// ASYNC WITHDRAWALS ///\n ////////////////////////////////////////////////////\n /**\n * @notice Request an asynchronous withdrawal of asset in exchange for OToken.\n * The OToken is burned on request and the asset is transferred to the withdrawer on claim.\n * This request can be claimed once the withdrawal queue's `claimable` amount\n * is greater than or equal this request's `queued` amount.\n * There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs\n * enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue.\n * OToken is converted to asset at 1:1.\n * @param _amount Amount of OToken to burn.\n * @return requestId Unique ID for the withdrawal request\n * @return queued Cumulative total of all asset queued including already claimed requests.\n */\n function requestWithdrawal(uint256 _amount)\n external\n virtual\n whenNotCapitalPaused\n nonReentrant\n returns (uint256 requestId, uint256 queued)\n {\n require(_amount > 0, \"Amount must be greater than 0\");\n require(withdrawalClaimDelay > 0, \"Async withdrawals not enabled\");\n\n // The check that the requester has enough OToken is done in to later burn call\n\n requestId = withdrawalQueueMetadata.nextWithdrawalIndex;\n queued =\n withdrawalQueueMetadata.queued +\n _amount.scaleBy(assetDecimals, 18);\n\n // Store the next withdrawal request\n withdrawalQueueMetadata.nextWithdrawalIndex = SafeCast.toUint128(\n requestId + 1\n );\n // Store the updated queued amount which reserves asset in the withdrawal queue\n // and reduces the vault's total asset\n withdrawalQueueMetadata.queued = SafeCast.toUint128(queued);\n // Store the user's withdrawal request\n // `queued` is in asset decimals, while `amount` is in OToken decimals (18)\n withdrawalRequests[requestId] = WithdrawalRequest({\n withdrawer: msg.sender,\n claimed: false,\n timestamp: uint40(block.timestamp),\n amount: SafeCast.toUint128(_amount),\n queued: SafeCast.toUint128(queued)\n });\n\n // Burn the user's OToken\n oToken.burn(msg.sender, _amount);\n\n // Prevent withdrawal if the vault is solvent by more than the allowed percentage\n _postRedeem();\n\n emit WithdrawalRequested(msg.sender, requestId, _amount, queued);\n }\n\n // slither-disable-start reentrancy-no-eth\n /**\n * @notice Claim a previously requested withdrawal once it is claimable.\n * This request can be claimed once the withdrawal queue's `claimable` amount\n * is greater than or equal this request's `queued` amount and 10 minutes has passed.\n * If the requests is not claimable, the transaction will revert with `Queue pending liquidity`.\n * If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`.\n * OToken is converted to asset at 1:1.\n * @param _requestId Unique ID for the withdrawal request\n * @return amount Amount of asset transferred to the withdrawer\n */\n function claimWithdrawal(uint256 _requestId)\n external\n virtual\n whenNotCapitalPaused\n nonReentrant\n returns (uint256 amount)\n {\n // Try and get more liquidity if there is not enough available\n if (\n withdrawalRequests[_requestId].queued >\n withdrawalQueueMetadata.claimable\n ) {\n // Add any asset to the withdrawal queue\n // this needs to remain here as:\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\n // - funds can be withdrawn from a strategy\n //\n // Those funds need to be added to withdrawal queue liquidity\n _addWithdrawalQueueLiquidity();\n }\n\n // Scale amount to asset decimals\n amount = _claimWithdrawal(_requestId);\n\n // transfer asset from the vault to the withdrawer\n IERC20(asset).safeTransfer(msg.sender, amount);\n\n // Prevent insolvency\n _postRedeem();\n }\n\n // slither-disable-end reentrancy-no-eth\n /**\n * @notice Claim a previously requested withdrawals once they are claimable.\n * This requests can be claimed once the withdrawal queue's `claimable` amount\n * is greater than or equal each request's `queued` amount and 10 minutes has passed.\n * If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`.\n * If one of the requests is not older than 10 minutes,\n * the whole transaction will revert with `Claim delay not met`.\n * @param _requestIds Unique ID of each withdrawal request\n * @return amounts Amount of asset received for each request\n * @return totalAmount Total amount of asset transferred to the withdrawer\n */\n function claimWithdrawals(uint256[] calldata _requestIds)\n external\n virtual\n whenNotCapitalPaused\n nonReentrant\n returns (uint256[] memory amounts, uint256 totalAmount)\n {\n // Add any asset to the withdrawal queue\n // this needs to remain here as:\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\n // - funds can be withdrawn from a strategy\n //\n // Those funds need to be added to withdrawal queue liquidity\n _addWithdrawalQueueLiquidity();\n\n amounts = new uint256[](_requestIds.length);\n for (uint256 i; i < _requestIds.length; ++i) {\n // Scale all amounts to asset decimals, thus totalAmount is also in asset decimals\n amounts[i] = _claimWithdrawal(_requestIds[i]);\n totalAmount += amounts[i];\n }\n\n // transfer all the claimed asset from the vault to the withdrawer\n IERC20(asset).safeTransfer(msg.sender, totalAmount);\n\n // Prevent insolvency\n _postRedeem();\n\n return (amounts, totalAmount);\n }\n\n function _claimWithdrawal(uint256 requestId)\n internal\n returns (uint256 amount)\n {\n require(withdrawalClaimDelay > 0, \"Async withdrawals not enabled\");\n\n // Load the structs from storage into memory\n WithdrawalRequest memory request = withdrawalRequests[requestId];\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n require(\n request.timestamp + withdrawalClaimDelay <= block.timestamp,\n \"Claim delay not met\"\n );\n // If there isn't enough reserved liquidity in the queue to claim\n require(request.queued <= queue.claimable, \"Queue pending liquidity\");\n require(request.withdrawer == msg.sender, \"Not requester\");\n require(request.claimed == false, \"Already claimed\");\n\n // Store the request as claimed\n withdrawalRequests[requestId].claimed = true;\n // Store the updated claimed amount\n withdrawalQueueMetadata.claimed =\n queue.claimed +\n SafeCast.toUint128(\n StableMath.scaleBy(request.amount, assetDecimals, 18)\n );\n\n emit WithdrawalClaimed(msg.sender, requestId, request.amount);\n\n return StableMath.scaleBy(request.amount, assetDecimals, 18);\n }\n\n function _postRedeem() internal view {\n // Until we can prove that we won't affect the prices of our asset\n // by withdrawing them, this should be here.\n // It's possible that a strategy was off on its asset total, perhaps\n // a reward token sold for more or for less than anticipated.\n uint256 totalUnits = _totalValue();\n\n // Check that the OTokens are backed by enough asset\n if (maxSupplyDiff > 0) {\n // If there are more outstanding withdrawal requests than asset in the vault and strategies\n // then the available asset will be negative and totalUnits will be rounded up to zero.\n // As we don't know the exact shortfall amount, we will reject all redeem and withdrawals\n require(totalUnits > 0, \"Too many outstanding requests\");\n\n // Allow a max difference of maxSupplyDiff% between\n // asset value and OUSD total supply\n uint256 diff = oToken.totalSupply().divPrecisely(totalUnits);\n require(\n (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,\n \"Backing supply liquidity error\"\n );\n }\n }\n\n /**\n * @notice Allocate unallocated funds on Vault to strategies.\n */\n function allocate() external virtual whenNotCapitalPaused nonReentrant {\n // Add any unallocated asset to the withdrawal queue first\n _addWithdrawalQueueLiquidity();\n\n _allocate();\n }\n\n /**\n * @dev Allocate asset (eg. WETH or USDC) to the default asset strategy\n * if there is excess to the Vault buffer.\n * This is called from either `mint` or `allocate` and assumes `_addWithdrawalQueueLiquidity`\n * has been called before this function.\n */\n function _allocate() internal virtual {\n // No need to do anything if no default strategy for asset\n address depositStrategyAddr = defaultStrategy;\n if (depositStrategyAddr == address(0)) return;\n\n uint256 assetAvailableInVault = _assetAvailable();\n // No need to do anything if there isn't any asset in the vault to allocate\n if (assetAvailableInVault == 0) return;\n\n // Calculate the target buffer for the vault using the total supply\n uint256 totalSupply = oToken.totalSupply();\n // Scaled to asset decimals\n uint256 targetBuffer = totalSupply.mulTruncate(vaultBuffer).scaleBy(\n assetDecimals,\n 18\n );\n\n // If available asset in the Vault is below or equal the target buffer then there's nothing to allocate\n if (assetAvailableInVault <= targetBuffer) return;\n\n // The amount of asset to allocate to the default strategy\n uint256 allocateAmount = assetAvailableInVault - targetBuffer;\n\n IStrategy strategy = IStrategy(depositStrategyAddr);\n // Transfer asset to the strategy and call the strategy's deposit function\n IERC20(asset).safeTransfer(address(strategy), allocateAmount);\n strategy.deposit(asset, allocateAmount);\n\n emit AssetAllocated(asset, depositStrategyAddr, allocateAmount);\n }\n\n /**\n * @notice Calculate the total value of asset held by the Vault and all\n * strategies and update the supply of OTokens.\n * @dev Restricted to the Operator, Strategist or Governor.\n */\n function rebase() external virtual nonReentrant {\n require(\n msg.sender == operatorAddr ||\n msg.sender == strategistAddr ||\n isGovernor(),\n \"Caller not authorized\"\n );\n _rebase();\n }\n\n /**\n * @dev Calculate the total value of asset held by the Vault and all\n * strategies and update the supply of OTokens, optionally sending a\n * portion of the yield to the trustee.\n * @return totalUnits Total balance of Vault in units\n */\n function _rebase() internal whenNotRebasePaused returns (uint256) {\n uint256 supply = oToken.totalSupply();\n uint256 vaultValue = _totalValue();\n // If no supply yet, do not rebase\n if (supply == 0) {\n return vaultValue;\n }\n\n // Calculate yield and new supply\n (uint256 yield, uint256 targetRate) = _nextYield(supply, vaultValue);\n uint256 newSupply = supply + yield;\n // Only rebase upwards and if we have enough backing funds\n if (newSupply <= supply || newSupply > vaultValue) {\n return vaultValue;\n }\n\n rebasePerSecondTarget = uint64(_min(targetRate, type(uint64).max));\n lastRebase = uint64(block.timestamp); // Intentional cast\n\n // Fee collection on yield\n address _trusteeAddress = trusteeAddress; // gas savings\n uint256 fee = 0;\n if (_trusteeAddress != address(0)) {\n fee = (yield * trusteeFeeBps) / 1e4;\n if (fee > 0) {\n require(fee < yield, \"Fee must not be greater than yield\");\n oToken.mint(_trusteeAddress, fee);\n }\n }\n emit YieldDistribution(_trusteeAddress, yield, fee);\n\n // Only ratchet OToken supply upwards\n // Final check uses latest totalSupply\n if (newSupply > oToken.totalSupply()) {\n oToken.changeSupply(newSupply);\n }\n return vaultValue;\n }\n\n /**\n * @notice Calculates the amount that would rebase at next rebase.\n * This is before any fees.\n * @return yield amount of expected yield\n */\n function previewYield() external view returns (uint256 yield) {\n (yield, ) = _nextYield(oToken.totalSupply(), _totalValue());\n return yield;\n }\n\n /**\n * @dev Calculates the amount that would rebase at next rebase.\n * See this Readme for detailed explanation:\n * contracts/contracts/vault/README - Yield Limits.md\n */\n function _nextYield(uint256 supply, uint256 vaultValue)\n internal\n view\n virtual\n returns (uint256 yield, uint256 targetRate)\n {\n uint256 nonRebasing = oToken.nonRebasingSupply();\n uint256 rebasing = supply - nonRebasing;\n uint256 elapsed = block.timestamp - lastRebase;\n targetRate = rebasePerSecondTarget;\n\n if (\n elapsed == 0 || // Yield only once per block.\n rebasing == 0 || // No yield if there are no rebasing tokens to give it to.\n supply > vaultValue || // No yield if we do not have yield to give.\n block.timestamp >= type(uint64).max // No yield if we are too far in the future to calculate it correctly.\n ) {\n return (0, targetRate);\n }\n\n // Start with the full difference available\n yield = vaultValue - supply;\n\n // Cap via optional automatic duration smoothing\n uint256 _dripDuration = dripDuration;\n if (_dripDuration > 1) {\n // If we are able to sustain an increased drip rate for\n // double the duration, then increase the target drip rate\n targetRate = _max(targetRate, yield / (_dripDuration * 2));\n // If we cannot sustain the target rate any more,\n // then rebase what we can, and reduce the target\n targetRate = _min(targetRate, yield / _dripDuration);\n // drip at the new target rate\n yield = _min(yield, targetRate * elapsed);\n }\n\n // Cap per second. elapsed is not 1e18 denominated\n yield = _min(yield, (rebasing * elapsed * rebasePerSecondMax) / 1e18);\n\n // Cap at a hard max per rebase, to avoid long durations resulting in huge rebases\n yield = _min(yield, (rebasing * MAX_REBASE) / 1e18);\n\n return (yield, targetRate);\n }\n\n /**\n * @notice Determine the total value of asset held by the vault and its\n * strategies.\n * @return value Total value in USD/ETH (1e18)\n */\n function totalValue() external view virtual returns (uint256 value) {\n value = _totalValue();\n }\n\n /**\n * @dev Internal Calculate the total value of the asset held by the\n * vault and its strategies.\n * @dev The total value of all WETH held by the vault and all its strategies\n * less any WETH that is reserved for the withdrawal queue.\n * If there is not enough WETH in the vault and all strategies to cover\n * all outstanding withdrawal requests then return a total value of 0.\n * @return value Total value in USD/ETH (1e18)\n */\n function _totalValue() internal view virtual returns (uint256 value) {\n // As asset is the only asset, just return the asset balance\n value = _checkBalance(asset).scaleBy(18, assetDecimals);\n }\n\n /**\n * @notice Get the balance of an asset held in Vault and all strategies.\n * @param _asset Address of asset\n * @return uint256 Balance of asset in decimals of asset\n */\n function checkBalance(address _asset) external view returns (uint256) {\n return _checkBalance(_asset);\n }\n\n /**\n * @notice Get the balance of an asset held in Vault and all strategies.\n * @dev Get the balance of an asset held in Vault and all strategies\n * less any asset that is reserved for the withdrawal queue.\n * BaseAsset is the only asset that can return a non-zero balance.\n * All other asset will return 0 even if there is some dust amounts left in the Vault.\n * For example, there is 1 wei left of stETH (or USDC) in the OETH (or OUSD) Vault but\n * will return 0 in this function.\n *\n * If there is not enough asset in the vault and all strategies to cover all outstanding\n * withdrawal requests then return a asset balance of 0\n * @param _asset Address of asset\n * @return balance Balance of asset in decimals of asset\n */\n function _checkBalance(address _asset)\n internal\n view\n virtual\n returns (uint256 balance)\n {\n if (_asset != asset) return 0;\n\n // Get the asset in the vault and the strategies\n IERC20 asset = IERC20(_asset);\n balance = asset.balanceOf(address(this));\n uint256 stratCount = allStrategies.length;\n for (uint256 i = 0; i < stratCount; ++i) {\n IStrategy strategy = IStrategy(allStrategies[i]);\n if (strategy.supportsAsset(_asset)) {\n balance = balance + strategy.checkBalance(_asset);\n }\n }\n\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // If the vault becomes insolvent enough that the total value in the vault and all strategies\n // is less than the outstanding withdrawals.\n // For example, there was a mass slashing event and most users request a withdrawal.\n if (balance + queue.claimed < queue.queued) {\n return 0;\n }\n\n // Need to remove asset that is reserved for the withdrawal queue\n return balance + queue.claimed - queue.queued;\n }\n\n /**\n * @notice Adds WETH to the withdrawal queue if there is a funding shortfall.\n * @dev is called from the Native Staking strategy when validator withdrawals are processed.\n * It also called before any WETH is allocated to a strategy.\n */\n function addWithdrawalQueueLiquidity() external {\n _addWithdrawalQueueLiquidity();\n }\n\n /**\n * @dev Adds asset (eg. WETH or USDC) to the withdrawal queue if there is a funding shortfall.\n * This assumes 1 asset equal 1 corresponding OToken.\n */\n function _addWithdrawalQueueLiquidity()\n internal\n returns (uint256 addedClaimable)\n {\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // Check if the claimable asset is less than the queued amount\n uint256 queueShortfall = queue.queued - queue.claimable;\n\n // No need to do anything is the withdrawal queue is full funded\n if (queueShortfall == 0) {\n return 0;\n }\n\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\n\n // Of the claimable withdrawal requests, how much is unclaimed?\n // That is, the amount of asset that is currently allocated for the withdrawal queue\n uint256 allocatedBaseAsset = queue.claimable - queue.claimed;\n\n // If there is no unallocated asset then there is nothing to add to the queue\n if (assetBalance <= allocatedBaseAsset) {\n return 0;\n }\n\n uint256 unallocatedBaseAsset = assetBalance - allocatedBaseAsset;\n // the new claimable amount is the smaller of the queue shortfall or unallocated asset\n addedClaimable = queueShortfall < unallocatedBaseAsset\n ? queueShortfall\n : unallocatedBaseAsset;\n uint256 newClaimable = queue.claimable + addedClaimable;\n\n // Store the new claimable amount back to storage\n withdrawalQueueMetadata.claimable = SafeCast.toUint128(newClaimable);\n\n // emit a WithdrawalClaimable event\n emit WithdrawalClaimable(newClaimable, addedClaimable);\n }\n\n /**\n * @dev Calculate how much asset (eg. WETH or USDC) in the vault is not reserved for the withdrawal queue.\n * That is, it is available to be redeemed or deposited into a strategy.\n */\n function _assetAvailable() internal view returns (uint256 assetAvailable) {\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // The amount of asset that is still to be claimed in the withdrawal queue\n uint256 outstandingWithdrawals = queue.queued - queue.claimed;\n\n // The amount of sitting in asset in the vault\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\n // If there is not enough asset in the vault to cover the outstanding withdrawals\n if (assetBalance <= outstandingWithdrawals) return 0;\n\n return assetBalance - outstandingWithdrawals;\n }\n\n /***************************************\n Utils\n ****************************************/\n\n /**\n * @notice Return the number of asset supported by the Vault.\n */\n function getAssetCount() public view returns (uint256) {\n return 1;\n }\n\n /**\n * @notice Return all vault asset addresses in order\n */\n function getAllAssets() external view returns (address[] memory) {\n address[] memory a = new address[](1);\n a[0] = asset;\n return a;\n }\n\n /**\n * @notice Return the number of strategies active on the Vault.\n */\n function getStrategyCount() external view returns (uint256) {\n return allStrategies.length;\n }\n\n /**\n * @notice Return the array of all strategies\n */\n function getAllStrategies() external view returns (address[] memory) {\n return allStrategies;\n }\n\n /**\n * @notice Returns whether the vault supports the asset\n * @param _asset address of the asset\n * @return true if supported\n */\n function isSupportedAsset(address _asset) external view returns (bool) {\n return asset == _asset;\n }\n\n function _min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n function _max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n}\n" + }, + "contracts/vault/VaultInitializer.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultInitializer contract\n * @notice The Vault contract initializes the vault.\n * @author Origin Protocol Inc\n */\n\nimport \"./VaultStorage.sol\";\n\nabstract contract VaultInitializer is VaultStorage {\n constructor(address _asset) VaultStorage(_asset) {}\n\n function initialize(address _oToken) external onlyGovernor initializer {\n require(_oToken != address(0), \"oToken address is zero\");\n\n oToken = OUSD(_oToken);\n\n rebasePaused = false;\n capitalPaused = true;\n\n // Initial Vault buffer of 0%\n vaultBuffer = 0;\n // Initial allocate threshold of 25,000 OUSD\n autoAllocateThreshold = 25000e18;\n // Initialize all strategies\n allStrategies = new address[](0);\n // Start with drip duration: 7 days\n dripDuration = 604800;\n }\n}\n" + }, + "contracts/vault/VaultStorage.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultStorage contract\n * @notice The VaultStorage contract defines the storage for the Vault contracts\n * @author Origin Protocol Inc\n */\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { OUSD } from \"../token/OUSD.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport \"../utils/Helpers.sol\";\n\nabstract contract VaultStorage is Initializable, Governable {\n using SafeERC20 for IERC20;\n\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\n event StrategyApproved(address _addr);\n event StrategyRemoved(address _addr);\n event Mint(address _addr, uint256 _value);\n event Redeem(address _addr, uint256 _value);\n event CapitalPaused();\n event CapitalUnpaused();\n event DefaultStrategyUpdated(address _strategy);\n event RebasePaused();\n event RebaseUnpaused();\n event VaultBufferUpdated(uint256 _vaultBuffer);\n event AllocateThresholdUpdated(uint256 _threshold);\n event StrategistUpdated(address _address);\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\n event TrusteeFeeBpsChanged(uint256 _basis);\n event TrusteeAddressChanged(address _address);\n event StrategyAddedToMintWhitelist(address indexed strategy);\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\n event DripDurationChanged(uint256 dripDuration);\n event OperatorUpdated(address newOperator);\n event WithdrawalRequested(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount,\n uint256 _queued\n );\n event WithdrawalClaimed(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount\n );\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\n\n // Since we are proxy, all state should be uninitalized.\n // Since this storage contract does not have logic directly on it\n // we should not be checking for to see if these variables can be constant.\n // slither-disable-start uninitialized-state\n // slither-disable-start constable-states\n\n /// @dev mapping of supported vault assets to their configuration\n uint256 private _deprecated_assets;\n /// @dev list of all assets supported by the vault.\n address[] private _deprecated_allAssets;\n\n // Strategies approved for use by the Vault\n struct Strategy {\n bool isSupported;\n uint256 _deprecated; // Deprecated storage slot\n }\n /// @dev mapping of strategy contracts to their configuration\n mapping(address => Strategy) public strategies;\n /// @dev list of all vault strategies\n address[] internal allStrategies;\n\n /// @notice Address of the Oracle price provider contract\n address private _deprecated_priceProvider;\n /// @notice pause rebasing if true\n bool public rebasePaused;\n /// @notice pause operations that change the OToken supply.\n /// eg mint, redeem, allocate, mint/burn for strategy\n bool public capitalPaused;\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\n uint256 private _deprecated_redeemFeeBps;\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\n uint256 public vaultBuffer;\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\n uint256 public autoAllocateThreshold;\n /// @dev Deprecated. Was the auto-rebase trigger threshold for mint/redeem.\n /// Storage slot retained for proxy compatibility; no longer read or written.\n uint256 internal __deprecatedRebaseThreshold;\n\n /// @dev Address of the OToken token. eg OUSD or OETH.\n OUSD public oToken;\n\n /// @dev Address of the contract responsible for post rebase syncs with AMMs\n address private _deprecated_rebaseHooksAddr = address(0);\n\n /// @dev Deprecated: Address of Uniswap\n address private _deprecated_uniswapAddr = address(0);\n\n /// @notice Address of the Strategist\n address public strategistAddr = address(0);\n\n /// @notice Mapping of asset address to the Strategy that they should automatically\n // be allocated to\n uint256 private _deprecated_assetDefaultStrategies;\n\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\n uint256 public maxSupplyDiff;\n\n /// @notice Trustee contract that can collect a percentage of yield\n address public trusteeAddress;\n\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\n uint256 public trusteeFeeBps;\n\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\n address[] private _deprecated_swapTokens;\n\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\n\n address private _deprecated_ousdMetaStrategy;\n\n /// @notice How much OTokens are currently minted by the strategy\n int256 private _deprecated_netOusdMintedForStrategy;\n\n /// @notice How much net total OTokens are allowed to be minted by all strategies\n uint256 private _deprecated_netOusdMintForStrategyThreshold;\n\n uint256 private _deprecated_swapConfig;\n\n // List of strategies that can mint oTokens directly\n // Used in OETHBaseVaultCore\n mapping(address => bool) public isMintWhitelistedStrategy;\n\n /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\n /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\n address private _deprecated_dripper;\n\n /// Withdrawal Queue Storage /////\n\n struct WithdrawalQueueMetadata {\n // cumulative total of all withdrawal requests included the ones that have already been claimed\n uint128 queued;\n // cumulative total of all the requests that can be claimed including the ones that have already been claimed\n uint128 claimable;\n // total of all the requests that have been claimed\n uint128 claimed;\n // index of the next withdrawal request starting at 0\n uint128 nextWithdrawalIndex;\n }\n\n /// @notice Global metadata for the withdrawal queue including:\n /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed\n /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed\n /// claimed - total of all the requests that have been claimed\n /// nextWithdrawalIndex - index of the next withdrawal request starting at 0\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\n\n struct WithdrawalRequest {\n address withdrawer;\n bool claimed;\n uint40 timestamp; // timestamp of the withdrawal request\n // Amount of oTokens to redeem. eg OETH\n uint128 amount;\n // cumulative total of all withdrawal requests including this one.\n // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\n uint128 queued;\n }\n\n /// @notice Mapping of withdrawal request indices to the user withdrawal request data\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\n\n /// @notice Sets a minimum delay that is required to elapse between\n /// requesting async withdrawals and claiming the request.\n /// When set to 0 async withdrawals are disabled.\n uint256 public withdrawalClaimDelay;\n\n /// @notice Time in seconds that the vault last rebased yield.\n uint64 public lastRebase;\n\n /// @notice Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\n uint64 public dripDuration;\n\n /// @notice max rebase percentage per second\n /// Can be used to set maximum yield of the protocol,\n /// spreading out yield over time\n uint64 public rebasePerSecondMax;\n\n /// @notice target rebase rate limit, based on past rates and funds available.\n uint64 public rebasePerSecondTarget;\n\n uint256 internal constant MAX_REBASE = 0.02 ether;\n uint256 internal constant MAX_REBASE_PER_SECOND =\n uint256(0.05 ether) / 1 days;\n\n /// @notice Default strategy for asset\n address public defaultStrategy;\n\n /// @notice Address authorized to call `rebase()` directly. The Governor\n /// and Strategist are always allowed in addition to this address.\n address public operatorAddr;\n\n // For future use\n uint256[41] private __gap;\n\n /// @notice Index of WETH asset in allAssets array\n /// Legacy OETHVaultCore code, relocated here for vault consistency.\n uint256 private _deprecated_wethAssetIndex;\n\n /// @dev Address of the asset (eg. WETH or USDC)\n address public immutable asset;\n uint8 internal immutable assetDecimals;\n\n // slither-disable-end constable-states\n // slither-disable-end uninitialized-state\n\n constructor(address _asset) {\n uint8 _decimals = IERC20Metadata(_asset).decimals();\n require(_decimals <= 18, \"invalid asset decimals\");\n asset = _asset;\n assetDecimals = _decimals;\n }\n\n /// @notice Deprecated: use `oToken()` instead.\n function oUSD() external view returns (OUSD) {\n return oToken;\n }\n}\n" + }, + "contracts/zapper/AbstractOTokenZapper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\n\nabstract contract AbstractOTokenZapper {\n IERC20 public immutable oToken;\n IERC4626 public immutable wOToken;\n IVault public immutable vault;\n\n IWETH9 public immutable weth;\n\n address private constant ETH_MARKER =\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n event Zap(address indexed minter, address indexed asset, uint256 amount);\n\n constructor(\n address _oToken,\n address _wOToken,\n address _vault,\n address _weth\n ) {\n oToken = IERC20(_oToken);\n wOToken = IERC4626(_wOToken);\n vault = IVault(_vault);\n weth = IWETH9(_weth);\n\n IWETH9(_weth).approve(address(_vault), type(uint256).max);\n IERC20(_oToken).approve(_wOToken, type(uint256).max);\n }\n\n /**\n * @dev Deposit ETH and receive OToken in return.\n * Will verify that the user is sent 1:1 for ETH.\n */\n receive() external payable {\n deposit();\n }\n\n /**\n * @dev Deposit ETH and receive OToken in return\n * Will verify that the user is sent 1:1 for ETH.\n * @return Amount of OETH sent to user\n */\n function deposit() public payable returns (uint256) {\n uint256 balance = address(this).balance;\n\n emit Zap(msg.sender, ETH_MARKER, balance);\n\n // Wrap ETH\n weth.deposit{ value: balance }();\n\n // Mint with WETH\n return _mint(balance, msg.sender);\n }\n\n /**\n * @dev Deposit ETH and receive superOETHb in return\n * @param minReceived min amount of wsuperOETHb to receive\n * @return Amount of wsuperOETHb sent to user\n */\n function depositETHForWrappedTokens(uint256 minReceived)\n external\n payable\n returns (uint256)\n {\n // slither-disable-start reentrancy-balance\n uint256 balance = address(this).balance;\n\n emit Zap(msg.sender, ETH_MARKER, balance);\n\n // Wrap ETH\n weth.deposit{ value: balance }();\n\n // Mint with WETH\n uint256 mintedOToken = _mint(balance, address(this));\n\n // Wrap OToken into wOToken\n uint256 mintedWOToken = wOToken.deposit(mintedOToken, msg.sender);\n\n require(mintedWOToken >= minReceived, \"Zapper: not enough minted\");\n\n // slither-disable-end reentrancy-balance\n return mintedWOToken;\n }\n\n /**\n * @dev Deposit WETH and receive OToken in return\n * @param wethAmount Amount of WETH to deposit\n * @param minReceived min amount of wsuperOETHb to receive\n * @return Amount of wsuperOETHb sent to user\n */\n function depositWETHForWrappedTokens(\n uint256 wethAmount,\n uint256 minReceived\n ) external returns (uint256) {\n // slither-disable-start reentrancy-balance\n // slither-disable-next-line unchecked-transfer unused-return\n weth.transferFrom(msg.sender, address(this), wethAmount);\n\n emit Zap(msg.sender, address(weth), wethAmount);\n\n // Mint with WETH\n uint256 mintedOToken = _mint(wethAmount, address(this));\n\n // Wrap OToken into wOToken\n uint256 mintedWOToken = wOToken.deposit(mintedOToken, msg.sender);\n\n require(mintedWOToken >= minReceived, \"Zapper: not enough minted\");\n\n // slither-disable-end reentrancy-balance\n return mintedWOToken;\n }\n\n /**\n * @dev Internal function to mint superOETHb with WETH\n * @param minOToken Minimum amount of OToken to for user to receive\n * @param recipient Address that receives the tokens\n * @return Amount of OToken sent to user\n */\n function _mint(uint256 minOToken, address recipient)\n internal\n returns (uint256)\n {\n uint256 toMint = weth.balanceOf(address(this));\n vault.mint(toMint);\n uint256 mintedAmount = oToken.balanceOf(address(this));\n require(mintedAmount >= minOToken, \"Zapper: not enough minted\");\n\n if (recipient != address(this)) {\n require(oToken.transfer(recipient, mintedAmount));\n }\n\n return mintedAmount;\n }\n}\n" + }, + "contracts/zapper/OETHBaseZapper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractOTokenZapper } from \"./AbstractOTokenZapper.sol\";\n\ncontract OETHBaseZapper is AbstractOTokenZapper {\n constructor(\n address _oethb,\n address _woethb,\n address _vault\n )\n AbstractOTokenZapper(\n _oethb,\n _woethb,\n _vault,\n 0x4200000000000000000000000000000000000006\n )\n {}\n}\n" + }, + "contracts/zapper/OETHZapper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractOTokenZapper } from \"./AbstractOTokenZapper.sol\";\n\ncontract OETHZapper is AbstractOTokenZapper {\n constructor(\n address _oeth,\n address _woeth,\n address _vault,\n address _weth\n ) AbstractOTokenZapper(_oeth, _woeth, _vault, _weth) {}\n}\n" + }, + "contracts/zapper/OSonicZapper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IWrappedSonic } from \"../interfaces/sonic/IWrappedSonic.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\n\n/**\n * @title Zapper for Origin Sonic (OS) tokens\n * @author Origin Protocol Inc\n */\ncontract OSonicZapper {\n IERC20 public immutable OS;\n IERC4626 public immutable wOS;\n IVault public immutable vault;\n\n IWrappedSonic public constant wS =\n IWrappedSonic(0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38);\n address private constant ETH_MARKER =\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n event Zap(address indexed minter, address indexed asset, uint256 amount);\n\n constructor(\n address _OS,\n address _wOS,\n address _vault\n ) {\n OS = IERC20(_OS);\n wOS = IERC4626(_wOS);\n vault = IVault(_vault);\n\n wS.approve(address(_vault), type(uint256).max);\n IERC20(_OS).approve(_wOS, type(uint256).max);\n }\n\n /**\n * @dev Deposit native S currency and receive Origin Sonic (OS) tokens in return.\n * Will verify that the user is sent 1:1 for S.\n */\n receive() external payable {\n deposit();\n }\n\n /**\n * @dev Deposit native S currency and receive Origin Sonic (OS) tokens in return.\n * Will verify that the user is sent 1:1 for S.\n * @return Amount of Origin Sonic (OS) tokens sent to user\n */\n function deposit() public payable returns (uint256) {\n uint256 balance = address(this).balance;\n\n emit Zap(msg.sender, ETH_MARKER, balance);\n\n // Wrap native S\n wS.deposit{ value: balance }();\n\n // Mint Origin Sonic (OS) with Wrapped Sonic (wS)\n return _mint(balance, msg.sender);\n }\n\n /**\n * @dev Deposit S and receive Wrapped Origin Sonic (wOS) in return\n * @param minReceived min amount of Wrapped Origin Sonic (wOS) to receive\n * @return Amount of Wrapped Origin Sonic (wOS) tokens sent to user\n */\n function depositSForWrappedTokens(uint256 minReceived)\n external\n payable\n returns (uint256)\n {\n // slither-disable-start reentrancy-balance\n uint256 balance = address(this).balance;\n\n emit Zap(msg.sender, ETH_MARKER, balance);\n\n // Wrap S\n wS.deposit{ value: balance }();\n\n // Mint with Wrapped Sonic\n uint256 mintOS = _mint(balance, address(this));\n\n // Wrap Origin Sonic (OS) into Wrapped Origin Sonic (wOS)\n uint256 mintedWOS = wOS.deposit(mintOS, msg.sender);\n\n require(mintedWOS >= minReceived, \"Zapper: not enough minted\");\n\n // slither-disable-end reentrancy-balance\n return mintedWOS;\n }\n\n /**\n * @dev Deposit Wrapped Sonic (wS) tokens and receive Wrapped Origin Sonic (wOS) tokens in return\n * @param wSAmount Amount of Wrapped Sonic (wS) to deposit\n * @param minReceived min amount of Wrapped Origin Sonic (wOS) token to receive\n * @return Amount of Wrapped Origin Sonic (wOS) tokens sent to user\n */\n function depositWSForWrappedTokens(uint256 wSAmount, uint256 minReceived)\n external\n returns (uint256)\n {\n // slither-disable-start reentrancy-balance\n // slither-disable-next-line unchecked-transfer unused-return\n wS.transferFrom(msg.sender, address(this), wSAmount);\n\n emit Zap(msg.sender, address(wS), wSAmount);\n\n // Mint with Wrapped Sonic (wS)\n uint256 mintedOS = _mint(wSAmount, address(this));\n\n // Wrap Origin Sonic (OS) tokens into Wrapped Origin Sonic (wOS) tokens\n uint256 mintedWOS = wOS.deposit(mintedOS, msg.sender);\n\n require(mintedWOS >= minReceived, \"Zapper: not enough minted\");\n\n // slither-disable-end reentrancy-balance\n return mintedWOS;\n }\n\n /**\n * @dev Internal function to mint Origin Sonic (OS) with Wrapped S (wS)\n * @param minOS Minimum amount of Origin Sonic (OS) tokens the user can receive\n * @param recipient Address that receives the tokens\n * @return Amount of Origin Sonic (OS) tokens sent to the recipient\n */\n function _mint(uint256 minOS, address recipient)\n internal\n returns (uint256)\n {\n uint256 toMint = wS.balanceOf(address(this));\n vault.mint(toMint);\n uint256 mintedAmount = OS.balanceOf(address(this));\n require(mintedAmount >= minOS, \"Zapper: not enough minted\");\n\n if (recipient != address(this)) {\n require(OS.transfer(recipient, mintedAmount));\n }\n\n return mintedAmount;\n }\n}\n" + }, + "hardhat/console.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.22 <0.9.0;\n\nlibrary console {\n address constant CONSOLE_ADDRESS =\n 0x000000000000000000636F6e736F6c652e6c6f67;\n\n function _sendLogPayloadImplementation(bytes memory payload) internal view {\n address consoleAddress = CONSOLE_ADDRESS;\n /// @solidity memory-safe-assembly\n assembly {\n pop(\n staticcall(\n gas(),\n consoleAddress,\n add(payload, 32),\n mload(payload),\n 0,\n 0\n )\n )\n }\n }\n\n function _castToPure(\n function(bytes memory) internal view fnIn\n ) internal pure returns (function(bytes memory) pure fnOut) {\n assembly {\n fnOut := fnIn\n }\n }\n\n function _sendLogPayload(bytes memory payload) internal pure {\n _castToPure(_sendLogPayloadImplementation)(payload);\n }\n\n function log() internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log()\"));\n }\n\n function logInt(int256 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(int256)\", p0));\n }\n\n function logUint(uint256 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256)\", p0));\n }\n\n function logString(string memory p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n }\n\n function logBool(bool p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n }\n\n function logAddress(address p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n }\n\n function logBytes(bytes memory p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes)\", p0));\n }\n\n function logBytes1(bytes1 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes1)\", p0));\n }\n\n function logBytes2(bytes2 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes2)\", p0));\n }\n\n function logBytes3(bytes3 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes3)\", p0));\n }\n\n function logBytes4(bytes4 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes4)\", p0));\n }\n\n function logBytes5(bytes5 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes5)\", p0));\n }\n\n function logBytes6(bytes6 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes6)\", p0));\n }\n\n function logBytes7(bytes7 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes7)\", p0));\n }\n\n function logBytes8(bytes8 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes8)\", p0));\n }\n\n function logBytes9(bytes9 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes9)\", p0));\n }\n\n function logBytes10(bytes10 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes10)\", p0));\n }\n\n function logBytes11(bytes11 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes11)\", p0));\n }\n\n function logBytes12(bytes12 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes12)\", p0));\n }\n\n function logBytes13(bytes13 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes13)\", p0));\n }\n\n function logBytes14(bytes14 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes14)\", p0));\n }\n\n function logBytes15(bytes15 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes15)\", p0));\n }\n\n function logBytes16(bytes16 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes16)\", p0));\n }\n\n function logBytes17(bytes17 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes17)\", p0));\n }\n\n function logBytes18(bytes18 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes18)\", p0));\n }\n\n function logBytes19(bytes19 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes19)\", p0));\n }\n\n function logBytes20(bytes20 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes20)\", p0));\n }\n\n function logBytes21(bytes21 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes21)\", p0));\n }\n\n function logBytes22(bytes22 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes22)\", p0));\n }\n\n function logBytes23(bytes23 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes23)\", p0));\n }\n\n function logBytes24(bytes24 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes24)\", p0));\n }\n\n function logBytes25(bytes25 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes25)\", p0));\n }\n\n function logBytes26(bytes26 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes26)\", p0));\n }\n\n function logBytes27(bytes27 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes27)\", p0));\n }\n\n function logBytes28(bytes28 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes28)\", p0));\n }\n\n function logBytes29(bytes29 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes29)\", p0));\n }\n\n function logBytes30(bytes30 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes30)\", p0));\n }\n\n function logBytes31(bytes31 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes31)\", p0));\n }\n\n function logBytes32(bytes32 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes32)\", p0));\n }\n\n function log(uint256 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256)\", p0));\n }\n\n function log(string memory p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n }\n\n function log(bool p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n }\n\n function log(address p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n }\n\n function log(uint256 p0, uint256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256)\", p0, p1));\n }\n\n function log(uint256 p0, string memory p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string)\", p0, p1));\n }\n\n function log(uint256 p0, bool p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool)\", p0, p1));\n }\n\n function log(uint256 p0, address p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address)\", p0, p1));\n }\n\n function log(string memory p0, uint256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256)\", p0, p1));\n }\n\n function log(string memory p0, string memory p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string)\", p0, p1));\n }\n\n function log(string memory p0, bool p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool)\", p0, p1));\n }\n\n function log(string memory p0, address p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address)\", p0, p1));\n }\n\n function log(bool p0, uint256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256)\", p0, p1));\n }\n\n function log(bool p0, string memory p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string)\", p0, p1));\n }\n\n function log(bool p0, bool p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool)\", p0, p1));\n }\n\n function log(bool p0, address p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address)\", p0, p1));\n }\n\n function log(address p0, uint256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256)\", p0, p1));\n }\n\n function log(address p0, string memory p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string)\", p0, p1));\n }\n\n function log(address p0, bool p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool)\", p0, p1));\n }\n\n function log(address p0, address p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address)\", p0, p1));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256)\", p0, p1, p2));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string)\", p0, p1, p2));\n }\n\n function log(uint256 p0, uint256 p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool)\", p0, p1, p2));\n }\n\n function log(uint256 p0, uint256 p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address)\", p0, p1, p2));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256)\", p0, p1, p2));\n }\n\n function log(uint256 p0, string memory p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string)\", p0, p1, p2));\n }\n\n function log(uint256 p0, string memory p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool)\", p0, p1, p2));\n }\n\n function log(uint256 p0, string memory p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address)\", p0, p1, p2));\n }\n\n function log(uint256 p0, bool p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256)\", p0, p1, p2));\n }\n\n function log(uint256 p0, bool p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string)\", p0, p1, p2));\n }\n\n function log(uint256 p0, bool p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool)\", p0, p1, p2));\n }\n\n function log(uint256 p0, bool p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address)\", p0, p1, p2));\n }\n\n function log(uint256 p0, address p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256)\", p0, p1, p2));\n }\n\n function log(uint256 p0, address p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string)\", p0, p1, p2));\n }\n\n function log(uint256 p0, address p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool)\", p0, p1, p2));\n }\n\n function log(uint256 p0, address p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address)\", p0, p1, p2));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256)\", p0, p1, p2));\n }\n\n function log(string memory p0, uint256 p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string)\", p0, p1, p2));\n }\n\n function log(string memory p0, uint256 p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool)\", p0, p1, p2));\n }\n\n function log(string memory p0, uint256 p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address)\", p0, p1, p2));\n }\n\n function log(string memory p0, string memory p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256)\", p0, p1, p2));\n }\n\n function log(string memory p0, string memory p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string)\", p0, p1, p2));\n }\n\n function log(string memory p0, string memory p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool)\", p0, p1, p2));\n }\n\n function log(string memory p0, string memory p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address)\", p0, p1, p2));\n }\n\n function log(string memory p0, bool p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256)\", p0, p1, p2));\n }\n\n function log(string memory p0, bool p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string)\", p0, p1, p2));\n }\n\n function log(string memory p0, bool p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool)\", p0, p1, p2));\n }\n\n function log(string memory p0, bool p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address)\", p0, p1, p2));\n }\n\n function log(string memory p0, address p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256)\", p0, p1, p2));\n }\n\n function log(string memory p0, address p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string)\", p0, p1, p2));\n }\n\n function log(string memory p0, address p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool)\", p0, p1, p2));\n }\n\n function log(string memory p0, address p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address)\", p0, p1, p2));\n }\n\n function log(bool p0, uint256 p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256)\", p0, p1, p2));\n }\n\n function log(bool p0, uint256 p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string)\", p0, p1, p2));\n }\n\n function log(bool p0, uint256 p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool)\", p0, p1, p2));\n }\n\n function log(bool p0, uint256 p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address)\", p0, p1, p2));\n }\n\n function log(bool p0, string memory p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256)\", p0, p1, p2));\n }\n\n function log(bool p0, string memory p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string)\", p0, p1, p2));\n }\n\n function log(bool p0, string memory p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool)\", p0, p1, p2));\n }\n\n function log(bool p0, string memory p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address)\", p0, p1, p2));\n }\n\n function log(bool p0, bool p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256)\", p0, p1, p2));\n }\n\n function log(bool p0, bool p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string)\", p0, p1, p2));\n }\n\n function log(bool p0, bool p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool)\", p0, p1, p2));\n }\n\n function log(bool p0, bool p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address)\", p0, p1, p2));\n }\n\n function log(bool p0, address p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256)\", p0, p1, p2));\n }\n\n function log(bool p0, address p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string)\", p0, p1, p2));\n }\n\n function log(bool p0, address p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool)\", p0, p1, p2));\n }\n\n function log(bool p0, address p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address)\", p0, p1, p2));\n }\n\n function log(address p0, uint256 p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256)\", p0, p1, p2));\n }\n\n function log(address p0, uint256 p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string)\", p0, p1, p2));\n }\n\n function log(address p0, uint256 p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool)\", p0, p1, p2));\n }\n\n function log(address p0, uint256 p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address)\", p0, p1, p2));\n }\n\n function log(address p0, string memory p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256)\", p0, p1, p2));\n }\n\n function log(address p0, string memory p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string)\", p0, p1, p2));\n }\n\n function log(address p0, string memory p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool)\", p0, p1, p2));\n }\n\n function log(address p0, string memory p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address)\", p0, p1, p2));\n }\n\n function log(address p0, bool p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256)\", p0, p1, p2));\n }\n\n function log(address p0, bool p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string)\", p0, p1, p2));\n }\n\n function log(address p0, bool p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool)\", p0, p1, p2));\n }\n\n function log(address p0, bool p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address)\", p0, p1, p2));\n }\n\n function log(address p0, address p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256)\", p0, p1, p2));\n }\n\n function log(address p0, address p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string)\", p0, p1, p2));\n }\n\n function log(address p0, address p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool)\", p0, p1, p2));\n }\n\n function log(address p0, address p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address)\", p0, p1, p2));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,address)\", p0, p1, p2, p3));\n }\n}\n" + }, + "lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IERC4626 } from \"../../../../interfaces/IERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n// From Open Zeppelin draft PR commit:\n// fac43034dca85ff539db3fc8aa2a7084b843d454\n// https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171\n\nabstract contract ERC4626 is ERC20, IERC4626 {\n IERC20Metadata private immutable _asset;\n\n constructor(IERC20Metadata __asset) {\n _asset = __asset;\n }\n\n /** @dev See {IERC4262-asset} */\n function asset() public view virtual override returns (address) {\n return address(_asset);\n }\n\n /** @dev See {IERC4262-totalAssets} */\n function totalAssets() public view virtual override returns (uint256) {\n return _asset.balanceOf(address(this));\n }\n\n /**\n * @dev See {IERC4262-convertToShares}\n *\n * Will revert if asserts > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset\n * would represent an infinite amout of shares.\n */\n function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) {\n uint256 supply = totalSupply();\n\n return\n (assets == 0 || supply == 0)\n ? (assets * 10**decimals()) / 10**_asset.decimals()\n : (assets * supply) / totalAssets();\n }\n\n /** @dev See {IERC4262-convertToAssets} */\n function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) {\n uint256 supply = totalSupply();\n\n return (supply == 0) ? (shares * 10**_asset.decimals()) / 10**decimals() : (shares * totalAssets()) / supply;\n }\n\n /** @dev See {IERC4262-maxDeposit} */\n function maxDeposit(address) public view virtual override returns (uint256) {\n return type(uint256).max;\n }\n\n /** @dev See {IERC4262-maxMint} */\n function maxMint(address) public view virtual override returns (uint256) {\n return type(uint256).max;\n }\n\n /** @dev See {IERC4262-maxWithdraw} */\n function maxWithdraw(address owner) public view virtual override returns (uint256) {\n return convertToAssets(balanceOf(owner));\n }\n\n /** @dev See {IERC4262-maxRedeem} */\n function maxRedeem(address owner) public view virtual override returns (uint256) {\n return balanceOf(owner);\n }\n\n /** @dev See {IERC4262-previewDeposit} */\n function previewDeposit(uint256 assets) public view virtual override returns (uint256) {\n return convertToShares(assets);\n }\n\n /** @dev See {IERC4262-previewMint} */\n function previewMint(uint256 shares) public view virtual override returns (uint256) {\n uint256 assets = convertToAssets(shares);\n return assets + (convertToShares(assets) < shares ? 1 : 0);\n }\n\n /** @dev See {IERC4262-previewWithdraw} */\n function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {\n uint256 shares = convertToShares(assets);\n return shares + (convertToAssets(shares) < assets ? 1 : 0);\n }\n\n /** @dev See {IERC4262-previewRedeem} */\n function previewRedeem(uint256 shares) public view virtual override returns (uint256) {\n return convertToAssets(shares);\n }\n\n /** @dev See {IERC4262-deposit} */\n function deposit(uint256 assets, address receiver) public virtual override returns (uint256) {\n require(assets <= maxDeposit(receiver), \"ERC4626: deposit more then max\");\n\n address caller = _msgSender();\n uint256 shares = previewDeposit(assets);\n\n // if _asset is ERC777, transferFrom can call reenter BEFORE the transfer happens through\n // the tokensToSend hook, so we need to transfer before we mint to keep the invariants.\n SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n _mint(receiver, shares);\n\n emit Deposit(caller, receiver, assets, shares);\n\n return shares;\n }\n\n /** @dev See {IERC4262-mint} */\n function mint(uint256 shares, address receiver) public virtual override returns (uint256) {\n require(shares <= maxMint(receiver), \"ERC4626: mint more then max\");\n\n address caller = _msgSender();\n uint256 assets = previewMint(shares);\n\n // if _asset is ERC777, transferFrom can call reenter BEFORE the transfer happens through\n // the tokensToSend hook, so we need to transfer before we mint to keep the invariants.\n SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n _mint(receiver, shares);\n\n emit Deposit(caller, receiver, assets, shares);\n\n return assets;\n }\n\n /** @dev See {IERC4262-withdraw} */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) public virtual override returns (uint256) {\n require(assets <= maxWithdraw(owner), \"ERC4626: withdraw more then max\");\n\n address caller = _msgSender();\n uint256 shares = previewWithdraw(assets);\n\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n\n // if _asset is ERC777, transfer can call reenter AFTER the transfer happens through\n // the tokensReceived hook, so we need to transfer after we burn to keep the invariants.\n _burn(owner, shares);\n SafeERC20.safeTransfer(_asset, receiver, assets);\n\n emit Withdraw(caller, receiver, owner, assets, shares);\n\n return shares;\n }\n\n /** @dev See {IERC4262-redeem} */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) public virtual override returns (uint256) {\n require(shares <= maxRedeem(owner), \"ERC4626: redeem more then max\");\n\n address caller = _msgSender();\n uint256 assets = previewRedeem(shares);\n\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n\n // if _asset is ERC777, transfer can call reenter AFTER the transfer happens through\n // the tokensReceived hook, so we need to transfer after we burn to keep the invariants.\n _burn(owner, shares);\n SafeERC20.safeTransfer(_asset, receiver, assets);\n\n emit Withdraw(caller, receiver, owner, assets, shares);\n\n return assets;\n }\n\n // Included here, since this method was not yet present in\n // the version of Open Zeppelin ERC20 code we use.\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n}" + }, + "lib/openzeppelin/interfaces/IERC4626.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IERC4626 is IERC20, IERC20Metadata {\n event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);\n\n event Withdraw(\n address indexed caller,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) external returns (uint256 assets);\n}" + }, + "solidity-bytes-utils/contracts/BytesLib.sol": { + "content": "// SPDX-License-Identifier: Unlicense\n/*\n * @title Solidity Bytes Arrays Utils\n * @author Gonçalo Sá \n *\n * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.\n * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.\n */\npragma solidity >=0.8.0 <0.9.0;\n\n\nlibrary BytesLib {\n function concat(\n bytes memory _preBytes,\n bytes memory _postBytes\n )\n internal\n pure\n returns (bytes memory)\n {\n bytes memory tempBytes;\n\n assembly {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // Store the length of the first bytes array at the beginning of\n // the memory for tempBytes.\n let length := mload(_preBytes)\n mstore(tempBytes, length)\n\n // Maintain a memory counter for the current write location in the\n // temp bytes array by adding the 32 bytes for the array length to\n // the starting location.\n let mc := add(tempBytes, 0x20)\n // Stop copying when the memory counter reaches the length of the\n // first bytes array.\n let end := add(mc, length)\n\n for {\n // Initialize a copy counter to the start of the _preBytes data,\n // 32 bytes into its memory.\n let cc := add(_preBytes, 0x20)\n } lt(mc, end) {\n // Increase both counters by 32 bytes each iteration.\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // Write the _preBytes data into the tempBytes memory 32 bytes\n // at a time.\n mstore(mc, mload(cc))\n }\n\n // Add the length of _postBytes to the current length of tempBytes\n // and store it as the new length in the first 32 bytes of the\n // tempBytes memory.\n length := mload(_postBytes)\n mstore(tempBytes, add(length, mload(tempBytes)))\n\n // Move the memory counter back from a multiple of 0x20 to the\n // actual end of the _preBytes data.\n mc := end\n // Stop copying when the memory counter reaches the new combined\n // length of the arrays.\n end := add(mc, length)\n\n for {\n let cc := add(_postBytes, 0x20)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n mstore(mc, mload(cc))\n }\n\n // Update the free-memory pointer by padding our last write location\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\n // next 32 byte block, then round down to the nearest multiple of\n // 32. If the sum of the length of the two arrays is zero then add\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\n mstore(0x40, and(\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\n not(31) // Round down to the nearest 32 bytes.\n ))\n }\n\n return tempBytes;\n }\n\n function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {\n assembly {\n // Read the first 32 bytes of _preBytes storage, which is the length\n // of the array. (We don't need to use the offset into the slot\n // because arrays use the entire slot.)\n let fslot := sload(_preBytes.slot)\n // Arrays of 31 bytes or less have an even value in their slot,\n // while longer arrays have an odd value. The actual length is\n // the slot divided by two for odd values, and the lowest order\n // byte divided by two for even values.\n // If the slot is even, bitwise and the slot with 255 and divide by\n // two to get the length. If the slot is odd, bitwise and the slot\n // with -1 and divide by two.\n let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n let mlength := mload(_postBytes)\n let newlength := add(slength, mlength)\n // slength can contain both the length and contents of the array\n // if length < 32 bytes so let's prepare for that\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n switch add(lt(slength, 32), lt(newlength, 32))\n case 2 {\n // Since the new array still fits in the slot, we just need to\n // update the contents of the slot.\n // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\n sstore(\n _preBytes.slot,\n // all the modifications to the slot are inside this\n // next block\n add(\n // we can just add to the slot contents because the\n // bytes we want to change are the LSBs\n fslot,\n add(\n mul(\n div(\n // load the bytes from memory\n mload(add(_postBytes, 0x20)),\n // zero all bytes to the right\n exp(0x100, sub(32, mlength))\n ),\n // and now shift left the number of bytes to\n // leave space for the length in the slot\n exp(0x100, sub(32, newlength))\n ),\n // increase length by the double of the memory\n // bytes length\n mul(mlength, 2)\n )\n )\n )\n }\n case 1 {\n // The stored value fits in the slot, but the combined value\n // will exceed it.\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n // save new length\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n // The contents of the _postBytes array start 32 bytes into\n // the structure. Our first read should obtain the `submod`\n // bytes that can fit into the unused space in the last word\n // of the stored array. To get this, we read 32 bytes starting\n // from `submod`, so the data we read overlaps with the array\n // contents by `submod` bytes. Masking the lowest-order\n // `submod` bytes allows us to add that value directly to the\n // stored value.\n\n let submod := sub(32, slength)\n let mc := add(_postBytes, submod)\n let end := add(_postBytes, mlength)\n let mask := sub(exp(0x100, submod), 1)\n\n sstore(\n sc,\n add(\n and(\n fslot,\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00\n ),\n and(mload(mc), mask)\n )\n )\n\n for {\n mc := add(mc, 0x20)\n sc := add(sc, 1)\n } lt(mc, end) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n sstore(sc, mload(mc))\n }\n\n mask := exp(0x100, sub(mc, end))\n\n sstore(sc, mul(div(mload(mc), mask), mask))\n }\n default {\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n // Start copying to the last used word of the stored array.\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n // save new length\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n // Copy over the first `submod` bytes of the new data as in\n // case 1 above.\n let slengthmod := mod(slength, 32)\n let mlengthmod := mod(mlength, 32)\n let submod := sub(32, slengthmod)\n let mc := add(_postBytes, submod)\n let end := add(_postBytes, mlength)\n let mask := sub(exp(0x100, submod), 1)\n\n sstore(sc, add(sload(sc), and(mload(mc), mask)))\n\n for {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } lt(mc, end) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n sstore(sc, mload(mc))\n }\n\n mask := exp(0x100, sub(mc, end))\n\n sstore(sc, mul(div(mload(mc), mask), mask))\n }\n }\n }\n\n function slice(\n bytes memory _bytes,\n uint256 _start,\n uint256 _length\n )\n internal\n pure\n returns (bytes memory)\n {\n // We're using the unchecked block below because otherwise execution ends \n // with the native overflow error code.\n unchecked {\n require(_length + 31 >= _length, \"slice_overflow\");\n }\n require(_bytes.length >= _start + _length, \"slice_outOfBounds\");\n\n bytes memory tempBytes;\n\n assembly {\n switch iszero(_length)\n case 0 {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // The first word of the slice result is potentially a partial\n // word read from the original array. To read it, we calculate\n // the length of that partial word and start copying that many\n // bytes into the array. The first word we copy will start with\n // data we don't care about, but the last `lengthmod` bytes will\n // land at the beginning of the contents of the new array. When\n // we're done copying, we overwrite the full first word with\n // the actual length of the slice.\n let lengthmod := and(_length, 31)\n\n // The multiplication in the next line is necessary\n // because when slicing multiples of 32 bytes (lengthmod == 0)\n // the following copy loop was copying the origin's length\n // and then ending prematurely not copying everything it should.\n let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n let end := add(mc, _length)\n\n for {\n // The multiplication in the next line has the same exact purpose\n // as the one above.\n let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n mstore(mc, mload(cc))\n }\n\n mstore(tempBytes, _length)\n\n //update free-memory pointer\n //allocating the array padded to 32 bytes like the compiler does now\n mstore(0x40, and(add(mc, 31), not(31)))\n }\n //if we want a zero-length slice let's just return a zero-length array\n default {\n tempBytes := mload(0x40)\n //zero out the 32 bytes slice we are about to return\n //we need to do it because Solidity does not garbage collect\n mstore(tempBytes, 0)\n\n mstore(0x40, add(tempBytes, 0x20))\n }\n }\n\n return tempBytes;\n }\n\n function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {\n require(_bytes.length >= _start + 20, \"toAddress_outOfBounds\");\n address tempAddress;\n\n assembly {\n tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)\n }\n\n return tempAddress;\n }\n\n function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {\n require(_bytes.length >= _start + 1 , \"toUint8_outOfBounds\");\n uint8 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x1), _start))\n }\n\n return tempUint;\n }\n\n function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {\n require(_bytes.length >= _start + 2, \"toUint16_outOfBounds\");\n uint16 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x2), _start))\n }\n\n return tempUint;\n }\n\n function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {\n require(_bytes.length >= _start + 4, \"toUint32_outOfBounds\");\n uint32 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x4), _start))\n }\n\n return tempUint;\n }\n\n function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {\n require(_bytes.length >= _start + 8, \"toUint64_outOfBounds\");\n uint64 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x8), _start))\n }\n\n return tempUint;\n }\n\n function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {\n require(_bytes.length >= _start + 12, \"toUint96_outOfBounds\");\n uint96 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0xc), _start))\n }\n\n return tempUint;\n }\n\n function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {\n require(_bytes.length >= _start + 16, \"toUint128_outOfBounds\");\n uint128 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x10), _start))\n }\n\n return tempUint;\n }\n\n function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {\n require(_bytes.length >= _start + 32, \"toUint256_outOfBounds\");\n uint256 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempUint;\n }\n\n function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {\n require(_bytes.length >= _start + 32, \"toBytes32_outOfBounds\");\n bytes32 tempBytes32;\n\n assembly {\n tempBytes32 := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempBytes32;\n }\n\n function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {\n bool success = true;\n\n assembly {\n let length := mload(_preBytes)\n\n // if lengths don't match the arrays are not equal\n switch eq(length, mload(_postBytes))\n case 1 {\n // cb is a circuit breaker in the for loop since there's\n // no said feature for inline assembly loops\n // cb = 1 - don't breaker\n // cb = 0 - break\n let cb := 1\n\n let mc := add(_preBytes, 0x20)\n let end := add(mc, length)\n\n for {\n let cc := add(_postBytes, 0x20)\n // the next line is the loop condition:\n // while(uint256(mc < end) + cb == 2)\n } eq(add(lt(mc, end), cb), 2) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // if any of these checks fails then arrays are not equal\n if iszero(eq(mload(mc), mload(cc))) {\n // unsuccess:\n success := 0\n cb := 0\n }\n }\n }\n default {\n // unsuccess:\n success := 0\n }\n }\n\n return success;\n }\n\n function equalStorage(\n bytes storage _preBytes,\n bytes memory _postBytes\n )\n internal\n view\n returns (bool)\n {\n bool success = true;\n\n assembly {\n // we know _preBytes_offset is 0\n let fslot := sload(_preBytes.slot)\n // Decode the length of the stored array like in concatStorage().\n let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n let mlength := mload(_postBytes)\n\n // if lengths don't match the arrays are not equal\n switch eq(slength, mlength)\n case 1 {\n // slength can contain both the length and contents of the array\n // if length < 32 bytes so let's prepare for that\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n if iszero(iszero(slength)) {\n switch lt(slength, 32)\n case 1 {\n // blank the last byte which is the length\n fslot := mul(div(fslot, 0x100), 0x100)\n\n if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\n // unsuccess:\n success := 0\n }\n }\n default {\n // cb is a circuit breaker in the for loop since there's\n // no said feature for inline assembly loops\n // cb = 1 - don't breaker\n // cb = 0 - break\n let cb := 1\n\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n let sc := keccak256(0x0, 0x20)\n\n let mc := add(_postBytes, 0x20)\n let end := add(mc, mlength)\n\n // the next line is the loop condition:\n // while(uint256(mc < end) + cb == 2)\n for {} eq(add(lt(mc, end), cb), 2) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n if iszero(eq(sload(sc), mload(mc))) {\n // unsuccess:\n success := 0\n cb := 0\n }\n }\n }\n }\n }\n default {\n // unsuccess:\n success := 0\n }\n }\n\n return success;\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "evmVersion": "paris", + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/contracts/deployments/mainnet/OETHVault.json b/contracts/deployments/mainnet/OETHVault.json index 8075d6dd58..6150195b6d 100644 --- a/contracts/deployments/mainnet/OETHVault.json +++ b/contracts/deployments/mainnet/OETHVault.json @@ -1,5 +1,5 @@ { - "address": "0x27E6e612dB61f5ebE3211a0719EEc00FbFC595e0", + "address": "0x0E979edF516f88119fa2843fA3f08A9643F8e575", "abi": [ { "inputs": [ @@ -139,6 +139,19 @@ "name": "Mint", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newOperator", + "type": "address" + } + ], + "name": "OperatorUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -177,19 +190,6 @@ "name": "RebasePerSecondMaxChanged", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "_threshold", - "type": "uint256" - } - ], - "name": "RebaseThresholdUpdated", - "type": "event" - }, { "anonymous": false, "inputs": [], @@ -872,6 +872,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "operatorAddr", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "pauseCapital", @@ -945,19 +958,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "rebaseThreshold", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -1063,12 +1063,12 @@ { "inputs": [ { - "internalType": "uint256", - "name": "apr", - "type": "uint256" + "internalType": "address", + "name": "_operator", + "type": "address" } ], - "name": "setRebaseRateMax", + "name": "setOperatorAddr", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -1077,11 +1077,11 @@ "inputs": [ { "internalType": "uint256", - "name": "_threshold", + "name": "apr", "type": "uint256" } ], - "name": "setRebaseThreshold", + "name": "setRebaseRateMax", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -1409,30 +1409,30 @@ "type": "function" } ], - "transactionHash": "0xa88bf8245427e4deb0d94c80017d75ea24755987e140cec2133d519e45b1f482", + "transactionHash": "0xf28227a33307bf55fcfd00cbef4491271a194c7d9fc25062ee920c2d3e81d340", "receipt": { "to": null, - "from": "0xDba474FeF81bc7475f70e28DFC12410f032A83Db", - "contractAddress": "0x27E6e612dB61f5ebE3211a0719EEc00FbFC595e0", - "transactionIndex": 77, - "gasUsed": "4593960", + "from": "0x58890A9cB27586E83Cb51d2d26bbE18a1a647245", + "contractAddress": "0x0E979edF516f88119fa2843fA3f08A9643F8e575", + "transactionIndex": 165, + "gasUsed": "4587717", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xe15b28453bbb09cc3f39e9b58981b411dd0e65125da6f88a524144f9b47226f6", - "transactionHash": "0xa88bf8245427e4deb0d94c80017d75ea24755987e140cec2133d519e45b1f482", + "blockHash": "0xf31b6817501d31f654eeb313c5e69f13573799335ded9b81016828069926509d", + "transactionHash": "0xf28227a33307bf55fcfd00cbef4491271a194c7d9fc25062ee920c2d3e81d340", "logs": [], - "blockNumber": 24598455, - "cumulativeGasUsed": "23081232", + "blockNumber": 25063939, + "cumulativeGasUsed": "26717964", "status": 1, "byzantium": true }, "args": [ "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" ], - "numDeployments": 2, - "solcInputHash": "ef6171d107508ae04c8fb89562e479dd", - "metadata": "{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"AllocateThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"AssetAllocated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"DefaultStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dripDuration\",\"type\":\"uint256\"}],\"name\":\"DripDurationChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"MaxSupplyDiffChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebasePaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rebaseRatePerSecond\",\"type\":\"uint256\"}],\"name\":\"RebasePerSecondMaxChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"RebaseThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebaseUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"StrategistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyAddedToMintWhitelist\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyRemovedFromMintWhitelist\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"TrusteeAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"TrusteeFeeBpsChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"VaultBufferUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newDelay\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_claimable\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newClaimable\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimable\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_queued\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_yield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"YieldDistribution\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddr\",\"type\":\"address\"}],\"name\":\"addStrategyToMintWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"addWithdrawalQueueLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"allocate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"approveStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"asset\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"autoAllocateThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"burnForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capitalPaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"claimWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_requestIds\",\"type\":\"uint256[]\"}],\"name\":\"claimWithdrawals\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"totalAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultStrategy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyToAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"depositToStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dripDuration\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAssets\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllStrategies\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAssetCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStrategyCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_oToken\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isMintWhitelistedStrategy\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"isSupportedAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRebase\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxSupplyDiff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mintForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oToken\",\"outputs\":[{\"internalType\":\"contract OUSD\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oUSD\",\"outputs\":[{\"internalType\":\"contract OUSD\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previewYield\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"yield\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePerSecondMax\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePerSecondTarget\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebaseThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"removeStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddr\",\"type\":\"address\"}],\"name\":\"removeStrategyFromMintWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"requestWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"queued\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setAutoAllocateThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"setDefaultStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dripDuration\",\"type\":\"uint256\"}],\"name\":\"setDripDuration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"setMaxSupplyDiff\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"apr\",\"type\":\"uint256\"}],\"name\":\"setRebaseRateMax\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setRebaseThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setStrategistAddr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setTrusteeAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"setTrusteeFeeBps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"setVaultBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_delay\",\"type\":\"uint256\"}],\"name\":\"setWithdrawalClaimDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"strategies\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isSupported\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"_deprecated\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategistAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"transferToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAllFromStrategies\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"}],\"name\":\"withdrawAllFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyFromAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"withdrawFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalClaimDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalQueueMetadata\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimable\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimed\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"nextWithdrawalIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"withdrawalRequests\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"claimed\",\"type\":\"bool\"},{\"internalType\":\"uint40\",\"name\":\"timestamp\",\"type\":\"uint40\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"addStrategyToMintWhitelist(address)\":{\"params\":{\"strategyAddr\":\"Strategy address\"}},\"addWithdrawalQueueLiquidity()\":{\"details\":\"is called from the Native Staking strategy when validator withdrawals are processed. It also called before any WETH is allocated to a strategy.\"},\"approveStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to add\"}},\"burnForStrategy(uint256)\":{\"details\":\"Notice: can't use `nonReentrant` modifier since the `redeem` function could require withdrawal on an AMO strategy and that one can call `burnForStrategy` while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\",\"params\":{\"_amount\":\"Amount of OToken to burn\"}},\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of asset\"},\"returns\":{\"_0\":\"uint256 Balance of asset in decimals of asset\"}},\"claimWithdrawal(uint256)\":{\"params\":{\"_requestId\":\"Unique ID for the withdrawal request\"},\"returns\":{\"amount\":\"Amount of asset transferred to the withdrawer\"}},\"claimWithdrawals(uint256[])\":{\"params\":{\"_requestIds\":\"Unique ID of each withdrawal request\"},\"returns\":{\"amounts\":\"Amount of asset received for each request\",\"totalAmount\":\"Total amount of asset transferred to the withdrawer\"}},\"depositToStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to deposit.\",\"_assets\":\"Array of asset address that will be deposited into the strategy.\",\"_strategyToAddress\":\"Address of the Strategy to deposit asset into.\"}},\"isSupportedAsset(address)\":{\"params\":{\"_asset\":\"address of the asset\"},\"returns\":{\"_0\":\"true if supported\"}},\"mint(address,uint256,uint256)\":{\"details\":\"Deprecated: use `mint(uint256 _amount)` instead.Deprecated: param _asset Address of the asset being depositedDeprecated: param _minimumOusdAmount Minimum OTokens to mint\",\"params\":{\"_amount\":\"Amount of the asset being deposited\"}},\"mint(uint256)\":{\"params\":{\"_amount\":\"Amount of the asset being deposited\"}},\"mintForStrategy(uint256)\":{\"params\":{\"_amount\":\"Amount of OToken to mint Notice: can't use `nonReentrant` modifier since the `mint` function can call `allocate`, and that can trigger an AMO strategy to call this function while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\"}},\"previewYield()\":{\"returns\":{\"yield\":\"amount of expected yield\"}},\"removeStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to remove\"}},\"removeStrategyFromMintWhitelist(address)\":{\"params\":{\"strategyAddr\":\"Strategy address\"}},\"requestWithdrawal(uint256)\":{\"params\":{\"_amount\":\"Amount of OToken to burn.\"},\"returns\":{\"queued\":\"Cumulative total of all asset queued including already claimed requests.\",\"requestId\":\"Unique ID for the withdrawal request\"}},\"setAutoAllocateThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setDefaultStrategy(address)\":{\"params\":{\"_strategy\":\"Address of the Strategy\"}},\"setDripDuration(uint256)\":{\"params\":{\"_dripDuration\":\"Time in seconds to target a constant yield rate\"}},\"setRebaseRateMax(uint256)\":{\"params\":{\"apr\":\"in 1e18 notation. 3 * 1e18 = 3% APR\"}},\"setRebaseThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setStrategistAddr(address)\":{\"params\":{\"_address\":\"Address of Strategist\"}},\"setVaultBuffer(uint256)\":{\"params\":{\"_vaultBuffer\":\"Percentage using 18 decimals. 100% = 1e18.\"}},\"setWithdrawalClaimDelay(uint256)\":{\"params\":{\"_delay\":\"Delay period (should be between 10 mins to 7 days). Set to 0 to disable async withdrawals\"}},\"totalValue()\":{\"returns\":{\"value\":\"Total value in USD/ETH (1e18)\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"transferToken(address,uint256)\":{\"params\":{\"_amount\":\"Amount of the asset to transfer\",\"_asset\":\"Address for the asset\"}},\"withdrawAllFromStrategy(address)\":{\"params\":{\"_strategyAddr\":\"Strategy address.\"}},\"withdrawFromStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to withdraw.\",\"_assets\":\"Array of asset address that will be withdrawn from the strategy.\",\"_strategyFromAddress\":\"Address of the Strategy to withdraw asset from.\"}}},\"title\":\"OETH VaultAdmin Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"addStrategyToMintWhitelist(address)\":{\"notice\":\"Adds a strategy to the mint whitelist. Reverts if strategy isn't approved on Vault.\"},\"addWithdrawalQueueLiquidity()\":{\"notice\":\"Adds WETH to the withdrawal queue if there is a funding shortfall.\"},\"allocate()\":{\"notice\":\"Allocate unallocated funds on Vault to strategies.\"},\"approveStrategy(address)\":{\"notice\":\"Add a strategy to the Vault.\"},\"autoAllocateThreshold()\":{\"notice\":\"OToken mints over this amount automatically allocate funds. 18 decimals.\"},\"burnForStrategy(uint256)\":{\"notice\":\"Burn OTokens for an allowed Strategy\"},\"capitalPaused()\":{\"notice\":\"pause operations that change the OToken supply. eg mint, redeem, allocate, mint/burn for strategy\"},\"checkBalance(address)\":{\"notice\":\"Get the balance of an asset held in Vault and all strategies.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"claimWithdrawal(uint256)\":{\"notice\":\"Claim a previously requested withdrawal once it is claimable. This request can be claimed once the withdrawal queue's `claimable` amount is greater than or equal this request's `queued` amount and 10 minutes has passed. If the requests is not claimable, the transaction will revert with `Queue pending liquidity`. If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`. OToken is converted to asset at 1:1.\"},\"claimWithdrawals(uint256[])\":{\"notice\":\"Claim a previously requested withdrawals once they are claimable. This requests can be claimed once the withdrawal queue's `claimable` amount is greater than or equal each request's `queued` amount and 10 minutes has passed. If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`. If one of the requests is not older than 10 minutes, the whole transaction will revert with `Claim delay not met`.\"},\"defaultStrategy()\":{\"notice\":\"Default strategy for asset\"},\"depositToStrategy(address,address[],uint256[])\":{\"notice\":\"Deposit multiple asset from the vault into the strategy.\"},\"dripDuration()\":{\"notice\":\"Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\"},\"getAllAssets()\":{\"notice\":\"Return all vault asset addresses in order\"},\"getAllStrategies()\":{\"notice\":\"Return the array of all strategies\"},\"getAssetCount()\":{\"notice\":\"Return the number of asset supported by the Vault.\"},\"getStrategyCount()\":{\"notice\":\"Return the number of strategies active on the Vault.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"isSupportedAsset(address)\":{\"notice\":\"Returns whether the vault supports the asset\"},\"lastRebase()\":{\"notice\":\"Time in seconds that the vault last rebased yield.\"},\"maxSupplyDiff()\":{\"notice\":\"Max difference between total supply and total value of assets. 18 decimals.\"},\"mint(address,uint256,uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mint(uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mintForStrategy(uint256)\":{\"notice\":\"Mint OTokens for an allowed Strategy\"},\"oUSD()\":{\"notice\":\"Deprecated: use `oToken()` instead.\"},\"pauseCapital()\":{\"notice\":\"Set the deposit paused flag to true to prevent capital movement.\"},\"pauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to prevent rebasing.\"},\"previewYield()\":{\"notice\":\"Calculates the amount that would rebase at next rebase. This is before any fees.\"},\"rebase()\":{\"notice\":\"Calculate the total value of asset held by the Vault and all strategies and update the supply of OTokens.\"},\"rebasePaused()\":{\"notice\":\"pause rebasing if true\"},\"rebasePerSecondMax()\":{\"notice\":\"max rebase percentage per second Can be used to set maximum yield of the protocol, spreading out yield over time\"},\"rebasePerSecondTarget()\":{\"notice\":\"target rebase rate limit, based on past rates and funds available.\"},\"rebaseThreshold()\":{\"notice\":\"OToken mints over this amount automatically rebase. 18 decimals.\"},\"removeStrategy(address)\":{\"notice\":\"Remove a strategy from the Vault.\"},\"removeStrategyFromMintWhitelist(address)\":{\"notice\":\"Removes a strategy from the mint whitelist.\"},\"requestWithdrawal(uint256)\":{\"notice\":\"Request an asynchronous withdrawal of asset in exchange for OToken. The OToken is burned on request and the asset is transferred to the withdrawer on claim. This request can be claimed once the withdrawal queue's `claimable` amount is greater than or equal this request's `queued` amount. There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue. OToken is converted to asset at 1:1.\"},\"setAutoAllocateThreshold(uint256)\":{\"notice\":\"Sets the minimum amount of OTokens in a mint to trigger an automatic allocation of funds afterwords.\"},\"setDefaultStrategy(address)\":{\"notice\":\"Set the default Strategy for asset, i.e. the one which the asset will be automatically allocated to and withdrawn from\"},\"setDripDuration(uint256)\":{\"notice\":\"Set the drip duration period\"},\"setMaxSupplyDiff(uint256)\":{\"notice\":\"Sets the maximum allowable difference between total supply and asset' value.\"},\"setRebaseRateMax(uint256)\":{\"notice\":\"Set a yield streaming max rate. This spreads yield over time if it is above the max rate. This is a per rebase APR which due to compounding differs from the yearly APR. Governance should consider this fact when picking a desired APR\"},\"setRebaseThreshold(uint256)\":{\"notice\":\"Set a minimum amount of OTokens in a mint or redeem that triggers a rebase\"},\"setStrategistAddr(address)\":{\"notice\":\"Set address of Strategist\"},\"setTrusteeAddress(address)\":{\"notice\":\"Sets the trusteeAddress that can receive a portion of yield. Setting to the zero address disables this feature.\"},\"setTrusteeFeeBps(uint256)\":{\"notice\":\"Sets the TrusteeFeeBps to the percentage of yield that should be received in basis points.\"},\"setVaultBuffer(uint256)\":{\"notice\":\"Set a buffer of asset to keep in the Vault to handle most redemptions without needing to spend gas unwinding asset from a Strategy.\"},\"setWithdrawalClaimDelay(uint256)\":{\"notice\":\"Changes the async withdrawal claim period for OETH & superOETHb\"},\"strategistAddr()\":{\"notice\":\"Address of the Strategist\"},\"totalValue()\":{\"notice\":\"Determine the total value of asset held by the vault and its strategies.\"},\"transferGovernance(address)\":{\"notice\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\"},\"transferToken(address,uint256)\":{\"notice\":\"Transfer token to governor. Intended for recovering tokens stuck in contract, i.e. mistaken sends.\"},\"trusteeAddress()\":{\"notice\":\"Trustee contract that can collect a percentage of yield\"},\"trusteeFeeBps()\":{\"notice\":\"Amount of yield collected in basis points. eg 2000 = 20%\"},\"unpauseCapital()\":{\"notice\":\"Set the deposit paused flag to false to enable capital movement.\"},\"unpauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to allow rebasing.\"},\"vaultBuffer()\":{\"notice\":\"Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\"},\"withdrawAllFromStrategies()\":{\"notice\":\"Withdraws all asset from all the strategies and sends asset to the Vault.\"},\"withdrawAllFromStrategy(address)\":{\"notice\":\"Withdraws all asset from the strategy and sends asset to the Vault.\"},\"withdrawFromStrategy(address,address[],uint256[])\":{\"notice\":\"Withdraw multiple asset from the strategy to the vault.\"},\"withdrawalClaimDelay()\":{\"notice\":\"Sets a minimum delay that is required to elapse between requesting async withdrawals and claiming the request. When set to 0 async withdrawals are disabled.\"},\"withdrawalQueueMetadata()\":{\"notice\":\"Global metadata for the withdrawal queue including: queued - cumulative total of all withdrawal requests included the ones that have already been claimed claimable - cumulative total of all the requests that can be claimed including the ones already claimed claimed - total of all the requests that have been claimed nextWithdrawalIndex - index of the next withdrawal request starting at 0\"},\"withdrawalRequests(uint256)\":{\"notice\":\"Mapping of withdrawal request indices to the user withdrawal request data\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/vault/OETHVault.sol\":\"OETHVault\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0x61437cb513a887a1bbad006e7b1c8b414478427d33de47c5600af3c748f108da\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeCast.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\\n * checks.\\n *\\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\\n * easily result in undesired exploitation or bugs, since developers usually\\n * assume that overflows raise errors. `SafeCast` restores this intuition by\\n * reverting the transaction when such an operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n *\\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\\n * all math on `uint256` and `int256` and then downcasting.\\n */\\nlibrary SafeCast {\\n /**\\n * @dev Returns the downcasted uint224 from uint256, reverting on\\n * overflow (when the input is greater than largest uint224).\\n *\\n * Counterpart to Solidity's `uint224` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 224 bits\\n */\\n function toUint224(uint256 value) internal pure returns (uint224) {\\n require(value <= type(uint224).max, \\\"SafeCast: value doesn't fit in 224 bits\\\");\\n return uint224(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint128 from uint256, reverting on\\n * overflow (when the input is greater than largest uint128).\\n *\\n * Counterpart to Solidity's `uint128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n */\\n function toUint128(uint256 value) internal pure returns (uint128) {\\n require(value <= type(uint128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return uint128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint96 from uint256, reverting on\\n * overflow (when the input is greater than largest uint96).\\n *\\n * Counterpart to Solidity's `uint96` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 96 bits\\n */\\n function toUint96(uint256 value) internal pure returns (uint96) {\\n require(value <= type(uint96).max, \\\"SafeCast: value doesn't fit in 96 bits\\\");\\n return uint96(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint64 from uint256, reverting on\\n * overflow (when the input is greater than largest uint64).\\n *\\n * Counterpart to Solidity's `uint64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n */\\n function toUint64(uint256 value) internal pure returns (uint64) {\\n require(value <= type(uint64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return uint64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint32 from uint256, reverting on\\n * overflow (when the input is greater than largest uint32).\\n *\\n * Counterpart to Solidity's `uint32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n */\\n function toUint32(uint256 value) internal pure returns (uint32) {\\n require(value <= type(uint32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return uint32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint16 from uint256, reverting on\\n * overflow (when the input is greater than largest uint16).\\n *\\n * Counterpart to Solidity's `uint16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n */\\n function toUint16(uint256 value) internal pure returns (uint16) {\\n require(value <= type(uint16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return uint16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint8 from uint256, reverting on\\n * overflow (when the input is greater than largest uint8).\\n *\\n * Counterpart to Solidity's `uint8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits.\\n */\\n function toUint8(uint256 value) internal pure returns (uint8) {\\n require(value <= type(uint8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return uint8(value);\\n }\\n\\n /**\\n * @dev Converts a signed int256 into an unsigned uint256.\\n *\\n * Requirements:\\n *\\n * - input must be greater than or equal to 0.\\n */\\n function toUint256(int256 value) internal pure returns (uint256) {\\n require(value >= 0, \\\"SafeCast: value must be positive\\\");\\n return uint256(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int128 from int256, reverting on\\n * overflow (when the input is less than smallest int128 or\\n * greater than largest int128).\\n *\\n * Counterpart to Solidity's `int128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt128(int256 value) internal pure returns (int128) {\\n require(value >= type(int128).min && value <= type(int128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return int128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int64 from int256, reverting on\\n * overflow (when the input is less than smallest int64 or\\n * greater than largest int64).\\n *\\n * Counterpart to Solidity's `int64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt64(int256 value) internal pure returns (int64) {\\n require(value >= type(int64).min && value <= type(int64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return int64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int32 from int256, reverting on\\n * overflow (when the input is less than smallest int32 or\\n * greater than largest int32).\\n *\\n * Counterpart to Solidity's `int32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt32(int256 value) internal pure returns (int32) {\\n require(value >= type(int32).min && value <= type(int32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return int32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int16 from int256, reverting on\\n * overflow (when the input is less than smallest int16 or\\n * greater than largest int16).\\n *\\n * Counterpart to Solidity's `int16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt16(int256 value) internal pure returns (int16) {\\n require(value >= type(int16).min && value <= type(int16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return int16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int8 from int256, reverting on\\n * overflow (when the input is less than smallest int8 or\\n * greater than largest int8).\\n *\\n * Counterpart to Solidity's `int8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits.\\n *\\n * _Available since v3.1._\\n */\\n function toInt8(int256 value) internal pure returns (int8) {\\n require(value >= type(int8).min && value <= type(int8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return int8(value);\\n }\\n\\n /**\\n * @dev Converts an unsigned uint256 into a signed int256.\\n *\\n * Requirements:\\n *\\n * - input must be less than or equal to maxInt256.\\n */\\n function toInt256(uint256 value) internal pure returns (int256) {\\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\\n require(value <= uint256(type(int256).max), \\\"SafeCast: value doesn't fit in an int256\\\");\\n return int256(value);\\n }\\n}\\n\",\"keccak256\":\"0x5c6caab697d302ad7eb59c234a4d2dbc965c1bae87709bd2850060b7695b28c7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa2f576be637946f767aa56601c26d717f48a0aff44f82e46f13807eea1009a21\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @notice Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @notice Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n emit GovernorshipTransferred(_governor(), newGovernor);\\n\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0xf32f873c8bfbacf2e5f01d0cf37bc7f54fbd5aa656e95c8a599114229946f107\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xa562062698aa12572123b36dfd2072f1a39e44fed2031cc19c2c9fd522f96ec2\",\"license\":\"MIT\"},\"contracts/interfaces/IStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\\n */\\ninterface IStrategy {\\n /**\\n * @dev Deposit the given asset to platform\\n * @param _asset asset address\\n * @param _amount Amount to deposit\\n */\\n function deposit(address _asset, uint256 _amount) external;\\n\\n /**\\n * @dev Deposit the entire balance of all supported assets in the Strategy\\n * to the platform\\n */\\n function depositAll() external;\\n\\n /**\\n * @dev Withdraw given asset from Lending platform\\n */\\n function withdraw(\\n address _recipient,\\n address _asset,\\n uint256 _amount\\n ) external;\\n\\n /**\\n * @dev Liquidate all assets in strategy and return them to Vault.\\n */\\n function withdrawAll() external;\\n\\n /**\\n * @dev Returns the current balance of the given asset.\\n */\\n function checkBalance(address _asset)\\n external\\n view\\n returns (uint256 balance);\\n\\n /**\\n * @dev Returns bool indicating whether strategy supports asset.\\n */\\n function supportsAsset(address _asset) external view returns (bool);\\n\\n /**\\n * @dev Collect reward tokens from the Strategy.\\n */\\n function collectRewardTokens() external;\\n\\n /**\\n * @dev The address array of the reward tokens for the Strategy.\\n */\\n function getRewardTokenAddresses() external view returns (address[] memory);\\n\\n function harvesterAddress() external view returns (address);\\n\\n function transferToken(address token, uint256 amount) external;\\n\\n function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\\n external;\\n}\\n\",\"keccak256\":\"0x79ca47defb3b5a56bba13f14c440838152fd1c1aa640476154516a16da4da8ba\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/IVault.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { VaultStorage } from \\\"../vault/VaultStorage.sol\\\";\\n\\ninterface IVault {\\n // slither-disable-start constable-states\\n\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event DefaultStrategyUpdated(address _strategy);\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\\n event DripDurationChanged(uint256 dripDuration);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\\n\\n // Governable.sol\\n function transferGovernance(address _newGovernor) external;\\n\\n function claimGovernance() external;\\n\\n function governor() external view returns (address);\\n\\n // VaultAdmin.sol\\n function setVaultBuffer(uint256 _vaultBuffer) external;\\n\\n function vaultBuffer() external view returns (uint256);\\n\\n function setAutoAllocateThreshold(uint256 _threshold) external;\\n\\n function autoAllocateThreshold() external view returns (uint256);\\n\\n function setRebaseThreshold(uint256 _threshold) external;\\n\\n function rebaseThreshold() external view returns (uint256);\\n\\n function setStrategistAddr(address _address) external;\\n\\n function strategistAddr() external view returns (address);\\n\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\\n\\n function maxSupplyDiff() external view returns (uint256);\\n\\n function setTrusteeAddress(address _address) external;\\n\\n function trusteeAddress() external view returns (address);\\n\\n function setTrusteeFeeBps(uint256 _basis) external;\\n\\n function trusteeFeeBps() external view returns (uint256);\\n\\n function approveStrategy(address _addr) external;\\n\\n function removeStrategy(address _addr) external;\\n\\n function setDefaultStrategy(address _strategy) external;\\n\\n function defaultStrategy() external view returns (address);\\n\\n function pauseRebase() external;\\n\\n function unpauseRebase() external;\\n\\n function rebasePaused() external view returns (bool);\\n\\n function pauseCapital() external;\\n\\n function unpauseCapital() external;\\n\\n function capitalPaused() external view returns (bool);\\n\\n function transferToken(address _asset, uint256 _amount) external;\\n\\n function withdrawAllFromStrategy(address _strategyAddr) external;\\n\\n function withdrawAllFromStrategies() external;\\n\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n // VaultCore.sol\\n function mint(uint256 _amount) external;\\n\\n function mintForStrategy(uint256 _amount) external;\\n\\n function burnForStrategy(uint256 _amount) external;\\n\\n function allocate() external;\\n\\n function rebase() external;\\n\\n function totalValue() external view returns (uint256 value);\\n\\n function checkBalance(address _asset) external view returns (uint256);\\n\\n function getAssetCount() external view returns (uint256);\\n\\n function getAllAssets() external view returns (address[] memory);\\n\\n function getStrategyCount() external view returns (uint256);\\n\\n function getAllStrategies() external view returns (address[] memory);\\n\\n function strategies(address _addr)\\n external\\n view\\n returns (VaultStorage.Strategy memory);\\n\\n /// @notice Deprecated: use `asset()` instead.\\n function isSupportedAsset(address _asset) external view returns (bool);\\n\\n function asset() external view returns (address);\\n\\n function oToken() external view returns (address);\\n\\n function initialize(address) external;\\n\\n function addWithdrawalQueueLiquidity() external;\\n\\n function requestWithdrawal(uint256 _amount)\\n external\\n returns (uint256 requestId, uint256 queued);\\n\\n function claimWithdrawal(uint256 requestId)\\n external\\n returns (uint256 amount);\\n\\n function claimWithdrawals(uint256[] memory requestIds)\\n external\\n returns (uint256[] memory amounts, uint256 totalAmount);\\n\\n function withdrawalQueueMetadata()\\n external\\n view\\n returns (VaultStorage.WithdrawalQueueMetadata memory);\\n\\n function withdrawalRequests(uint256 requestId)\\n external\\n view\\n returns (VaultStorage.WithdrawalRequest memory);\\n\\n function addStrategyToMintWhitelist(address strategyAddr) external;\\n\\n function removeStrategyFromMintWhitelist(address strategyAddr) external;\\n\\n function isMintWhitelistedStrategy(address strategyAddr)\\n external\\n view\\n returns (bool);\\n\\n function withdrawalClaimDelay() external view returns (uint256);\\n\\n function setWithdrawalClaimDelay(uint256 newDelay) external;\\n\\n function lastRebase() external view returns (uint64);\\n\\n function dripDuration() external view returns (uint64);\\n\\n function setDripDuration(uint256 _dripDuration) external;\\n\\n function rebasePerSecondMax() external view returns (uint64);\\n\\n function setRebaseRateMax(uint256 yearlyApr) external;\\n\\n function rebasePerSecondTarget() external view returns (uint64);\\n\\n function previewYield() external view returns (uint256 yield);\\n\\n // slither-disable-end constable-states\\n}\\n\",\"keccak256\":\"0x820394780e59498f66759341c8d0986ce95293efce81caaf3b57f0705097ba2a\",\"license\":\"BUSL-1.1\"},\"contracts/token/OUSD.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OUSD Token Contract\\n * @dev ERC20 compatible contract for OUSD\\n * @dev Implements an elastic supply\\n * @author Origin Protocol Inc\\n */\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\ncontract OUSD is Governable {\\n using SafeCast for int256;\\n using SafeCast for uint256;\\n\\n /// @dev Event triggered when the supply changes\\n /// @param totalSupply Updated token total supply\\n /// @param rebasingCredits Updated token rebasing credits\\n /// @param rebasingCreditsPerToken Updated token rebasing credits per token\\n event TotalSupplyUpdatedHighres(\\n uint256 totalSupply,\\n uint256 rebasingCredits,\\n uint256 rebasingCreditsPerToken\\n );\\n /// @dev Event triggered when an account opts in for rebasing\\n /// @param account Address of the account\\n event AccountRebasingEnabled(address account);\\n /// @dev Event triggered when an account opts out of rebasing\\n /// @param account Address of the account\\n event AccountRebasingDisabled(address account);\\n /// @dev Emitted when `value` tokens are moved from one account `from` to\\n /// another `to`.\\n /// @param from Address of the account tokens are moved from\\n /// @param to Address of the account tokens are moved to\\n /// @param value Amount of tokens transferred\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n /// @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n /// a call to {approve}. `value` is the new allowance.\\n /// @param owner Address of the owner approving allowance\\n /// @param spender Address of the spender allowance is granted to\\n /// @param value Amount of tokens spender can transfer\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 value\\n );\\n /// @dev Yield resulting from {changeSupply} that a `source` account would\\n /// receive is directed to `target` account.\\n /// @param source Address of the source forwarding the yield\\n /// @param target Address of the target receiving the yield\\n event YieldDelegated(address source, address target);\\n /// @dev Yield delegation from `source` account to the `target` account is\\n /// suspended.\\n /// @param source Address of the source suspending yield forwarding\\n /// @param target Address of the target no longer receiving yield from `source`\\n /// account\\n event YieldUndelegated(address source, address target);\\n\\n enum RebaseOptions {\\n NotSet,\\n StdNonRebasing,\\n StdRebasing,\\n YieldDelegationSource,\\n YieldDelegationTarget\\n }\\n\\n uint256[154] private _gap; // Slots to align with deployed contract\\n uint256 private constant MAX_SUPPLY = type(uint128).max;\\n /// @dev The amount of tokens in existence\\n uint256 public totalSupply;\\n mapping(address => mapping(address => uint256)) private allowances;\\n /// @dev The vault with privileges to execute {mint}, {burn}\\n /// and {changeSupply}\\n address public vaultAddress;\\n mapping(address => uint256) internal creditBalances;\\n // the 2 storage variables below need trailing underscores to not name collide with public functions\\n uint256 private rebasingCredits_; // Sum of all rebasing credits (creditBalances for rebasing accounts)\\n uint256 private rebasingCreditsPerToken_;\\n /// @dev The amount of tokens that are not rebasing - receiving yield\\n uint256 public nonRebasingSupply;\\n mapping(address => uint256) internal alternativeCreditsPerToken;\\n /// @dev A map of all addresses and their respective RebaseOptions\\n mapping(address => RebaseOptions) public rebaseState;\\n mapping(address => uint256) private __deprecated_isUpgraded;\\n /// @dev A map of addresses that have yields forwarded to. This is an\\n /// inverse mapping of {yieldFrom}\\n /// Key Account forwarding yield\\n /// Value Account receiving yield\\n mapping(address => address) public yieldTo;\\n /// @dev A map of addresses that are receiving the yield. This is an\\n /// inverse mapping of {yieldTo}\\n /// Key Account receiving yield\\n /// Value Account forwarding yield\\n mapping(address => address) public yieldFrom;\\n\\n uint256 private constant RESOLUTION_INCREASE = 1e9;\\n uint256[34] private __gap; // including below gap totals up to 200\\n\\n /// @dev Verifies that the caller is the Governor or Strategist.\\n modifier onlyGovernorOrStrategist() {\\n require(\\n isGovernor() || msg.sender == IVault(vaultAddress).strategistAddr(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n /// @dev Initializes the contract and sets necessary variables.\\n /// @param _vaultAddress Address of the vault contract\\n /// @param _initialCreditsPerToken The starting rebasing credits per token.\\n function initialize(address _vaultAddress, uint256 _initialCreditsPerToken)\\n external\\n onlyGovernor\\n {\\n require(_vaultAddress != address(0), \\\"Zero vault address\\\");\\n require(vaultAddress == address(0), \\\"Already initialized\\\");\\n\\n rebasingCreditsPerToken_ = _initialCreditsPerToken;\\n vaultAddress = _vaultAddress;\\n }\\n\\n /// @dev Returns the symbol of the token, a shorter version\\n /// of the name.\\n function symbol() external pure virtual returns (string memory) {\\n return \\\"OUSD\\\";\\n }\\n\\n /// @dev Returns the name of the token.\\n function name() external pure virtual returns (string memory) {\\n return \\\"Origin Dollar\\\";\\n }\\n\\n /// @dev Returns the number of decimals used to get its user representation.\\n function decimals() external pure virtual returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev Verifies that the caller is the Vault contract\\n */\\n modifier onlyVault() {\\n require(vaultAddress == msg.sender, \\\"Caller is not the Vault\\\");\\n _;\\n }\\n\\n /**\\n * @return High resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerTokenHighres() external view returns (uint256) {\\n return rebasingCreditsPerToken_;\\n }\\n\\n /**\\n * @return Low resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerToken() external view returns (uint256) {\\n return rebasingCreditsPerToken_ / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return High resolution total number of rebasing credits\\n */\\n function rebasingCreditsHighres() external view returns (uint256) {\\n return rebasingCredits_;\\n }\\n\\n /**\\n * @return Low resolution total number of rebasing credits\\n */\\n function rebasingCredits() external view returns (uint256) {\\n return rebasingCredits_ / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @notice Gets the balance of the specified address.\\n * @param _account Address to query the balance of.\\n * @return A uint256 representing the amount of base units owned by the\\n * specified address.\\n */\\n function balanceOf(address _account) public view returns (uint256) {\\n RebaseOptions state = rebaseState[_account];\\n if (state == RebaseOptions.YieldDelegationSource) {\\n // Saves a slot read when transferring to or from a yield delegating source\\n // since we know creditBalances equals the balance.\\n return creditBalances[_account];\\n }\\n uint256 baseBalance = (creditBalances[_account] * 1e18) /\\n _creditsPerToken(_account);\\n if (state == RebaseOptions.YieldDelegationTarget) {\\n // creditBalances of yieldFrom accounts equals token balances\\n return baseBalance - creditBalances[yieldFrom[_account]];\\n }\\n return baseBalance;\\n }\\n\\n /**\\n * @notice Gets the credits balance of the specified address.\\n * @dev Backwards compatible with old low res credits per token.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256) Credit balance and credits per token of the\\n * address\\n */\\n function creditsBalanceOf(address _account)\\n external\\n view\\n returns (uint256, uint256)\\n {\\n uint256 cpt = _creditsPerToken(_account);\\n if (cpt == 1e27) {\\n // For a period before the resolution upgrade, we created all new\\n // contract accounts at high resolution. Since they are not changing\\n // as a result of this upgrade, we will return their true values\\n return (creditBalances[_account], cpt);\\n } else {\\n return (\\n creditBalances[_account] / RESOLUTION_INCREASE,\\n cpt / RESOLUTION_INCREASE\\n );\\n }\\n }\\n\\n /**\\n * @notice Gets the credits balance of the specified address.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\\n * address, and isUpgraded\\n */\\n function creditsBalanceOfHighres(address _account)\\n external\\n view\\n returns (\\n uint256,\\n uint256,\\n bool\\n )\\n {\\n return (\\n creditBalances[_account],\\n _creditsPerToken(_account),\\n true // all accounts have their resolution \\\"upgraded\\\"\\n );\\n }\\n\\n // Backwards compatible view\\n function nonRebasingCreditsPerToken(address _account)\\n external\\n view\\n returns (uint256)\\n {\\n return alternativeCreditsPerToken[_account];\\n }\\n\\n /**\\n * @notice Transfer tokens to a specified address.\\n * @param _to the address to transfer to.\\n * @param _value the amount to be transferred.\\n * @return true on success.\\n */\\n function transfer(address _to, uint256 _value) external returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n\\n _executeTransfer(msg.sender, _to, _value);\\n\\n emit Transfer(msg.sender, _to, _value);\\n return true;\\n }\\n\\n /**\\n * @notice Transfer tokens from one address to another.\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value The amount of tokens to be transferred.\\n * @return true on success.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n uint256 userAllowance = allowances[_from][msg.sender];\\n require(_value <= userAllowance, \\\"Allowance exceeded\\\");\\n\\n unchecked {\\n allowances[_from][msg.sender] = userAllowance - _value;\\n }\\n\\n _executeTransfer(_from, _to, _value);\\n\\n emit Transfer(_from, _to, _value);\\n return true;\\n }\\n\\n function _executeTransfer(\\n address _from,\\n address _to,\\n uint256 _value\\n ) internal {\\n (\\n int256 fromRebasingCreditsDiff,\\n int256 fromNonRebasingSupplyDiff\\n ) = _adjustAccount(_from, -_value.toInt256());\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_to, _value.toInt256());\\n\\n _adjustGlobals(\\n fromRebasingCreditsDiff + toRebasingCreditsDiff,\\n fromNonRebasingSupplyDiff + toNonRebasingSupplyDiff\\n );\\n }\\n\\n function _adjustAccount(address _account, int256 _balanceChange)\\n internal\\n returns (int256 rebasingCreditsDiff, int256 nonRebasingSupplyDiff)\\n {\\n RebaseOptions state = rebaseState[_account];\\n int256 currentBalance = balanceOf(_account).toInt256();\\n if (currentBalance + _balanceChange < 0) {\\n revert(\\\"Transfer amount exceeds balance\\\");\\n }\\n uint256 newBalance = (currentBalance + _balanceChange).toUint256();\\n\\n if (state == RebaseOptions.YieldDelegationSource) {\\n address target = yieldTo[_account];\\n uint256 targetOldBalance = balanceOf(target);\\n uint256 targetNewCredits = _balanceToRebasingCredits(\\n targetOldBalance + newBalance\\n );\\n rebasingCreditsDiff =\\n targetNewCredits.toInt256() -\\n creditBalances[target].toInt256();\\n\\n creditBalances[_account] = newBalance;\\n creditBalances[target] = targetNewCredits;\\n } else if (state == RebaseOptions.YieldDelegationTarget) {\\n uint256 newCredits = _balanceToRebasingCredits(\\n newBalance + creditBalances[yieldFrom[_account]]\\n );\\n rebasingCreditsDiff =\\n newCredits.toInt256() -\\n creditBalances[_account].toInt256();\\n creditBalances[_account] = newCredits;\\n } else {\\n _autoMigrate(_account);\\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\\n _account\\n ];\\n if (alternativeCreditsPerTokenMem > 0) {\\n nonRebasingSupplyDiff = _balanceChange;\\n if (alternativeCreditsPerTokenMem != 1e18) {\\n alternativeCreditsPerToken[_account] = 1e18;\\n }\\n creditBalances[_account] = newBalance;\\n } else {\\n uint256 newCredits = _balanceToRebasingCredits(newBalance);\\n rebasingCreditsDiff =\\n newCredits.toInt256() -\\n creditBalances[_account].toInt256();\\n creditBalances[_account] = newCredits;\\n }\\n }\\n }\\n\\n function _adjustGlobals(\\n int256 _rebasingCreditsDiff,\\n int256 _nonRebasingSupplyDiff\\n ) internal {\\n if (_rebasingCreditsDiff != 0) {\\n rebasingCredits_ = (rebasingCredits_.toInt256() +\\n _rebasingCreditsDiff).toUint256();\\n }\\n if (_nonRebasingSupplyDiff != 0) {\\n nonRebasingSupply = (nonRebasingSupply.toInt256() +\\n _nonRebasingSupplyDiff).toUint256();\\n }\\n }\\n\\n /**\\n * @notice Function to check the amount of tokens that _owner has allowed\\n * to `_spender`.\\n * @param _owner The address which owns the funds.\\n * @param _spender The address which will spend the funds.\\n * @return The number of tokens still available for the _spender.\\n */\\n function allowance(address _owner, address _spender)\\n external\\n view\\n returns (uint256)\\n {\\n return allowances[_owner][_spender];\\n }\\n\\n /**\\n * @notice Approve the passed address to spend the specified amount of\\n * tokens on behalf of msg.sender.\\n * @param _spender The address which will spend the funds.\\n * @param _value The amount of tokens to be spent.\\n * @return true on success.\\n */\\n function approve(address _spender, uint256 _value) external returns (bool) {\\n allowances[msg.sender][_spender] = _value;\\n emit Approval(msg.sender, _spender, _value);\\n return true;\\n }\\n\\n /**\\n * @notice Creates `_amount` tokens and assigns them to `_account`,\\n * increasing the total supply.\\n */\\n function mint(address _account, uint256 _amount) external onlyVault {\\n require(_account != address(0), \\\"Mint to the zero address\\\");\\n\\n // Account\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_account, _amount.toInt256());\\n // Globals\\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\\n totalSupply = totalSupply + _amount;\\n\\n require(totalSupply < MAX_SUPPLY, \\\"Max supply\\\");\\n emit Transfer(address(0), _account, _amount);\\n }\\n\\n /**\\n * @notice Destroys `_amount` tokens from `_account`,\\n * reducing the total supply.\\n */\\n function burn(address _account, uint256 _amount) external onlyVault {\\n require(_account != address(0), \\\"Burn from the zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n\\n // Account\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_account, -_amount.toInt256());\\n // Globals\\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\\n totalSupply = totalSupply - _amount;\\n\\n emit Transfer(_account, address(0), _amount);\\n }\\n\\n /**\\n * @dev Get the credits per token for an account. Returns a fixed amount\\n * if the account is non-rebasing.\\n * @param _account Address of the account.\\n */\\n function _creditsPerToken(address _account)\\n internal\\n view\\n returns (uint256)\\n {\\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\\n _account\\n ];\\n if (alternativeCreditsPerTokenMem != 0) {\\n return alternativeCreditsPerTokenMem;\\n } else {\\n return rebasingCreditsPerToken_;\\n }\\n }\\n\\n /**\\n * @dev Auto migrate contracts to be non rebasing,\\n * unless they have opted into yield.\\n * @param _account Address of the account.\\n */\\n function _autoMigrate(address _account) internal {\\n uint256 codeLen = _account.code.length;\\n bool isEOA = (codeLen == 0) ||\\n (codeLen == 23 && bytes3(_account.code) == 0xef0100);\\n // In previous code versions, contracts would not have had their\\n // rebaseState[_account] set to RebaseOptions.NonRebasing when migrated\\n // therefore we check the actual accounting used on the account as well.\\n if (\\n (!isEOA) &&\\n rebaseState[_account] == RebaseOptions.NotSet &&\\n alternativeCreditsPerToken[_account] == 0\\n ) {\\n _rebaseOptOut(_account);\\n }\\n }\\n\\n /**\\n * @dev Calculates credits from contract's global rebasingCreditsPerToken_, and\\n * also balance that corresponds to those credits. The latter is important\\n * when adjusting the contract's global nonRebasingSupply to circumvent any\\n * possible rounding errors.\\n *\\n * @param _balance Balance of the account.\\n */\\n function _balanceToRebasingCredits(uint256 _balance)\\n internal\\n view\\n returns (uint256 rebasingCredits)\\n {\\n // Rounds up, because we need to ensure that accounts always have\\n // at least the balance that they should have.\\n // Note this should always be used on an absolute account value,\\n // not on a possibly negative diff, because then the rounding would be wrong.\\n return ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18;\\n }\\n\\n /**\\n * @notice The calling account will start receiving yield after a successful call.\\n * @param _account Address of the account.\\n */\\n function governanceRebaseOptIn(address _account) external onlyGovernor {\\n require(_account != address(0), \\\"Zero address not allowed\\\");\\n _rebaseOptIn(_account);\\n }\\n\\n /**\\n * @notice The calling account will start receiving yield after a successful call.\\n */\\n function rebaseOptIn() external {\\n _rebaseOptIn(msg.sender);\\n }\\n\\n function _rebaseOptIn(address _account) internal {\\n uint256 balance = balanceOf(_account);\\n\\n // prettier-ignore\\n require(\\n alternativeCreditsPerToken[_account] > 0 ||\\n // Accounts may explicitly `rebaseOptIn` regardless of\\n // accounting if they have a 0 balance.\\n creditBalances[_account] == 0\\n ,\\n \\\"Account must be non-rebasing\\\"\\n );\\n RebaseOptions state = rebaseState[_account];\\n // prettier-ignore\\n require(\\n state == RebaseOptions.StdNonRebasing ||\\n state == RebaseOptions.NotSet,\\n \\\"Only standard non-rebasing accounts can opt in\\\"\\n );\\n\\n uint256 newCredits = _balanceToRebasingCredits(balance);\\n\\n // Account\\n rebaseState[_account] = RebaseOptions.StdRebasing;\\n alternativeCreditsPerToken[_account] = 0;\\n creditBalances[_account] = newCredits;\\n // Globals\\n _adjustGlobals(newCredits.toInt256(), -balance.toInt256());\\n\\n emit AccountRebasingEnabled(_account);\\n }\\n\\n /**\\n * @notice The calling account will no longer receive yield\\n */\\n function rebaseOptOut() external {\\n _rebaseOptOut(msg.sender);\\n }\\n\\n function _rebaseOptOut(address _account) internal {\\n require(\\n alternativeCreditsPerToken[_account] == 0,\\n \\\"Account must be rebasing\\\"\\n );\\n RebaseOptions state = rebaseState[_account];\\n require(\\n state == RebaseOptions.StdRebasing || state == RebaseOptions.NotSet,\\n \\\"Only standard rebasing accounts can opt out\\\"\\n );\\n\\n uint256 oldCredits = creditBalances[_account];\\n uint256 balance = balanceOf(_account);\\n\\n // Account\\n rebaseState[_account] = RebaseOptions.StdNonRebasing;\\n alternativeCreditsPerToken[_account] = 1e18;\\n creditBalances[_account] = balance;\\n // Globals\\n _adjustGlobals(-oldCredits.toInt256(), balance.toInt256());\\n\\n emit AccountRebasingDisabled(_account);\\n }\\n\\n /**\\n * @notice Distribute yield to users. This changes the exchange rate\\n * between \\\"credits\\\" and OUSD tokens to change rebasing user's balances.\\n * @param _newTotalSupply New total supply of OUSD.\\n */\\n function changeSupply(uint256 _newTotalSupply) external onlyVault {\\n require(totalSupply > 0, \\\"Cannot increase 0 supply\\\");\\n\\n if (totalSupply == _newTotalSupply) {\\n emit TotalSupplyUpdatedHighres(\\n totalSupply,\\n rebasingCredits_,\\n rebasingCreditsPerToken_\\n );\\n return;\\n }\\n\\n totalSupply = _newTotalSupply > MAX_SUPPLY\\n ? MAX_SUPPLY\\n : _newTotalSupply;\\n\\n uint256 rebasingSupply = totalSupply - nonRebasingSupply;\\n // round up in the favour of the protocol\\n rebasingCreditsPerToken_ =\\n (rebasingCredits_ * 1e18 + rebasingSupply - 1) /\\n rebasingSupply;\\n\\n require(rebasingCreditsPerToken_ > 0, \\\"Invalid change in supply\\\");\\n\\n emit TotalSupplyUpdatedHighres(\\n totalSupply,\\n rebasingCredits_,\\n rebasingCreditsPerToken_\\n );\\n }\\n\\n /*\\n * @notice Send the yield from one account to another account.\\n * Each account keeps its own balances.\\n */\\n function delegateYield(address _from, address _to)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_from != address(0), \\\"Zero from address not allowed\\\");\\n require(_to != address(0), \\\"Zero to address not allowed\\\");\\n\\n require(_from != _to, \\\"Cannot delegate to self\\\");\\n require(\\n yieldFrom[_to] == address(0) &&\\n yieldTo[_to] == address(0) &&\\n yieldFrom[_from] == address(0) &&\\n yieldTo[_from] == address(0),\\n \\\"Blocked by existing yield delegation\\\"\\n );\\n RebaseOptions stateFrom = rebaseState[_from];\\n RebaseOptions stateTo = rebaseState[_to];\\n\\n require(\\n stateFrom == RebaseOptions.NotSet ||\\n stateFrom == RebaseOptions.StdNonRebasing ||\\n stateFrom == RebaseOptions.StdRebasing,\\n \\\"Invalid rebaseState from\\\"\\n );\\n\\n require(\\n stateTo == RebaseOptions.NotSet ||\\n stateTo == RebaseOptions.StdNonRebasing ||\\n stateTo == RebaseOptions.StdRebasing,\\n \\\"Invalid rebaseState to\\\"\\n );\\n\\n if (alternativeCreditsPerToken[_from] == 0) {\\n _rebaseOptOut(_from);\\n }\\n if (alternativeCreditsPerToken[_to] > 0) {\\n _rebaseOptIn(_to);\\n }\\n\\n uint256 fromBalance = balanceOf(_from);\\n uint256 toBalance = balanceOf(_to);\\n uint256 oldToCredits = creditBalances[_to];\\n uint256 newToCredits = _balanceToRebasingCredits(\\n fromBalance + toBalance\\n );\\n\\n // Set up the bidirectional links\\n yieldTo[_from] = _to;\\n yieldFrom[_to] = _from;\\n\\n // Local\\n rebaseState[_from] = RebaseOptions.YieldDelegationSource;\\n alternativeCreditsPerToken[_from] = 1e18;\\n creditBalances[_from] = fromBalance;\\n rebaseState[_to] = RebaseOptions.YieldDelegationTarget;\\n creditBalances[_to] = newToCredits;\\n\\n // Global\\n int256 creditsChange = newToCredits.toInt256() -\\n oldToCredits.toInt256();\\n _adjustGlobals(creditsChange, -(fromBalance).toInt256());\\n emit YieldDelegated(_from, _to);\\n }\\n\\n /*\\n * @notice Stop sending the yield from one account to another account.\\n */\\n function undelegateYield(address _from) external onlyGovernorOrStrategist {\\n // Require a delegation, which will also ensure a valid delegation\\n require(yieldTo[_from] != address(0), \\\"Zero address not allowed\\\");\\n\\n address to = yieldTo[_from];\\n uint256 fromBalance = balanceOf(_from);\\n uint256 toBalance = balanceOf(to);\\n uint256 oldToCredits = creditBalances[to];\\n uint256 newToCredits = _balanceToRebasingCredits(toBalance);\\n\\n // Remove the bidirectional links\\n yieldFrom[to] = address(0);\\n yieldTo[_from] = address(0);\\n\\n // Local\\n rebaseState[_from] = RebaseOptions.StdNonRebasing;\\n // alternativeCreditsPerToken[from] already 1e18 from `delegateYield()`\\n creditBalances[_from] = fromBalance;\\n rebaseState[to] = RebaseOptions.StdRebasing;\\n // alternativeCreditsPerToken[to] already 0 from `delegateYield()`\\n creditBalances[to] = newToCredits;\\n\\n // Global\\n int256 creditsChange = newToCredits.toInt256() -\\n oldToCredits.toInt256();\\n _adjustGlobals(creditsChange, fromBalance.toInt256());\\n emit YieldUndelegated(_from, to);\\n }\\n}\\n\",\"keccak256\":\"0x73439bef6569f5adf6f5ce2cb54a5f0d3109d4819457532236e172a7091980a9\",\"license\":\"BUSL-1.1\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { IBasicToken } from \\\"../interfaces/IBasicToken.sol\\\";\\n\\nlibrary Helpers {\\n /**\\n * @notice Fetch the `symbol()` from an ERC20 token\\n * @dev Grabs the `symbol()` from a contract\\n * @param _token Address of the ERC20 token\\n * @return string Symbol of the ERC20 token\\n */\\n function getSymbol(address _token) internal view returns (string memory) {\\n string memory symbol = IBasicToken(_token).symbol();\\n return symbol;\\n }\\n\\n /**\\n * @notice Fetch the `decimals()` from an ERC20 token\\n * @dev Grabs the `decimals()` from a contract and fails if\\n * the decimal value does not live within a certain range\\n * @param _token Address of the ERC20 token\\n * @return uint256 Decimals of the ERC20 token\\n */\\n function getDecimals(address _token) internal view returns (uint256) {\\n uint256 decimals = IBasicToken(_token).decimals();\\n require(\\n decimals >= 4 && decimals <= 18,\\n \\\"Token must have sufficient decimal places\\\"\\n );\\n\\n return decimals;\\n }\\n}\\n\",\"keccak256\":\"0x4366f8d90b34c1eef8bbaaf369b1e5cd59f04027bb3c111f208eaee65bbc0346\",\"license\":\"BUSL-1.1\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base contract any contracts that need to initialize state after deployment.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0x50d39ebf38a3d3111f2b77a6c75ece1d4ae731552fec4697ab16fcf6c0d4d5e8\",\"license\":\"BUSL-1.1\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n // slither-disable-next-line divide-before-multiply\\n x = x.div(10**(from - to));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e36 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0x71d6ed0053a1e5ef018d27c3b6d024f336d8157ab6f6859e400b3243a50a71b7\",\"license\":\"BUSL-1.1\"},\"contracts/vault/OETHVault.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { VaultAdmin } from \\\"./VaultAdmin.sol\\\";\\n\\n/**\\n * @title OETH VaultAdmin Contract\\n * @author Origin Protocol Inc\\n */\\ncontract OETHVault is VaultAdmin {\\n constructor(address _weth) VaultAdmin(_weth) {}\\n}\\n\",\"keccak256\":\"0x4941cf6a70075b74b021ec51482e11fdcae242db6e83e0d43cd5049011e45fbb\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultAdmin contract\\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\nimport \\\"./VaultCore.sol\\\";\\n\\nabstract contract VaultAdmin is VaultCore {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n using SafeCast for uint256;\\n\\n /**\\n * @dev Verifies that the caller is the Governor or Strategist.\\n */\\n modifier onlyGovernorOrStrategist() {\\n require(\\n msg.sender == strategistAddr || isGovernor(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n constructor(address _asset) VaultCore(_asset) {}\\n\\n /***************************************\\n Configuration\\n ****************************************/\\n /**\\n * @notice Set a buffer of asset to keep in the Vault to handle most\\n * redemptions without needing to spend gas unwinding asset from a Strategy.\\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\\n */\\n function setVaultBuffer(uint256 _vaultBuffer)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_vaultBuffer <= 1e18, \\\"Invalid value\\\");\\n vaultBuffer = _vaultBuffer;\\n emit VaultBufferUpdated(_vaultBuffer);\\n }\\n\\n /**\\n * @notice Sets the minimum amount of OTokens in a mint to trigger an\\n * automatic allocation of funds afterwords.\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setAutoAllocateThreshold(uint256 _threshold)\\n external\\n onlyGovernor\\n {\\n autoAllocateThreshold = _threshold;\\n emit AllocateThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set a minimum amount of OTokens in a mint or redeem that triggers a\\n * rebase\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setRebaseThreshold(uint256 _threshold) external onlyGovernor {\\n rebaseThreshold = _threshold;\\n emit RebaseThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set address of Strategist\\n * @param _address Address of Strategist\\n */\\n function setStrategistAddr(address _address) external onlyGovernor {\\n strategistAddr = _address;\\n emit StrategistUpdated(_address);\\n }\\n\\n /**\\n * @notice Set the default Strategy for asset, i.e. the one which\\n * the asset will be automatically allocated to and withdrawn from\\n * @param _strategy Address of the Strategy\\n */\\n function setDefaultStrategy(address _strategy)\\n external\\n onlyGovernorOrStrategist\\n {\\n emit DefaultStrategyUpdated(_strategy);\\n // If its a zero address being passed for the strategy we are removing\\n // the default strategy\\n if (_strategy != address(0)) {\\n // Make sure the strategy meets some criteria\\n require(strategies[_strategy].isSupported, \\\"Strategy not approved\\\");\\n require(\\n IStrategy(_strategy).supportsAsset(asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n }\\n defaultStrategy = _strategy;\\n }\\n\\n /**\\n * @notice Changes the async withdrawal claim period for OETH & superOETHb\\n * @param _delay Delay period (should be between 10 mins to 7 days).\\n * Set to 0 to disable async withdrawals\\n */\\n function setWithdrawalClaimDelay(uint256 _delay) external onlyGovernor {\\n require(\\n _delay == 0 || (_delay >= 10 minutes && _delay <= 15 days),\\n \\\"Invalid claim delay period\\\"\\n );\\n withdrawalClaimDelay = _delay;\\n emit WithdrawalClaimDelayUpdated(_delay);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Set a yield streaming max rate. This spreads yield over\\n * time if it is above the max rate. This is a per rebase APR which\\n * due to compounding differs from the yearly APR. Governance should\\n * consider this fact when picking a desired APR\\n * @param apr in 1e18 notation. 3 * 1e18 = 3% APR\\n */\\n function setRebaseRateMax(uint256 apr) external onlyGovernorOrStrategist {\\n // The old yield will be at the old rate\\n _rebase();\\n // Change the rate\\n uint256 newPerSecond = apr / 100 / 365 days;\\n require(newPerSecond <= MAX_REBASE_PER_SECOND, \\\"Rate too high\\\");\\n rebasePerSecondMax = newPerSecond.toUint64();\\n emit RebasePerSecondMaxChanged(newPerSecond);\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Set the drip duration period\\n * @param _dripDuration Time in seconds to target a constant yield rate\\n */\\n function setDripDuration(uint256 _dripDuration)\\n external\\n onlyGovernorOrStrategist\\n {\\n // The old yield will be at the old rate\\n _rebase();\\n dripDuration = _dripDuration.toUint64();\\n emit DripDurationChanged(_dripDuration);\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /***************************************\\n Strategy Config\\n ****************************************/\\n\\n /**\\n * @notice Add a strategy to the Vault.\\n * @param _addr Address of the strategy to add\\n */\\n function approveStrategy(address _addr) external onlyGovernor {\\n require(!strategies[_addr].isSupported, \\\"Strategy already approved\\\");\\n require(\\n IStrategy(_addr).supportsAsset(asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\\n allStrategies.push(_addr);\\n emit StrategyApproved(_addr);\\n }\\n\\n /**\\n * @notice Remove a strategy from the Vault.\\n * @param _addr Address of the strategy to remove\\n */\\n\\n function removeStrategy(address _addr) external onlyGovernor {\\n require(strategies[_addr].isSupported, \\\"Strategy not approved\\\");\\n require(defaultStrategy != _addr, \\\"Strategy is default for asset\\\");\\n\\n // Initialize strategyIndex with out of bounds result so function will\\n // revert if no valid index found\\n uint256 stratCount = allStrategies.length;\\n uint256 strategyIndex = stratCount;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n if (allStrategies[i] == _addr) {\\n strategyIndex = i;\\n break;\\n }\\n }\\n\\n if (strategyIndex < stratCount) {\\n allStrategies[strategyIndex] = allStrategies[stratCount - 1];\\n allStrategies.pop();\\n\\n // Mark the strategy as not supported\\n strategies[_addr].isSupported = false;\\n isMintWhitelistedStrategy[_addr] = false;\\n\\n // Withdraw all asset\\n IStrategy strategy = IStrategy(_addr);\\n strategy.withdrawAll();\\n\\n // 1e13 for 18 decimals. And 1e1(10) for 6 decimals\\n uint256 maxDustBalance = uint256(1e13).scaleBy(assetDecimals, 18);\\n\\n /*\\n * Some strategies are not able to withdraw all of their funds in a synchronous call.\\n * Prevent the possible accidental removal of such strategies before their funds are withdrawn.\\n */\\n require(\\n strategy.checkBalance(asset) < maxDustBalance,\\n \\\"Strategy has funds\\\"\\n );\\n emit StrategyRemoved(_addr);\\n }\\n }\\n\\n /**\\n * @notice Adds a strategy to the mint whitelist.\\n * Reverts if strategy isn't approved on Vault.\\n * @param strategyAddr Strategy address\\n */\\n function addStrategyToMintWhitelist(address strategyAddr)\\n external\\n onlyGovernor\\n {\\n require(strategies[strategyAddr].isSupported, \\\"Strategy not approved\\\");\\n\\n require(\\n !isMintWhitelistedStrategy[strategyAddr],\\n \\\"Already whitelisted\\\"\\n );\\n\\n isMintWhitelistedStrategy[strategyAddr] = true;\\n\\n emit StrategyAddedToMintWhitelist(strategyAddr);\\n }\\n\\n /**\\n * @notice Removes a strategy from the mint whitelist.\\n * @param strategyAddr Strategy address\\n */\\n function removeStrategyFromMintWhitelist(address strategyAddr)\\n external\\n onlyGovernor\\n {\\n // Intentionally skipping `strategies.isSupported` check since\\n // we may wanna remove an address even after removing the strategy\\n\\n require(isMintWhitelistedStrategy[strategyAddr], \\\"Not whitelisted\\\");\\n\\n isMintWhitelistedStrategy[strategyAddr] = false;\\n\\n emit StrategyRemovedFromMintWhitelist(strategyAddr);\\n }\\n\\n /***************************************\\n Strategies\\n ****************************************/\\n\\n /**\\n * @notice Deposit multiple asset from the vault into the strategy.\\n * @param _strategyToAddress Address of the Strategy to deposit asset into.\\n * @param _assets Array of asset address that will be deposited into the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to deposit.\\n */\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _depositToStrategy(_strategyToAddress, _assets, _amounts);\\n }\\n\\n function _depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyToAddress].isSupported,\\n \\\"Invalid to Strategy\\\"\\n );\\n require(\\n _assets.length == 1 && _amounts.length == 1 && _assets[0] == asset,\\n \\\"Only asset is supported\\\"\\n );\\n\\n // Check the there is enough asset to transfer once the backing\\n // asset reserved for the withdrawal queue is accounted for\\n require(\\n _amounts[0] <= _assetAvailable(),\\n \\\"Not enough assets available\\\"\\n );\\n\\n // Send required amount of funds to the strategy\\n IERC20(asset).safeTransfer(_strategyToAddress, _amounts[0]);\\n\\n // Deposit all the funds that have been sent to the strategy\\n IStrategy(_strategyToAddress).depositAll();\\n }\\n\\n /**\\n * @notice Withdraw multiple asset from the strategy to the vault.\\n * @param _strategyFromAddress Address of the Strategy to withdraw asset from.\\n * @param _assets Array of asset address that will be withdrawn from the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to withdraw.\\n */\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _withdrawFromStrategy(\\n address(this),\\n _strategyFromAddress,\\n _assets,\\n _amounts\\n );\\n }\\n\\n /**\\n * @param _recipient can either be a strategy or the Vault\\n */\\n function _withdrawFromStrategy(\\n address _recipient,\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyFromAddress].isSupported,\\n \\\"Invalid from Strategy\\\"\\n );\\n require(_assets.length == _amounts.length, \\\"Parameter length mismatch\\\");\\n\\n uint256 assetCount = _assets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n // Withdraw from Strategy to the recipient\\n IStrategy(_strategyFromAddress).withdraw(\\n _recipient,\\n _assets[i],\\n _amounts[i]\\n );\\n }\\n\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @notice Sets the maximum allowable difference between\\n * total supply and asset' value.\\n */\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\\n maxSupplyDiff = _maxSupplyDiff;\\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\\n }\\n\\n /**\\n * @notice Sets the trusteeAddress that can receive a portion of yield.\\n * Setting to the zero address disables this feature.\\n */\\n function setTrusteeAddress(address _address) external onlyGovernor {\\n trusteeAddress = _address;\\n emit TrusteeAddressChanged(_address);\\n }\\n\\n /**\\n * @notice Sets the TrusteeFeeBps to the percentage of yield that should be\\n * received in basis points.\\n */\\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\\n require(_basis <= 5000, \\\"basis cannot exceed 50%\\\");\\n trusteeFeeBps = _basis;\\n emit TrusteeFeeBpsChanged(_basis);\\n }\\n\\n /***************************************\\n Pause\\n ****************************************/\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent rebasing.\\n */\\n function pauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = true;\\n emit RebasePaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to allow rebasing.\\n */\\n function unpauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = false;\\n emit RebaseUnpaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent capital movement.\\n */\\n function pauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = true;\\n emit CapitalPaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to false to enable capital movement.\\n */\\n function unpauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = false;\\n emit CapitalUnpaused();\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\\n * contract, i.e. mistaken sends.\\n * @param _asset Address for the asset\\n * @param _amount Amount of the asset to transfer\\n */\\n function transferToken(address _asset, uint256 _amount)\\n external\\n onlyGovernor\\n {\\n require(asset != _asset, \\\"Only unsupported asset\\\");\\n IERC20(_asset).safeTransfer(governor(), _amount);\\n }\\n\\n /***************************************\\n Strategies Admin\\n ****************************************/\\n\\n /**\\n * @notice Withdraws all asset from the strategy and sends asset to the Vault.\\n * @param _strategyAddr Strategy address.\\n */\\n function withdrawAllFromStrategy(address _strategyAddr)\\n external\\n onlyGovernorOrStrategist\\n {\\n _withdrawAllFromStrategy(_strategyAddr);\\n }\\n\\n function _withdrawAllFromStrategy(address _strategyAddr) internal virtual {\\n require(\\n strategies[_strategyAddr].isSupported,\\n \\\"Strategy is not supported\\\"\\n );\\n IStrategy strategy = IStrategy(_strategyAddr);\\n strategy.withdrawAll();\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @notice Withdraws all asset from all the strategies and sends asset to the Vault.\\n */\\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\\n _withdrawAllFromStrategies();\\n }\\n\\n function _withdrawAllFromStrategies() internal virtual {\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy(allStrategies[i]).withdrawAll();\\n }\\n _addWithdrawalQueueLiquidity();\\n }\\n}\\n\",\"keccak256\":\"0x3ba59fd88e9e3dae7197f04bc76213143f36b2e0922958c6f69d406a4a25f9c2\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultCore.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultCore contract\\n * @notice The Vault contract stores asset. On a deposit, OTokens will be minted\\n and sent to the depositor. On a withdrawal, OTokens will be burned and\\n asset will be sent to the withdrawer. The Vault accepts deposits of\\n interest from yield bearing strategies which will modify the supply\\n of OTokens.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\n\\nimport \\\"./VaultInitializer.sol\\\";\\n\\nabstract contract VaultCore is VaultInitializer {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n\\n /**\\n * @dev Verifies that the rebasing is not paused.\\n */\\n modifier whenNotRebasePaused() {\\n require(!rebasePaused, \\\"Rebasing paused\\\");\\n _;\\n }\\n\\n /**\\n * @dev Verifies that the deposits are not paused.\\n */\\n modifier whenNotCapitalPaused() {\\n require(!capitalPaused, \\\"Capital paused\\\");\\n _;\\n }\\n\\n constructor(address _asset) VaultInitializer(_asset) {}\\n\\n ////////////////////////////////////////////////////\\n /// MINT / BURN ///\\n ////////////////////////////////////////////////////\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @dev Deprecated: use `mint(uint256 _amount)` instead.\\n * @dev Deprecated: param _asset Address of the asset being deposited\\n * @param _amount Amount of the asset being deposited\\n * @dev Deprecated: param _minimumOusdAmount Minimum OTokens to mint\\n */\\n function mint(\\n address,\\n uint256 _amount,\\n uint256\\n ) external whenNotCapitalPaused nonReentrant {\\n _mint(_amount);\\n }\\n\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @param _amount Amount of the asset being deposited\\n */\\n function mint(uint256 _amount) external whenNotCapitalPaused nonReentrant {\\n _mint(_amount);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @dev Deposit a supported asset and mint OTokens.\\n * @param _amount Amount of the asset being deposited\\n */\\n function _mint(uint256 _amount) internal virtual {\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n\\n // Scale amount to 18 decimals\\n uint256 scaledAmount = _amount.scaleBy(18, assetDecimals);\\n\\n emit Mint(msg.sender, scaledAmount);\\n\\n // Rebase must happen before any transfers occur.\\n if (!rebasePaused && scaledAmount >= rebaseThreshold) {\\n _rebase();\\n }\\n\\n // Mint oTokens\\n oToken.mint(msg.sender, scaledAmount);\\n\\n IERC20(asset).safeTransferFrom(msg.sender, address(this), _amount);\\n\\n // Give priority to the withdrawal queue for the new asset liquidity\\n _addWithdrawalQueueLiquidity();\\n\\n // Auto-allocate if necessary\\n if (scaledAmount >= autoAllocateThreshold) {\\n _allocate();\\n }\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /**\\n * @notice Mint OTokens for an allowed Strategy\\n * @param _amount Amount of OToken to mint\\n *\\n * Notice: can't use `nonReentrant` modifier since the `mint` function can\\n * call `allocate`, and that can trigger an AMO strategy to call this function\\n * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function mintForStrategy(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n {\\n require(\\n strategies[msg.sender].isSupported == true,\\n \\\"Unsupported strategy\\\"\\n );\\n require(\\n isMintWhitelistedStrategy[msg.sender] == true,\\n \\\"Not whitelisted strategy\\\"\\n );\\n\\n emit Mint(msg.sender, _amount);\\n // Mint matching amount of OTokens\\n oToken.mint(msg.sender, _amount);\\n }\\n\\n /**\\n * @notice Burn OTokens for an allowed Strategy\\n * @param _amount Amount of OToken to burn\\n *\\n * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could\\n * require withdrawal on an AMO strategy and that one can call `burnForStrategy`\\n * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function burnForStrategy(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n {\\n require(\\n strategies[msg.sender].isSupported == true,\\n \\\"Unsupported strategy\\\"\\n );\\n require(\\n isMintWhitelistedStrategy[msg.sender] == true,\\n \\\"Not whitelisted strategy\\\"\\n );\\n\\n emit Redeem(msg.sender, _amount);\\n\\n // Burn OTokens\\n oToken.burn(msg.sender, _amount);\\n }\\n\\n ////////////////////////////////////////////////////\\n /// ASYNC WITHDRAWALS ///\\n ////////////////////////////////////////////////////\\n /**\\n * @notice Request an asynchronous withdrawal of asset in exchange for OToken.\\n * The OToken is burned on request and the asset is transferred to the withdrawer on claim.\\n * This request can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal this request's `queued` amount.\\n * There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs\\n * enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue.\\n * OToken is converted to asset at 1:1.\\n * @param _amount Amount of OToken to burn.\\n * @return requestId Unique ID for the withdrawal request\\n * @return queued Cumulative total of all asset queued including already claimed requests.\\n */\\n function requestWithdrawal(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 requestId, uint256 queued)\\n {\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n require(withdrawalClaimDelay > 0, \\\"Async withdrawals not enabled\\\");\\n\\n // The check that the requester has enough OToken is done in to later burn call\\n\\n requestId = withdrawalQueueMetadata.nextWithdrawalIndex;\\n queued =\\n withdrawalQueueMetadata.queued +\\n _amount.scaleBy(assetDecimals, 18);\\n\\n // Store the next withdrawal request\\n withdrawalQueueMetadata.nextWithdrawalIndex = SafeCast.toUint128(\\n requestId + 1\\n );\\n // Store the updated queued amount which reserves asset in the withdrawal queue\\n // and reduces the vault's total asset\\n withdrawalQueueMetadata.queued = SafeCast.toUint128(queued);\\n // Store the user's withdrawal request\\n // `queued` is in asset decimals, while `amount` is in OToken decimals (18)\\n withdrawalRequests[requestId] = WithdrawalRequest({\\n withdrawer: msg.sender,\\n claimed: false,\\n timestamp: uint40(block.timestamp),\\n amount: SafeCast.toUint128(_amount),\\n queued: SafeCast.toUint128(queued)\\n });\\n\\n // Burn the user's OToken\\n oToken.burn(msg.sender, _amount);\\n\\n // Prevent withdrawal if the vault is solvent by more than the allowed percentage\\n _postRedeem(_amount);\\n\\n emit WithdrawalRequested(msg.sender, requestId, _amount, queued);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Claim a previously requested withdrawal once it is claimable.\\n * This request can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal this request's `queued` amount and 10 minutes has passed.\\n * If the requests is not claimable, the transaction will revert with `Queue pending liquidity`.\\n * If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`.\\n * OToken is converted to asset at 1:1.\\n * @param _requestId Unique ID for the withdrawal request\\n * @return amount Amount of asset transferred to the withdrawer\\n */\\n function claimWithdrawal(uint256 _requestId)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 amount)\\n {\\n // Try and get more liquidity if there is not enough available\\n if (\\n withdrawalRequests[_requestId].queued >\\n withdrawalQueueMetadata.claimable\\n ) {\\n // Add any asset to the withdrawal queue\\n // this needs to remain here as:\\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\\n // - funds can be withdrawn from a strategy\\n //\\n // Those funds need to be added to withdrawal queue liquidity\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n // Scale amount to asset decimals\\n amount = _claimWithdrawal(_requestId);\\n\\n // transfer asset from the vault to the withdrawer\\n IERC20(asset).safeTransfer(msg.sender, amount);\\n\\n // Prevent insolvency\\n _postRedeem(amount.scaleBy(18, assetDecimals));\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n /**\\n * @notice Claim a previously requested withdrawals once they are claimable.\\n * This requests can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal each request's `queued` amount and 10 minutes has passed.\\n * If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`.\\n * If one of the requests is not older than 10 minutes,\\n * the whole transaction will revert with `Claim delay not met`.\\n * @param _requestIds Unique ID of each withdrawal request\\n * @return amounts Amount of asset received for each request\\n * @return totalAmount Total amount of asset transferred to the withdrawer\\n */\\n function claimWithdrawals(uint256[] calldata _requestIds)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256[] memory amounts, uint256 totalAmount)\\n {\\n // Add any asset to the withdrawal queue\\n // this needs to remain here as:\\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\\n // - funds can be withdrawn from a strategy\\n //\\n // Those funds need to be added to withdrawal queue liquidity\\n _addWithdrawalQueueLiquidity();\\n\\n amounts = new uint256[](_requestIds.length);\\n for (uint256 i; i < _requestIds.length; ++i) {\\n // Scale all amounts to asset decimals, thus totalAmount is also in asset decimals\\n amounts[i] = _claimWithdrawal(_requestIds[i]);\\n totalAmount += amounts[i];\\n }\\n\\n // transfer all the claimed asset from the vault to the withdrawer\\n IERC20(asset).safeTransfer(msg.sender, totalAmount);\\n\\n // Prevent insolvency\\n _postRedeem(totalAmount.scaleBy(18, assetDecimals));\\n\\n return (amounts, totalAmount);\\n }\\n\\n function _claimWithdrawal(uint256 requestId)\\n internal\\n returns (uint256 amount)\\n {\\n require(withdrawalClaimDelay > 0, \\\"Async withdrawals not enabled\\\");\\n\\n // Load the structs from storage into memory\\n WithdrawalRequest memory request = withdrawalRequests[requestId];\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n require(\\n request.timestamp + withdrawalClaimDelay <= block.timestamp,\\n \\\"Claim delay not met\\\"\\n );\\n // If there isn't enough reserved liquidity in the queue to claim\\n require(request.queued <= queue.claimable, \\\"Queue pending liquidity\\\");\\n require(request.withdrawer == msg.sender, \\\"Not requester\\\");\\n require(request.claimed == false, \\\"Already claimed\\\");\\n\\n // Store the request as claimed\\n withdrawalRequests[requestId].claimed = true;\\n // Store the updated claimed amount\\n withdrawalQueueMetadata.claimed =\\n queue.claimed +\\n SafeCast.toUint128(\\n StableMath.scaleBy(request.amount, assetDecimals, 18)\\n );\\n\\n emit WithdrawalClaimed(msg.sender, requestId, request.amount);\\n\\n return StableMath.scaleBy(request.amount, assetDecimals, 18);\\n }\\n\\n function _postRedeem(uint256 _amount) internal {\\n // Until we can prove that we won't affect the prices of our asset\\n // by withdrawing them, this should be here.\\n // It's possible that a strategy was off on its asset total, perhaps\\n // a reward token sold for more or for less than anticipated.\\n uint256 totalUnits = 0;\\n if (_amount >= rebaseThreshold && !rebasePaused) {\\n totalUnits = _rebase();\\n } else {\\n totalUnits = _totalValue();\\n }\\n\\n // Check that the OTokens are backed by enough asset\\n if (maxSupplyDiff > 0) {\\n // If there are more outstanding withdrawal requests than asset in the vault and strategies\\n // then the available asset will be negative and totalUnits will be rounded up to zero.\\n // As we don't know the exact shortfall amount, we will reject all redeem and withdrawals\\n require(totalUnits > 0, \\\"Too many outstanding requests\\\");\\n\\n // Allow a max difference of maxSupplyDiff% between\\n // asset value and OUSD total supply\\n uint256 diff = oToken.totalSupply().divPrecisely(totalUnits);\\n require(\\n (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,\\n \\\"Backing supply liquidity error\\\"\\n );\\n }\\n }\\n\\n /**\\n * @notice Allocate unallocated funds on Vault to strategies.\\n */\\n function allocate() external virtual whenNotCapitalPaused nonReentrant {\\n // Add any unallocated asset to the withdrawal queue first\\n _addWithdrawalQueueLiquidity();\\n\\n _allocate();\\n }\\n\\n /**\\n * @dev Allocate asset (eg. WETH or USDC) to the default asset strategy\\n * if there is excess to the Vault buffer.\\n * This is called from either `mint` or `allocate` and assumes `_addWithdrawalQueueLiquidity`\\n * has been called before this function.\\n */\\n function _allocate() internal virtual {\\n // No need to do anything if no default strategy for asset\\n address depositStrategyAddr = defaultStrategy;\\n if (depositStrategyAddr == address(0)) return;\\n\\n uint256 assetAvailableInVault = _assetAvailable();\\n // No need to do anything if there isn't any asset in the vault to allocate\\n if (assetAvailableInVault == 0) return;\\n\\n // Calculate the target buffer for the vault using the total supply\\n uint256 totalSupply = oToken.totalSupply();\\n // Scaled to asset decimals\\n uint256 targetBuffer = totalSupply.mulTruncate(vaultBuffer).scaleBy(\\n assetDecimals,\\n 18\\n );\\n\\n // If available asset in the Vault is below or equal the target buffer then there's nothing to allocate\\n if (assetAvailableInVault <= targetBuffer) return;\\n\\n // The amount of asset to allocate to the default strategy\\n uint256 allocateAmount = assetAvailableInVault - targetBuffer;\\n\\n IStrategy strategy = IStrategy(depositStrategyAddr);\\n // Transfer asset to the strategy and call the strategy's deposit function\\n IERC20(asset).safeTransfer(address(strategy), allocateAmount);\\n strategy.deposit(asset, allocateAmount);\\n\\n emit AssetAllocated(asset, depositStrategyAddr, allocateAmount);\\n }\\n\\n /**\\n * @notice Calculate the total value of asset held by the Vault and all\\n * strategies and update the supply of OTokens.\\n */\\n function rebase() external virtual nonReentrant {\\n _rebase();\\n }\\n\\n /**\\n * @dev Calculate the total value of asset held by the Vault and all\\n * strategies and update the supply of OTokens, optionally sending a\\n * portion of the yield to the trustee.\\n * @return totalUnits Total balance of Vault in units\\n */\\n function _rebase() internal whenNotRebasePaused returns (uint256) {\\n uint256 supply = oToken.totalSupply();\\n uint256 vaultValue = _totalValue();\\n // If no supply yet, do not rebase\\n if (supply == 0) {\\n return vaultValue;\\n }\\n\\n // Calculate yield and new supply\\n (uint256 yield, uint256 targetRate) = _nextYield(supply, vaultValue);\\n uint256 newSupply = supply + yield;\\n // Only rebase upwards and if we have enough backing funds\\n if (newSupply <= supply || newSupply > vaultValue) {\\n return vaultValue;\\n }\\n\\n rebasePerSecondTarget = uint64(_min(targetRate, type(uint64).max));\\n lastRebase = uint64(block.timestamp); // Intentional cast\\n\\n // Fee collection on yield\\n address _trusteeAddress = trusteeAddress; // gas savings\\n uint256 fee = 0;\\n if (_trusteeAddress != address(0)) {\\n fee = (yield * trusteeFeeBps) / 1e4;\\n if (fee > 0) {\\n require(fee < yield, \\\"Fee must not be greater than yield\\\");\\n oToken.mint(_trusteeAddress, fee);\\n }\\n }\\n emit YieldDistribution(_trusteeAddress, yield, fee);\\n\\n // Only ratchet OToken supply upwards\\n // Final check uses latest totalSupply\\n if (newSupply > oToken.totalSupply()) {\\n oToken.changeSupply(newSupply);\\n }\\n return vaultValue;\\n }\\n\\n /**\\n * @notice Calculates the amount that would rebase at next rebase.\\n * This is before any fees.\\n * @return yield amount of expected yield\\n */\\n function previewYield() external view returns (uint256 yield) {\\n (yield, ) = _nextYield(oToken.totalSupply(), _totalValue());\\n return yield;\\n }\\n\\n /**\\n * @dev Calculates the amount that would rebase at next rebase.\\n * See this Readme for detailed explanation:\\n * contracts/contracts/vault/README - Yield Limits.md\\n */\\n function _nextYield(uint256 supply, uint256 vaultValue)\\n internal\\n view\\n virtual\\n returns (uint256 yield, uint256 targetRate)\\n {\\n uint256 nonRebasing = oToken.nonRebasingSupply();\\n uint256 rebasing = supply - nonRebasing;\\n uint256 elapsed = block.timestamp - lastRebase;\\n targetRate = rebasePerSecondTarget;\\n\\n if (\\n elapsed == 0 || // Yield only once per block.\\n rebasing == 0 || // No yield if there are no rebasing tokens to give it to.\\n supply > vaultValue || // No yield if we do not have yield to give.\\n block.timestamp >= type(uint64).max // No yield if we are too far in the future to calculate it correctly.\\n ) {\\n return (0, targetRate);\\n }\\n\\n // Start with the full difference available\\n yield = vaultValue - supply;\\n\\n // Cap via optional automatic duration smoothing\\n uint256 _dripDuration = dripDuration;\\n if (_dripDuration > 1) {\\n // If we are able to sustain an increased drip rate for\\n // double the duration, then increase the target drip rate\\n targetRate = _max(targetRate, yield / (_dripDuration * 2));\\n // If we cannot sustain the target rate any more,\\n // then rebase what we can, and reduce the target\\n targetRate = _min(targetRate, yield / _dripDuration);\\n // drip at the new target rate\\n yield = _min(yield, targetRate * elapsed);\\n }\\n\\n // Cap per second. elapsed is not 1e18 denominated\\n yield = _min(yield, (rebasing * elapsed * rebasePerSecondMax) / 1e18);\\n\\n // Cap at a hard max per rebase, to avoid long durations resulting in huge rebases\\n yield = _min(yield, (rebasing * MAX_REBASE) / 1e18);\\n\\n return (yield, targetRate);\\n }\\n\\n /**\\n * @notice Determine the total value of asset held by the vault and its\\n * strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function totalValue() external view virtual returns (uint256 value) {\\n value = _totalValue();\\n }\\n\\n /**\\n * @dev Internal Calculate the total value of the asset held by the\\n * vault and its strategies.\\n * @dev The total value of all WETH held by the vault and all its strategies\\n * less any WETH that is reserved for the withdrawal queue.\\n * If there is not enough WETH in the vault and all strategies to cover\\n * all outstanding withdrawal requests then return a total value of 0.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValue() internal view virtual returns (uint256 value) {\\n // As asset is the only asset, just return the asset balance\\n value = _checkBalance(asset).scaleBy(18, assetDecimals);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @param _asset Address of asset\\n * @return uint256 Balance of asset in decimals of asset\\n */\\n function checkBalance(address _asset) external view returns (uint256) {\\n return _checkBalance(_asset);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @dev Get the balance of an asset held in Vault and all strategies\\n * less any asset that is reserved for the withdrawal queue.\\n * BaseAsset is the only asset that can return a non-zero balance.\\n * All other asset will return 0 even if there is some dust amounts left in the Vault.\\n * For example, there is 1 wei left of stETH (or USDC) in the OETH (or OUSD) Vault but\\n * will return 0 in this function.\\n *\\n * If there is not enough asset in the vault and all strategies to cover all outstanding\\n * withdrawal requests then return a asset balance of 0\\n * @param _asset Address of asset\\n * @return balance Balance of asset in decimals of asset\\n */\\n function _checkBalance(address _asset)\\n internal\\n view\\n virtual\\n returns (uint256 balance)\\n {\\n if (_asset != asset) return 0;\\n\\n // Get the asset in the vault and the strategies\\n IERC20 asset = IERC20(_asset);\\n balance = asset.balanceOf(address(this));\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy strategy = IStrategy(allStrategies[i]);\\n if (strategy.supportsAsset(_asset)) {\\n balance = balance + strategy.checkBalance(_asset);\\n }\\n }\\n\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // If the vault becomes insolvent enough that the total value in the vault and all strategies\\n // is less than the outstanding withdrawals.\\n // For example, there was a mass slashing event and most users request a withdrawal.\\n if (balance + queue.claimed < queue.queued) {\\n return 0;\\n }\\n\\n // Need to remove asset that is reserved for the withdrawal queue\\n return balance + queue.claimed - queue.queued;\\n }\\n\\n /**\\n * @notice Adds WETH to the withdrawal queue if there is a funding shortfall.\\n * @dev is called from the Native Staking strategy when validator withdrawals are processed.\\n * It also called before any WETH is allocated to a strategy.\\n */\\n function addWithdrawalQueueLiquidity() external {\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @dev Adds asset (eg. WETH or USDC) to the withdrawal queue if there is a funding shortfall.\\n * This assumes 1 asset equal 1 corresponding OToken.\\n */\\n function _addWithdrawalQueueLiquidity()\\n internal\\n returns (uint256 addedClaimable)\\n {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // Check if the claimable asset is less than the queued amount\\n uint256 queueShortfall = queue.queued - queue.claimable;\\n\\n // No need to do anything is the withdrawal queue is full funded\\n if (queueShortfall == 0) {\\n return 0;\\n }\\n\\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\\n\\n // Of the claimable withdrawal requests, how much is unclaimed?\\n // That is, the amount of asset that is currently allocated for the withdrawal queue\\n uint256 allocatedBaseAsset = queue.claimable - queue.claimed;\\n\\n // If there is no unallocated asset then there is nothing to add to the queue\\n if (assetBalance <= allocatedBaseAsset) {\\n return 0;\\n }\\n\\n uint256 unallocatedBaseAsset = assetBalance - allocatedBaseAsset;\\n // the new claimable amount is the smaller of the queue shortfall or unallocated asset\\n addedClaimable = queueShortfall < unallocatedBaseAsset\\n ? queueShortfall\\n : unallocatedBaseAsset;\\n uint256 newClaimable = queue.claimable + addedClaimable;\\n\\n // Store the new claimable amount back to storage\\n withdrawalQueueMetadata.claimable = SafeCast.toUint128(newClaimable);\\n\\n // emit a WithdrawalClaimable event\\n emit WithdrawalClaimable(newClaimable, addedClaimable);\\n }\\n\\n /**\\n * @dev Calculate how much asset (eg. WETH or USDC) in the vault is not reserved for the withdrawal queue.\\n * That is, it is available to be redeemed or deposited into a strategy.\\n */\\n function _assetAvailable() internal view returns (uint256 assetAvailable) {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // The amount of asset that is still to be claimed in the withdrawal queue\\n uint256 outstandingWithdrawals = queue.queued - queue.claimed;\\n\\n // The amount of sitting in asset in the vault\\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\\n // If there is not enough asset in the vault to cover the outstanding withdrawals\\n if (assetBalance <= outstandingWithdrawals) return 0;\\n\\n return assetBalance - outstandingWithdrawals;\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Return the number of asset supported by the Vault.\\n */\\n function getAssetCount() public view returns (uint256) {\\n return 1;\\n }\\n\\n /**\\n * @notice Return all vault asset addresses in order\\n */\\n function getAllAssets() external view returns (address[] memory) {\\n address[] memory a = new address[](1);\\n a[0] = asset;\\n return a;\\n }\\n\\n /**\\n * @notice Return the number of strategies active on the Vault.\\n */\\n function getStrategyCount() external view returns (uint256) {\\n return allStrategies.length;\\n }\\n\\n /**\\n * @notice Return the array of all strategies\\n */\\n function getAllStrategies() external view returns (address[] memory) {\\n return allStrategies;\\n }\\n\\n /**\\n * @notice Returns whether the vault supports the asset\\n * @param _asset address of the asset\\n * @return true if supported\\n */\\n function isSupportedAsset(address _asset) external view returns (bool) {\\n return asset == _asset;\\n }\\n\\n function _min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n function _max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a > b ? a : b;\\n }\\n}\\n\",\"keccak256\":\"0xf5c7295587db70ea009853009724ded12486dfabf420d589ee1eec37e9a681eb\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultInitializer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultInitializer contract\\n * @notice The Vault contract initializes the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport \\\"./VaultStorage.sol\\\";\\n\\nabstract contract VaultInitializer is VaultStorage {\\n constructor(address _asset) VaultStorage(_asset) {}\\n\\n function initialize(address _oToken) external onlyGovernor initializer {\\n require(_oToken != address(0), \\\"oToken address is zero\\\");\\n\\n oToken = OUSD(_oToken);\\n\\n rebasePaused = false;\\n capitalPaused = true;\\n\\n // Initial Vault buffer of 0%\\n vaultBuffer = 0;\\n // Initial allocate threshold of 25,000 OUSD\\n autoAllocateThreshold = 25000e18;\\n // Threshold for rebasing\\n rebaseThreshold = 1000e18;\\n // Initialize all strategies\\n allStrategies = new address[](0);\\n // Start with drip duration: 7 days\\n dripDuration = 604800;\\n }\\n}\\n\",\"keccak256\":\"0xb0b99b4b9279ab87b6008fb9675b581cc009a51cc5f9c0fb838eda86b1bca02b\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultStorage.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultStorage contract\\n * @notice The VaultStorage contract defines the storage for the Vault contracts\\n * @author Origin Protocol Inc\\n */\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { IERC20Metadata } from \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { OUSD } from \\\"../token/OUSD.sol\\\";\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport \\\"../utils/Helpers.sol\\\";\\n\\nabstract contract VaultStorage is Initializable, Governable {\\n using SafeERC20 for IERC20;\\n\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event DefaultStrategyUpdated(address _strategy);\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\\n event DripDurationChanged(uint256 dripDuration);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\\n\\n // Since we are proxy, all state should be uninitalized.\\n // Since this storage contract does not have logic directly on it\\n // we should not be checking for to see if these variables can be constant.\\n // slither-disable-start uninitialized-state\\n // slither-disable-start constable-states\\n\\n /// @dev mapping of supported vault assets to their configuration\\n uint256 private _deprecated_assets;\\n /// @dev list of all assets supported by the vault.\\n address[] private _deprecated_allAssets;\\n\\n // Strategies approved for use by the Vault\\n struct Strategy {\\n bool isSupported;\\n uint256 _deprecated; // Deprecated storage slot\\n }\\n /// @dev mapping of strategy contracts to their configuration\\n mapping(address => Strategy) public strategies;\\n /// @dev list of all vault strategies\\n address[] internal allStrategies;\\n\\n /// @notice Address of the Oracle price provider contract\\n address private _deprecated_priceProvider;\\n /// @notice pause rebasing if true\\n bool public rebasePaused;\\n /// @notice pause operations that change the OToken supply.\\n /// eg mint, redeem, allocate, mint/burn for strategy\\n bool public capitalPaused;\\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\\n uint256 private _deprecated_redeemFeeBps;\\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\\n uint256 public vaultBuffer;\\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\\n uint256 public autoAllocateThreshold;\\n /// @notice OToken mints over this amount automatically rebase. 18 decimals.\\n uint256 public rebaseThreshold;\\n\\n /// @dev Address of the OToken token. eg OUSD or OETH.\\n OUSD public oToken;\\n\\n /// @dev Address of the contract responsible for post rebase syncs with AMMs\\n address private _deprecated_rebaseHooksAddr = address(0);\\n\\n /// @dev Deprecated: Address of Uniswap\\n address private _deprecated_uniswapAddr = address(0);\\n\\n /// @notice Address of the Strategist\\n address public strategistAddr = address(0);\\n\\n /// @notice Mapping of asset address to the Strategy that they should automatically\\n // be allocated to\\n uint256 private _deprecated_assetDefaultStrategies;\\n\\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\\n uint256 public maxSupplyDiff;\\n\\n /// @notice Trustee contract that can collect a percentage of yield\\n address public trusteeAddress;\\n\\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\\n uint256 public trusteeFeeBps;\\n\\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\\n address[] private _deprecated_swapTokens;\\n\\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\\n\\n address private _deprecated_ousdMetaStrategy;\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n int256 private _deprecated_netOusdMintedForStrategy;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n uint256 private _deprecated_netOusdMintForStrategyThreshold;\\n\\n uint256 private _deprecated_swapConfig;\\n\\n // List of strategies that can mint oTokens directly\\n // Used in OETHBaseVaultCore\\n mapping(address => bool) public isMintWhitelistedStrategy;\\n\\n /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\\n /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\\n address private _deprecated_dripper;\\n\\n /// Withdrawal Queue Storage /////\\n\\n struct WithdrawalQueueMetadata {\\n // cumulative total of all withdrawal requests included the ones that have already been claimed\\n uint128 queued;\\n // cumulative total of all the requests that can be claimed including the ones that have already been claimed\\n uint128 claimable;\\n // total of all the requests that have been claimed\\n uint128 claimed;\\n // index of the next withdrawal request starting at 0\\n uint128 nextWithdrawalIndex;\\n }\\n\\n /// @notice Global metadata for the withdrawal queue including:\\n /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed\\n /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed\\n /// claimed - total of all the requests that have been claimed\\n /// nextWithdrawalIndex - index of the next withdrawal request starting at 0\\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\\n\\n struct WithdrawalRequest {\\n address withdrawer;\\n bool claimed;\\n uint40 timestamp; // timestamp of the withdrawal request\\n // Amount of oTokens to redeem. eg OETH\\n uint128 amount;\\n // cumulative total of all withdrawal requests including this one.\\n // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\\n uint128 queued;\\n }\\n\\n /// @notice Mapping of withdrawal request indices to the user withdrawal request data\\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\\n\\n /// @notice Sets a minimum delay that is required to elapse between\\n /// requesting async withdrawals and claiming the request.\\n /// When set to 0 async withdrawals are disabled.\\n uint256 public withdrawalClaimDelay;\\n\\n /// @notice Time in seconds that the vault last rebased yield.\\n uint64 public lastRebase;\\n\\n /// @notice Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\\n uint64 public dripDuration;\\n\\n /// @notice max rebase percentage per second\\n /// Can be used to set maximum yield of the protocol,\\n /// spreading out yield over time\\n uint64 public rebasePerSecondMax;\\n\\n /// @notice target rebase rate limit, based on past rates and funds available.\\n uint64 public rebasePerSecondTarget;\\n\\n uint256 internal constant MAX_REBASE = 0.02 ether;\\n uint256 internal constant MAX_REBASE_PER_SECOND =\\n uint256(0.05 ether) / 1 days;\\n\\n /// @notice Default strategy for asset\\n address public defaultStrategy;\\n\\n // For future use\\n uint256[42] private __gap;\\n\\n /// @notice Index of WETH asset in allAssets array\\n /// Legacy OETHVaultCore code, relocated here for vault consistency.\\n uint256 private _deprecated_wethAssetIndex;\\n\\n /// @dev Address of the asset (eg. WETH or USDC)\\n address public immutable asset;\\n uint8 internal immutable assetDecimals;\\n\\n // slither-disable-end constable-states\\n // slither-disable-end uninitialized-state\\n\\n constructor(address _asset) {\\n uint8 _decimals = IERC20Metadata(_asset).decimals();\\n require(_decimals <= 18, \\\"invalid asset decimals\\\");\\n asset = _asset;\\n assetDecimals = _decimals;\\n }\\n\\n /// @notice Deprecated: use `oToken()` instead.\\n function oUSD() external view returns (OUSD) {\\n return oToken;\\n }\\n}\\n\",\"keccak256\":\"0xcca0e0ebbbbda50b23fba7aea96a1e34f6a9d58c8f2e86e84b0911d4a9e5d418\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x60c0604052603d80546001600160a01b0319908116909155603e805482169055603f8054909116905534801561003457600080fd5b5060405161544638038061544683398101604081905261005391610133565b808080806000816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100bb9190610163565b905060128160ff1611156101155760405162461bcd60e51b815260206004820152601660248201527f696e76616c696420617373657420646563696d616c7300000000000000000000604482015260640160405180910390fd5b6001600160a01b0390911660805260ff1660a0525061018692505050565b60006020828403121561014557600080fd5b81516001600160a01b038116811461015c57600080fd5b9392505050565b60006020828403121561017557600080fd5b815160ff8116811461015c57600080fd5b60805160a0516151e561026160003960008181610fa60152818161178b0152818161205401528181612c6f015281816131560152818161376201528181613806015281816140ae01526144630152600081816105870152818161089401528181610c4e01528181610fe4015281816112d301528181611438015281816117570152818161189401528181612c3b015281816132520152818161338001528181613b0501528181613dda01528181613f110152818161411901528181614164015281816141cc0152818161448a01526148c501526151e56000f3fe608060405234801561001057600080fd5b50600436106104075760003560e01c80636217f3ea11610220578063ae69f3cb11610130578063c5f00841116100b8578063d4c3eea011610087578063d4c3eea0146109e6578063e6cc5432146109ee578063ea33b8e414610a02578063f844443614610a0a578063fac5bb9b14610a1d57600080fd5b8063c5f00841146109bb578063c7af3352146109c3578063c9919112146109cb578063d38bfff4146109d357600080fd5b8063b890ebf6116100ff578063b890ebf61461096b578063b9b17f9f1461097e578063bb7a632e14610986578063c3b28864146109a0578063c4d66de8146109a857600080fd5b8063ae69f3cb1461092a578063af14052c1461093d578063b2c9336d14610945578063b4925a201461095857600080fd5b806394828ffd116101b35780639fa1826e116101825780639fa1826e146108ec578063a0712d68146108f5578063a0aead4d14610908578063ab80dafb1461090f578063abaa99161461092257600080fd5b806394828ffd1461086957806395b166bc146108715780639be918e6146108845780639ee679e8146108c457600080fd5b8063840c4c7a116101ef578063840c4c7a146107925780638e510b52146107a55780638ec489a2146107ae578063937b2581146107c157600080fd5b80636217f3ea14610746578063663e64ce14610759578063773540b31461076c57806378f353a11461077f57600080fd5b806339ebf8231161031b578063527e83a8116102ae57806357bee9441161027d57806357bee944146106f45780635802a17214610707578063597c8910146107185780635d36b1901461072b5780635f5152261461073357600080fd5b8063527e83a8146106aa57806352d38e5d146106c457806353ca9f24146106cd578063570d8e1d146106e157600080fd5b806345e4213b116102ea57806345e4213b1461063b57806348e30f541461064457806349c1d54d146106655780634d5f46291461067857600080fd5b806339ebf823146105a95780633b8ae397146105ed5780633dbc911f146106005780634530820a1461060857600080fd5b80631a32aad61161039e5780632acada4d1161036d5780632acada4d146104f35780632da845a81461050857806331e19cfa1461051b578063362bd1a31461052357806338d52e0f1461058257600080fd5b80631a32aad6146104ad5780631cfbe7bc146104c05780631edfe3da146104d3578063207134b0146104ea57600080fd5b80631072cbea116103da5780631072cbea14610461578063156e29f614610474578063175188e8146104875780631816dd4a1461049a57600080fd5b80630493a0fa1461040c57806309f49bf5146104215780630acbda75146104295780630c340a241461043c575b600080fd5b61041f61041a366004614b73565b610a30565b005b61041f610ae6565b61041f610437366004614b73565b610b56565b610444610c01565b6040516001600160a01b0390911681526020015b60405180910390f35b61041f61046f366004614ba8565b610c1e565b61041f610482366004614bd2565b610cdc565b61041f610495366004614c05565b610d4f565b61041f6104a8366004614c05565b6110e2565b603c54610444906001600160a01b031681565b61041f6104ce366004614b73565b6111e9565b6104dc60395481565b604051908152602001610458565b6104dc60435481565b6104fb6112ab565b6040516104589190614c20565b61041f610516366004614c05565b611322565b6036546104dc565b604b54604c5461054f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610458565b6104447f000000000000000000000000000000000000000000000000000000000000000081565b6105d66105b7366004614c05565b6035602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610458565b61041f6105fb366004614c05565b611394565b61041f6115a7565b61062b610616366004614c05565b60496020526000908152604090205460ff1681565b6040519015158152602001610458565b6104dc604e5481565b610657610652366004614cb0565b61161d565b604051610458929190614cf1565b604254610444906001600160a01b031681565b604f5461069290600160c01b90046001600160401b031681565b6040516001600160401b039091168152602001610458565b604f5461069290600160801b90046001600160401b031681565b6104dc603b5481565b60375461062b90600160a01b900460ff1681565b603f54610444906001600160a01b031681565b61041f610702366004614c05565b6117c2565b603c546001600160a01b0316610444565b61041f610726366004614c05565b611975565b61041f6119b9565b6104dc610741366004614c05565b611a5f565b61041f610754366004614b73565b611a70565b61041f610767366004614b73565b611bf4565b61041f61077a366004614c05565b611c4d565b604f54610692906001600160401b031681565b61041f6107a0366004614d3e565b611cbf565b6104dc60415481565b61041f6107bc366004614b73565b611d46565b6108226107cf366004614b73565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a001610458565b61041f611dfb565b61041f61087f366004614c05565b611e6b565b61062b610892366004614c05565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b6108d76108d2366004614b73565b611f32565b60408051928352602083019190915201610458565b6104dc603a5481565b61041f610903366004614b73565b612273565b60016104dc565b61041f61091d366004614b73565b6122e4565b61041f612433565b61041f610938366004614d3e565b6124ab565b61041f612527565b61041f610953366004614b73565b61256d565b61041f610966366004614b73565b6125c6565b61041f610979366004614b73565b6126e4565b61041f61273d565b604f5461069290600160401b90046001600160401b031681565b6104fb612745565b61041f6109b6366004614c05565b6127a7565b61041f61295f565b61062b6129d5565b61041f612a06565b61041f6109e1366004614c05565b612a46565b6104dc612aea565b60375461062b90600160a81b900460ff1681565b6104dc612af4565b6104dc610a18366004614b73565b612b83565b605054610444906001600160a01b031681565b603f546001600160a01b0316331480610a4c5750610a4c6129d5565b610a715760405162461bcd60e51b8152600401610a6890614dc2565b60405180910390fd5b610a79612c9e565b50610a8381613038565b604f80546001600160401b0392909216600160401b0267ffffffffffffffff60401b199092169190911790556040518181527f406e15fbca1d8ded2dbb06765fea3a54f18395c54125a4c9916dd00ea14ee15e906020015b60405180910390a150565b603f546001600160a01b0316331480610b025750610b026129d5565b610b1e5760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b610b5e6129d5565b610b7a5760405162461bcd60e51b8152600401610a6890614e0a565b611388811115610bcc5760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f7420657863656564203530250000000000000000006044820152606401610a68565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c790602001610adb565b6000610c196000805160206151908339815191525490565b905090565b610c266129d5565b610c425760405162461bcd60e51b8152600401610a6890614e0a565b816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610cbc5760405162461bcd60e51b815260206004820152601660248201527513db9b1e481d5b9cdd5c1c1bdc9d195908185cdcd95d60521b6044820152606401610a68565b610cd8610cc7610c01565b6001600160a01b03841690836130a4565b5050565b603754600160a81b900460ff1615610d065760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101610d385760405162461bcd60e51b8152600401610a6890614e69565b60028255610d45846130fa565b5060019055505050565b610d576129d5565b610d735760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff16610dab5760405162461bcd60e51b8152600401610a6890614e91565b6050546001600160a01b03808316911603610e085760405162461bcd60e51b815260206004820152601d60248201527f53747261746567792069732064656661756c7420666f722061737365740000006044820152606401610a68565b6036548060005b82811015610e5e57836001600160a01b031660368281548110610e3457610e34614ec0565b6000918252602090912001546001600160a01b031603610e5657809150610e5e565b600101610e0f565b50818110156110dd576036610e74600184614eec565b81548110610e8457610e84614ec0565b600091825260209091200154603680546001600160a01b039092169183908110610eb057610eb0614ec0565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610eef57610eef614eff565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038516808352603582526040808420805460ff1990811690915560499093528084208054909316909255815163429c145b60e11b815291518693919263853828b692600480830193919282900301818387803b158015610f7b57600080fd5b505af1158015610f8f573d6000803e3d6000fd5b5060009250610fcd91506509184e72a000905060ff7f0000000000000000000000000000000000000000000000000000000000000000166012613296565b604051632fa8a91360e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192508291841690635f51522690602401602060405180830381865afa158015611038573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105c9190614f15565b1061109e5760405162461bcd60e51b81526020600482015260126024820152715374726174656779206861732066756e647360701b6044820152606401610a68565b6040516001600160a01b03861681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49060200160405180910390a150505b505050565b6110ea6129d5565b6111065760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff1661113e5760405162461bcd60e51b8152600401610a6890614e91565b6001600160a01b03811660009081526049602052604090205460ff161561119d5760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481dda1a5d195b1a5cdd1959606a1b6044820152606401610a68565b6001600160a01b038116600081815260496020526040808220805460ff19166001179055517f47c8c96a5942f094264111c5fe7f6a4fe86efe63254a6fa7afa5fc84f07d58e89190a250565b6111f16129d5565b61120d5760405162461bcd60e51b8152600401610a6890614e0a565b80158061122a5750610258811015801561122a57506213c6808111155b6112765760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636c61696d2064656c617920706572696f640000000000006044820152606401610a68565b604e8190556040518181527fc59f5e32049abab44ddea11021f5abb89422a2f550837afcf25df9fc8d0db6b090602001610adb565b60408051600180825281830190925260609160009190602080830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061130557611305614ec0565b6001600160a01b0390921660209283029190910190910152919050565b61132a6129d5565b6113465760405162461bcd60e51b8152600401610a6890614e0a565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610adb565b61139c6129d5565b6113b85760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff16156114215760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f766564000000000000006044820152606401610a68565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa158015611487573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ab9190614f44565b6114f75760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a68565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610adb565b603f546001600160a01b03163314806115c357506115c36129d5565b6115df5760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b603754606090600090600160a81b900460ff161561164d5760405162461bcd60e51b8152600401610a6890614e41565b6000805160206151708339815191528054600119810161167f5760405162461bcd60e51b8152600401610a6890614e69565b6002825561168b6132fa565b50846001600160401b038111156116a4576116a4614f2e565b6040519080825280602002602001820160405280156116cd578160200160208202803683370190505b50935060005b85811015611749576116fc8787838181106116f0576116f0614ec0565b905060200201356134d6565b85828151811061170e5761170e614ec0565b60200260200101818152505084818151811061172c5761172c614ec0565b60200260200101518461173f9190614f66565b93506001016116d3565b5061177e6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130a4565b6117b56117b084601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b613837565b6001825550509250929050565b603f546001600160a01b03163314806117de57506117de6129d5565b6117fa5760405162461bcd60e51b8152600401610a6890614dc2565b6040516001600160a01b03821681527f45a9e715f8779ebeab88d3e8d081fb8b484b7730857e7c4478a95a5b1d8f79489060200160405180910390a16001600160a01b03811615611953576001600160a01b03811660009081526035602052604090205460ff1661187d5760405162461bcd60e51b8152600401610a6890614e91565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa1580156118e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119079190614f44565b6119535760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a68565b605080546001600160a01b0319166001600160a01b0392909216919091179055565b603f546001600160a01b031633148061199157506119916129d5565b6119ad5760405162461bcd60e51b8152600401610a6890614dc2565b6119b6816139da565b50565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614611a545760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610a68565b611a5d33613aa2565b565b6000611a6a82613b01565b92915050565b603754600160a81b900460ff1615611a9a5760405162461bcd60e51b8152600401610a6890614e41565b3360009081526035602052604090205460ff161515600114611af55760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a68565b3360009081526049602052604090205460ff161515600114611b545760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a68565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051611b85929190614f79565b60405180910390a1603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90611bbf9033908590600401614f79565b600060405180830381600087803b158015611bd957600080fd5b505af1158015611bed573d6000803e3d6000fd5b5050505050565b611bfc6129d5565b611c185760405162461bcd60e51b8152600401610a6890614e0a565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610adb565b611c556129d5565b611c715760405162461bcd60e51b8152600401610a6890614e0a565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610adb565b603f546001600160a01b0316331480611cdb5750611cdb6129d5565b611cf75760405162461bcd60e51b8152600401610a6890614dc2565b60008051602061517083398151915280546001198101611d295760405162461bcd60e51b8152600401610a6890614e69565b60028255611d3a8787878787613d63565b50600190555050505050565b603f546001600160a01b0316331480611d625750611d626129d5565b611d7e5760405162461bcd60e51b8152600401610a6890614dc2565b670de0b6b3a7640000811115611dc65760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b6044820152606401610a68565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610adb565b603f546001600160a01b0316331480611e175750611e176129d5565b611e335760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e736129d5565b611e8f5760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526049602052604090205460ff16611ee95760405162461bcd60e51b815260206004820152600f60248201526e139bdd081dda1a5d195b1a5cdd1959608a1b6044820152606401610a68565b6001600160a01b038116600081815260496020526040808220805460ff19169055517f0ec40967a61509853550658e51d0e4297f7cba244fe4adc8ba18b5631ac20e2f9190a250565b6037546000908190600160a81b900460ff1615611f615760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101611f935760405162461bcd60e51b8152600401610a6890614e69565b6002825560008511611fe75760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a68565b6000604e54116120395760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a68565b604c54600160801b90046001600160801b0316935061207d857f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b604b5461209391906001600160801b0316614f66565b92506120a86120a3856001614f66565b613fa2565b604c80546001600160801b03928316600160801b0292169190911790556120ce83613fa2565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff16918101919091526060810161211e87613fa2565b6001600160801b0316815260200161213585613fa2565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906121f09033908990600401614f79565b600060405180830381600087803b15801561220a57600080fd5b505af115801561221e573d6000803e3d6000fd5b5050505061222b85613837565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff161561229d5760405162461bcd60e51b8152600401610a6890614e41565b600080516020615170833981519152805460011981016122cf5760405162461bcd60e51b8152600401610a6890614e69565b600282556122dc836130fa565b506001905550565b603754600160a81b900460ff161561230e5760405162461bcd60e51b8152600401610a6890614e41565b3360009081526035602052604090205460ff1615156001146123695760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a68565b3360009081526049602052604090205460ff1615156001146123c85760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a68565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516123f9929190614f79565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611bbf9033908590600401614f79565b603754600160a81b900460ff161561245d5760405162461bcd60e51b8152600401610a6890614e41565b6000805160206151708339815191528054600119810161248f5760405162461bcd60e51b8152600401610a6890614e69565b6002825561249b6132fa565b506124a461400b565b5060019055565b603f546001600160a01b03163314806124c757506124c76129d5565b6124e35760405162461bcd60e51b8152600401610a6890614dc2565b600080516020615170833981519152805460011981016125155760405162461bcd60e51b8152600401610a6890614e69565b60028255611d3a308888888888614234565b600080516020615170833981519152805460011981016125595760405162461bcd60e51b8152600401610a6890614e69565b60028255612565612c9e565b505060019055565b6125756129d5565b6125915760405162461bcd60e51b8152600401610a6890614e0a565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610adb565b603f546001600160a01b03163314806125e257506125e26129d5565b6125fe5760405162461bcd60e51b8152600401610a6890614dc2565b612606612c9e565b5060006301e13380612619606484614f92565b6126239190614f92565b90506126396201518066b1a2bc2ec50000614f92565b8111156126785760405162461bcd60e51b815260206004820152600d60248201526c0a4c2e8ca40e8dede40d0d2ced609b1b6044820152606401610a68565b61268181613038565b604f80546001600160401b0392909216600160801b0267ffffffffffffffff60801b199092169190911790556040518181527fef46f143af5fead0010484fe7d6ec2e2972420faa76157f5a6075aa72e614cb59060200160405180910390a15050565b6126ec6129d5565b6127085760405162461bcd60e51b8152600401610a6890614e0a565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d90602001610adb565b6119b66132fa565b6060603680548060200260200160405190810160405280929190818152602001828054801561279d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161277f575b5050505050905090565b6127af6129d5565b6127cb5760405162461bcd60e51b8152600401610a6890614e0a565b600054610100900460ff16806127e4575060005460ff16155b6128475760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a68565b600054610100900460ff16158015612869576000805461ffff19166101011790555b6001600160a01b0382166128b85760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b6044820152606401610a68565b603c80546001600160a01b0384166001600160a01b03199091161790556037805461ffff60a01b1916600160a81b1790556000603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b55604080519182526020820190819052905161292891603691614b02565b50604f805467ffffffffffffffff60401b19166a093a8000000000000000001790558015610cd8576000805461ff00191690555050565b603f546001600160a01b031633148061297b575061297b6129d5565b6129975760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b60006129ed6000805160206151908339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612a225750612a226129d5565b612a3e5760405162461bcd60e51b8152600401610a6890614dc2565b611a5d6143c5565b612a4e6129d5565b612a6a5760405162461bcd60e51b8152600401610a6890614e0a565b612a92817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612ab26000805160206151908339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000610c1961445a565b6000612b7d603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b709190614f15565b612b7861445a565b6144ae565b50919050565b603754600090600160a81b900460ff1615612bb05760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101612be25760405162461bcd60e51b8152600401610a6890614e69565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115612c2357612c216132fa565b505b612c2c846134d6565b9250612c626001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130a4565b612c946117b084601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b5060019055919050565b603754600090600160a01b900460ff1615612ced5760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b6044820152606401610a68565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612d37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d5b9190614f15565b90506000612d6761445a565b905081600003612d7a5791506130359050565b600080612d8784846144ae565b90925090506000612d988386614f66565b90508481111580612da857508381115b15612db7575091949350505050565b612dc8826001600160401b03614681565b604f805477ffffffffffffffffffffffffffffffff000000000000000016600160c01b6001600160401b039384160267ffffffffffffffff19161742929092169190911790556042546001600160a01b031660008115612f045761271060435486612e339190614fb4565b612e3d9190614f92565b90508015612f0457848110612e9f5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b6064820152608401610a68565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612ed19085908590600401614f79565b600060405180830381600087803b158015612eeb57600080fd5b505af1158015612eff573d6000803e3d6000fd5b505050505b604080516001600160a01b0384168152602081018790529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a1603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc59190614f15565b83111561302b57603c546040516339a7919f60e01b8152600481018590526001600160a01b03909116906339a7919f90602401600060405180830381600087803b15801561301257600080fd5b505af1158015613026573d6000803e3d6000fd5b505050505b5093955050505050505b90565b60006001600160401b038211156130a05760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610a68565b5090565b6110dd8363a9059cbb60e01b84846040516024016130c3929190614f79565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614697565b6000811161314a5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a68565b600061317b82601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b90507f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516131ae929190614f79565b60405180910390a1603754600160a01b900460ff161580156131d25750603b548110155b156131e1576131df612c9e565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132139033908590600401614f79565b600060405180830381600087803b15801561322d57600080fd5b505af1158015613241573d6000803e3d6000fd5b5061327c9250506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169050333085614769565b6132846132fa565b50603a548110610cd857610cd861400b565b6000818311156132c6576132bf6132ad8385614eec565b6132b890600a6150b2565b85906147a7565b93506132f0565b818310156132f0576132ed6132db8484614eec565b6132e690600a6150b2565b85906147b3565b93505b50825b9392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c548084169686019690965292909404166060830152600092839161334c916150be565b6001600160801b03169050806000036133685760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156133cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133f39190614f15565b905060008360400151846020015161340b91906150be565b6001600160801b0316905080821161342857600094505050505090565b60006134348284614eec565b90508084106134435780613445565b835b955060008686602001516001600160801b03166134629190614f66565b905061346d81613fa2565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f463333906134c59083908a90918252602082015260400190565b60405180910390a150505050505090565b600080604e54116135295760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a68565b6000828152604d6020908152604091829020825160a08101845281546001600160a01b038116825260ff600160a01b82041615158285015264ffffffffff600160a81b90910481168286019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915288519081018952604b548084168252849004831697810197909752604c54808316988801989098529190960490951694840194909452604e549151909342926135f092909116614f66565b11156136345760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b6044820152606401610a68565b80602001516001600160801b031682608001516001600160801b0316111561369e5760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c69717569646974790000000000000000006044820152606401610a68565b81516001600160a01b031633146136e75760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b6044820152606401610a68565b60208201511561372b5760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b6044820152606401610a68565b6000848152604d60205260409020805460ff60a01b1916600160a01b179055606082015161378b906120a3906001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b816040015161379a91906150dd565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a361382f82606001516001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b949350505050565b6000603b5482101580156138555750603754600160a01b900460ff16155b1561386957613862612c9e565b9050613874565b61387161445a565b90505b60415415610cd857600081116138cc5760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e672072657175657374730000006044820152606401610a68565b600061394f82603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613925573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139499190614f15565b906147bf565b9050604154670de0b6b3a7640000821161397a5761397582670de0b6b3a7640000614eec565b61398c565b61398c670de0b6b3a764000083614eec565b11156110dd5760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f7200006044820152606401610a68565b6001600160a01b03811660009081526035602052604090205460ff16613a425760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f72746564000000000000006044820152606401610a68565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a8257600080fd5b505af1158015613a96573d6000803e3d6000fd5b505050506110dd6132fa565b6001600160a01b038116613af85760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610a68565b6119b6816147e0565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614613b4457506000919050565b6040516370a0823160e01b815230600482015282906001600160a01b038216906370a0823190602401602060405180830381865afa158015613b8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bae9190614f15565b60365490925060005b81811015613cd357600060368281548110613bd457613bd4614ec0565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af690602401602060405180830381865afa158015613c2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4e9190614f44565b15613cca57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f51522690602401602060405180830381865afa158015613c99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cbd9190614f15565b613cc79086614f66565b94505b50600101613bb7565b5060408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529091613d219086614f66565b1015613d3257506000949350505050565b805160408201516001600160801b0391821691613d50911686614f66565b613d5a9190614eec565b95945050505050565b6001600160a01b03851660009081526035602052604090205460ff16613dc15760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b6044820152606401610a68565b600183148015613dd15750600181145b8015613e3557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684846000818110613e1557613e15614ec0565b9050602002016020810190613e2a9190614c05565b6001600160a01b0316145b613e815760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920617373657420697320737570706f727465640000000000000000006044820152606401610a68565b613e89614847565b82826000818110613e9c57613e9c614ec0565b905060200201351115613ef15760405162461bcd60e51b815260206004820152601b60248201527f4e6f7420656e6f7567682061737365747320617661696c61626c6500000000006044820152606401610a68565b613f488583836000818110613f0857613f08614ec0565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166130a49092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613f8357600080fd5b505af1158015613f97573d6000803e3d6000fd5b505050505050505050565b60006001600160801b038211156130a05760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610a68565b6050546001600160a01b03168061401f5750565b6000614029614847565b905080600003614037575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015614081573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140a59190614f15565b905060006140ee7f000000000000000000000000000000000000000000000000000000000000000060ff1660126140e76039548661495590919063ffffffff16565b9190613296565b90508083116140fd5750505050565b60006141098285614eec565b9050846141406001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682846130a4565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061418e907f0000000000000000000000000000000000000000000000000000000000000000908690600401614f79565b600060405180830381600087803b1580156141a857600080fd5b505af11580156141bc573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b6001600160a01b03851660009081526035602052604090205460ff166142945760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b6044820152606401610a68565b8281146142e35760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d61746368000000000000006044820152606401610a68565b8260005b818110156143b257866001600160a01b031663d9caed128988888581811061431157614311614ec0565b90506020020160208101906143269190614c05565b87878681811061433857614338614ec0565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561438f57600080fd5b505af11580156143a3573d6000803e3d6000fd5b505050508060010190506142e7565b506143bb6132fa565b5050505050505050565b60365460005b8181101561445157603681815481106143e6576143e6614ec0565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b15801561442e57600080fd5b505af1158015614442573d6000803e3d6000fd5b505050508060010190506143cb565b50610cd86132fa565b6000610c1960127f000000000000000000000000000000000000000000000000000000000000000060ff166140e77f0000000000000000000000000000000000000000000000000000000000000000613b01565b6000806000603c60009054906101000a90046001600160a01b03166001600160a01b031663e696393a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614506573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061452a9190614f15565b905060006145388287614eec565b604f54909150600090614554906001600160401b031642614eec565b604f54600160c01b90046001600160401b031694509050801580614576575081155b8061458057508587115b8061459257506001600160401b034210155b156145a3576000945050505061467a565b6145ad8787614eec565b604f54909550600160401b90046001600160401b03166001811115614612576145ea856145db836002614fb4565b6145e59089614f92565b61496a565b94506145ff856145fa8389614f92565b614681565b945061460f866145fa8488614fb4565b95505b604f54614653908790670de0b6b3a764000090600160801b90046001600160401b031661463f8688614fb4565b6146499190614fb4565b6145fa9190614f92565b955061467386670de0b6b3a764000061464966470de4df82000087614fb4565b9550505050505b9250929050565b600081831061469057816132f3565b5090919050565b60006146ec826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166149799092919063ffffffff16565b8051909150156110dd578080602001905181019061470a9190614f44565b6110dd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a68565b6040516001600160a01b03808516602483015283166044820152606481018290526147a19085906323b872dd60e01b906084016130c3565b50505050565b60006132f38284614fb4565b60006132f38284614f92565b6000806147d484670de0b6b3a76400006147a7565b905061382f81846147b3565b806001600160a01b03166148006000805160206151908339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a360008051602061519083398151915255565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c5480831695850186905292909204166060830152600092839161489791906150be565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561490c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149309190614f15565b9050818111614943576000935050505090565b61494d8282614eec565b935050505090565b60006132f38383670de0b6b3a7640000614988565b600081831161469057816132f3565b606061382f84846000856149a1565b60008061499585856147a7565b9050613d5a81846147b3565b606082471015614a025760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a68565b843b614a505760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a68565b600080866001600160a01b03168587604051614a6c9190615120565b60006040518083038185875af1925050503d8060008114614aa9576040519150601f19603f3d011682016040523d82523d6000602084013e614aae565b606091505b5091509150614abe828286614ac9565b979650505050505050565b60608315614ad85750816132f3565b825115614ae85782518084602001fd5b8160405162461bcd60e51b8152600401610a68919061513c565b828054828255906000526020600020908101928215614b57579160200282015b82811115614b5757825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614b22565b506130a09291505b808211156130a05760008155600101614b5f565b600060208284031215614b8557600080fd5b5035919050565b80356001600160a01b0381168114614ba357600080fd5b919050565b60008060408385031215614bbb57600080fd5b614bc483614b8c565b946020939093013593505050565b600080600060608486031215614be757600080fd5b614bf084614b8c565b95602085013595506040909401359392505050565b600060208284031215614c1757600080fd5b6132f382614b8c565b602080825282518282018190526000918401906040840190835b81811015614c615783516001600160a01b0316835260209384019390920191600101614c3a565b509095945050505050565b60008083601f840112614c7e57600080fd5b5081356001600160401b03811115614c9557600080fd5b6020830191508360208260051b850101111561467a57600080fd5b60008060208385031215614cc357600080fd5b82356001600160401b03811115614cd957600080fd5b614ce585828601614c6c565b90969095509350505050565b6040808252835190820181905260009060208501906060840190835b81811015614d2b578351835260209384019390920191600101614d0d565b5050602093909301939093525092915050565b600080600080600060608688031215614d5657600080fd5b614d5f86614b8c565b945060208601356001600160401b03811115614d7a57600080fd5b614d8688828901614c6c565b90955093505060408601356001600160401b03811115614da557600080fd5b614db188828901614c6c565b969995985093965092949392505050565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60208082526015908201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115611a6a57611a6a614ed6565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614f2757600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215614f5657600080fd5b815180151581146132f357600080fd5b80820180821115611a6a57611a6a614ed6565b6001600160a01b03929092168252602082015260400190565b600082614faf57634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417611a6a57611a6a614ed6565b6001815b600184111561500657808504811115614fea57614fea614ed6565b6001841615614ff857908102905b60019390931c928002614fcf565b935093915050565b60008261501d57506001611a6a565b8161502a57506000611a6a565b8160018114615040576002811461504a57615066565b6001915050611a6a565b60ff84111561505b5761505b614ed6565b50506001821b611a6a565b5060208310610133831016604e8410600b8410161715615089575081810a611a6a565b6150966000198484614fcb565b80600019048211156150aa576150aa614ed6565b029392505050565b60006132f3838361500e565b6001600160801b038281168282160390811115611a6a57611a6a614ed6565b6001600160801b038181168382160190811115611a6a57611a6a614ed6565b60005b838110156151175781810151838201526020016150ff565b50506000910152565b600082516151328184602087016150fc565b9190910192915050565b602081526000825180602084015261515b8160408501602087016150fc565b601f01601f1916919091016040019291505056fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220ad2bbf11f4c3aba5417c05c51e1987c17591311a3639bb4da53d878f94bbcc7864736f6c634300081c0033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106104075760003560e01c80636217f3ea11610220578063ae69f3cb11610130578063c5f00841116100b8578063d4c3eea011610087578063d4c3eea0146109e6578063e6cc5432146109ee578063ea33b8e414610a02578063f844443614610a0a578063fac5bb9b14610a1d57600080fd5b8063c5f00841146109bb578063c7af3352146109c3578063c9919112146109cb578063d38bfff4146109d357600080fd5b8063b890ebf6116100ff578063b890ebf61461096b578063b9b17f9f1461097e578063bb7a632e14610986578063c3b28864146109a0578063c4d66de8146109a857600080fd5b8063ae69f3cb1461092a578063af14052c1461093d578063b2c9336d14610945578063b4925a201461095857600080fd5b806394828ffd116101b35780639fa1826e116101825780639fa1826e146108ec578063a0712d68146108f5578063a0aead4d14610908578063ab80dafb1461090f578063abaa99161461092257600080fd5b806394828ffd1461086957806395b166bc146108715780639be918e6146108845780639ee679e8146108c457600080fd5b8063840c4c7a116101ef578063840c4c7a146107925780638e510b52146107a55780638ec489a2146107ae578063937b2581146107c157600080fd5b80636217f3ea14610746578063663e64ce14610759578063773540b31461076c57806378f353a11461077f57600080fd5b806339ebf8231161031b578063527e83a8116102ae57806357bee9441161027d57806357bee944146106f45780635802a17214610707578063597c8910146107185780635d36b1901461072b5780635f5152261461073357600080fd5b8063527e83a8146106aa57806352d38e5d146106c457806353ca9f24146106cd578063570d8e1d146106e157600080fd5b806345e4213b116102ea57806345e4213b1461063b57806348e30f541461064457806349c1d54d146106655780634d5f46291461067857600080fd5b806339ebf823146105a95780633b8ae397146105ed5780633dbc911f146106005780634530820a1461060857600080fd5b80631a32aad61161039e5780632acada4d1161036d5780632acada4d146104f35780632da845a81461050857806331e19cfa1461051b578063362bd1a31461052357806338d52e0f1461058257600080fd5b80631a32aad6146104ad5780631cfbe7bc146104c05780631edfe3da146104d3578063207134b0146104ea57600080fd5b80631072cbea116103da5780631072cbea14610461578063156e29f614610474578063175188e8146104875780631816dd4a1461049a57600080fd5b80630493a0fa1461040c57806309f49bf5146104215780630acbda75146104295780630c340a241461043c575b600080fd5b61041f61041a366004614b73565b610a30565b005b61041f610ae6565b61041f610437366004614b73565b610b56565b610444610c01565b6040516001600160a01b0390911681526020015b60405180910390f35b61041f61046f366004614ba8565b610c1e565b61041f610482366004614bd2565b610cdc565b61041f610495366004614c05565b610d4f565b61041f6104a8366004614c05565b6110e2565b603c54610444906001600160a01b031681565b61041f6104ce366004614b73565b6111e9565b6104dc60395481565b604051908152602001610458565b6104dc60435481565b6104fb6112ab565b6040516104589190614c20565b61041f610516366004614c05565b611322565b6036546104dc565b604b54604c5461054f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610458565b6104447f000000000000000000000000000000000000000000000000000000000000000081565b6105d66105b7366004614c05565b6035602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610458565b61041f6105fb366004614c05565b611394565b61041f6115a7565b61062b610616366004614c05565b60496020526000908152604090205460ff1681565b6040519015158152602001610458565b6104dc604e5481565b610657610652366004614cb0565b61161d565b604051610458929190614cf1565b604254610444906001600160a01b031681565b604f5461069290600160c01b90046001600160401b031681565b6040516001600160401b039091168152602001610458565b604f5461069290600160801b90046001600160401b031681565b6104dc603b5481565b60375461062b90600160a01b900460ff1681565b603f54610444906001600160a01b031681565b61041f610702366004614c05565b6117c2565b603c546001600160a01b0316610444565b61041f610726366004614c05565b611975565b61041f6119b9565b6104dc610741366004614c05565b611a5f565b61041f610754366004614b73565b611a70565b61041f610767366004614b73565b611bf4565b61041f61077a366004614c05565b611c4d565b604f54610692906001600160401b031681565b61041f6107a0366004614d3e565b611cbf565b6104dc60415481565b61041f6107bc366004614b73565b611d46565b6108226107cf366004614b73565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a001610458565b61041f611dfb565b61041f61087f366004614c05565b611e6b565b61062b610892366004614c05565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b6108d76108d2366004614b73565b611f32565b60408051928352602083019190915201610458565b6104dc603a5481565b61041f610903366004614b73565b612273565b60016104dc565b61041f61091d366004614b73565b6122e4565b61041f612433565b61041f610938366004614d3e565b6124ab565b61041f612527565b61041f610953366004614b73565b61256d565b61041f610966366004614b73565b6125c6565b61041f610979366004614b73565b6126e4565b61041f61273d565b604f5461069290600160401b90046001600160401b031681565b6104fb612745565b61041f6109b6366004614c05565b6127a7565b61041f61295f565b61062b6129d5565b61041f612a06565b61041f6109e1366004614c05565b612a46565b6104dc612aea565b60375461062b90600160a81b900460ff1681565b6104dc612af4565b6104dc610a18366004614b73565b612b83565b605054610444906001600160a01b031681565b603f546001600160a01b0316331480610a4c5750610a4c6129d5565b610a715760405162461bcd60e51b8152600401610a6890614dc2565b60405180910390fd5b610a79612c9e565b50610a8381613038565b604f80546001600160401b0392909216600160401b0267ffffffffffffffff60401b199092169190911790556040518181527f406e15fbca1d8ded2dbb06765fea3a54f18395c54125a4c9916dd00ea14ee15e906020015b60405180910390a150565b603f546001600160a01b0316331480610b025750610b026129d5565b610b1e5760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b610b5e6129d5565b610b7a5760405162461bcd60e51b8152600401610a6890614e0a565b611388811115610bcc5760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f7420657863656564203530250000000000000000006044820152606401610a68565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c790602001610adb565b6000610c196000805160206151908339815191525490565b905090565b610c266129d5565b610c425760405162461bcd60e51b8152600401610a6890614e0a565b816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610cbc5760405162461bcd60e51b815260206004820152601660248201527513db9b1e481d5b9cdd5c1c1bdc9d195908185cdcd95d60521b6044820152606401610a68565b610cd8610cc7610c01565b6001600160a01b03841690836130a4565b5050565b603754600160a81b900460ff1615610d065760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101610d385760405162461bcd60e51b8152600401610a6890614e69565b60028255610d45846130fa565b5060019055505050565b610d576129d5565b610d735760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff16610dab5760405162461bcd60e51b8152600401610a6890614e91565b6050546001600160a01b03808316911603610e085760405162461bcd60e51b815260206004820152601d60248201527f53747261746567792069732064656661756c7420666f722061737365740000006044820152606401610a68565b6036548060005b82811015610e5e57836001600160a01b031660368281548110610e3457610e34614ec0565b6000918252602090912001546001600160a01b031603610e5657809150610e5e565b600101610e0f565b50818110156110dd576036610e74600184614eec565b81548110610e8457610e84614ec0565b600091825260209091200154603680546001600160a01b039092169183908110610eb057610eb0614ec0565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610eef57610eef614eff565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038516808352603582526040808420805460ff1990811690915560499093528084208054909316909255815163429c145b60e11b815291518693919263853828b692600480830193919282900301818387803b158015610f7b57600080fd5b505af1158015610f8f573d6000803e3d6000fd5b5060009250610fcd91506509184e72a000905060ff7f0000000000000000000000000000000000000000000000000000000000000000166012613296565b604051632fa8a91360e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192508291841690635f51522690602401602060405180830381865afa158015611038573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105c9190614f15565b1061109e5760405162461bcd60e51b81526020600482015260126024820152715374726174656779206861732066756e647360701b6044820152606401610a68565b6040516001600160a01b03861681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49060200160405180910390a150505b505050565b6110ea6129d5565b6111065760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff1661113e5760405162461bcd60e51b8152600401610a6890614e91565b6001600160a01b03811660009081526049602052604090205460ff161561119d5760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481dda1a5d195b1a5cdd1959606a1b6044820152606401610a68565b6001600160a01b038116600081815260496020526040808220805460ff19166001179055517f47c8c96a5942f094264111c5fe7f6a4fe86efe63254a6fa7afa5fc84f07d58e89190a250565b6111f16129d5565b61120d5760405162461bcd60e51b8152600401610a6890614e0a565b80158061122a5750610258811015801561122a57506213c6808111155b6112765760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636c61696d2064656c617920706572696f640000000000006044820152606401610a68565b604e8190556040518181527fc59f5e32049abab44ddea11021f5abb89422a2f550837afcf25df9fc8d0db6b090602001610adb565b60408051600180825281830190925260609160009190602080830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061130557611305614ec0565b6001600160a01b0390921660209283029190910190910152919050565b61132a6129d5565b6113465760405162461bcd60e51b8152600401610a6890614e0a565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610adb565b61139c6129d5565b6113b85760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff16156114215760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f766564000000000000006044820152606401610a68565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa158015611487573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ab9190614f44565b6114f75760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a68565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610adb565b603f546001600160a01b03163314806115c357506115c36129d5565b6115df5760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b603754606090600090600160a81b900460ff161561164d5760405162461bcd60e51b8152600401610a6890614e41565b6000805160206151708339815191528054600119810161167f5760405162461bcd60e51b8152600401610a6890614e69565b6002825561168b6132fa565b50846001600160401b038111156116a4576116a4614f2e565b6040519080825280602002602001820160405280156116cd578160200160208202803683370190505b50935060005b85811015611749576116fc8787838181106116f0576116f0614ec0565b905060200201356134d6565b85828151811061170e5761170e614ec0565b60200260200101818152505084818151811061172c5761172c614ec0565b60200260200101518461173f9190614f66565b93506001016116d3565b5061177e6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130a4565b6117b56117b084601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b613837565b6001825550509250929050565b603f546001600160a01b03163314806117de57506117de6129d5565b6117fa5760405162461bcd60e51b8152600401610a6890614dc2565b6040516001600160a01b03821681527f45a9e715f8779ebeab88d3e8d081fb8b484b7730857e7c4478a95a5b1d8f79489060200160405180910390a16001600160a01b03811615611953576001600160a01b03811660009081526035602052604090205460ff1661187d5760405162461bcd60e51b8152600401610a6890614e91565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa1580156118e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119079190614f44565b6119535760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a68565b605080546001600160a01b0319166001600160a01b0392909216919091179055565b603f546001600160a01b031633148061199157506119916129d5565b6119ad5760405162461bcd60e51b8152600401610a6890614dc2565b6119b6816139da565b50565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614611a545760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610a68565b611a5d33613aa2565b565b6000611a6a82613b01565b92915050565b603754600160a81b900460ff1615611a9a5760405162461bcd60e51b8152600401610a6890614e41565b3360009081526035602052604090205460ff161515600114611af55760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a68565b3360009081526049602052604090205460ff161515600114611b545760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a68565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051611b85929190614f79565b60405180910390a1603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90611bbf9033908590600401614f79565b600060405180830381600087803b158015611bd957600080fd5b505af1158015611bed573d6000803e3d6000fd5b5050505050565b611bfc6129d5565b611c185760405162461bcd60e51b8152600401610a6890614e0a565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610adb565b611c556129d5565b611c715760405162461bcd60e51b8152600401610a6890614e0a565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610adb565b603f546001600160a01b0316331480611cdb5750611cdb6129d5565b611cf75760405162461bcd60e51b8152600401610a6890614dc2565b60008051602061517083398151915280546001198101611d295760405162461bcd60e51b8152600401610a6890614e69565b60028255611d3a8787878787613d63565b50600190555050505050565b603f546001600160a01b0316331480611d625750611d626129d5565b611d7e5760405162461bcd60e51b8152600401610a6890614dc2565b670de0b6b3a7640000811115611dc65760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b6044820152606401610a68565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610adb565b603f546001600160a01b0316331480611e175750611e176129d5565b611e335760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e736129d5565b611e8f5760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526049602052604090205460ff16611ee95760405162461bcd60e51b815260206004820152600f60248201526e139bdd081dda1a5d195b1a5cdd1959608a1b6044820152606401610a68565b6001600160a01b038116600081815260496020526040808220805460ff19169055517f0ec40967a61509853550658e51d0e4297f7cba244fe4adc8ba18b5631ac20e2f9190a250565b6037546000908190600160a81b900460ff1615611f615760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101611f935760405162461bcd60e51b8152600401610a6890614e69565b6002825560008511611fe75760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a68565b6000604e54116120395760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a68565b604c54600160801b90046001600160801b0316935061207d857f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b604b5461209391906001600160801b0316614f66565b92506120a86120a3856001614f66565b613fa2565b604c80546001600160801b03928316600160801b0292169190911790556120ce83613fa2565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff16918101919091526060810161211e87613fa2565b6001600160801b0316815260200161213585613fa2565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906121f09033908990600401614f79565b600060405180830381600087803b15801561220a57600080fd5b505af115801561221e573d6000803e3d6000fd5b5050505061222b85613837565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff161561229d5760405162461bcd60e51b8152600401610a6890614e41565b600080516020615170833981519152805460011981016122cf5760405162461bcd60e51b8152600401610a6890614e69565b600282556122dc836130fa565b506001905550565b603754600160a81b900460ff161561230e5760405162461bcd60e51b8152600401610a6890614e41565b3360009081526035602052604090205460ff1615156001146123695760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a68565b3360009081526049602052604090205460ff1615156001146123c85760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a68565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516123f9929190614f79565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611bbf9033908590600401614f79565b603754600160a81b900460ff161561245d5760405162461bcd60e51b8152600401610a6890614e41565b6000805160206151708339815191528054600119810161248f5760405162461bcd60e51b8152600401610a6890614e69565b6002825561249b6132fa565b506124a461400b565b5060019055565b603f546001600160a01b03163314806124c757506124c76129d5565b6124e35760405162461bcd60e51b8152600401610a6890614dc2565b600080516020615170833981519152805460011981016125155760405162461bcd60e51b8152600401610a6890614e69565b60028255611d3a308888888888614234565b600080516020615170833981519152805460011981016125595760405162461bcd60e51b8152600401610a6890614e69565b60028255612565612c9e565b505060019055565b6125756129d5565b6125915760405162461bcd60e51b8152600401610a6890614e0a565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610adb565b603f546001600160a01b03163314806125e257506125e26129d5565b6125fe5760405162461bcd60e51b8152600401610a6890614dc2565b612606612c9e565b5060006301e13380612619606484614f92565b6126239190614f92565b90506126396201518066b1a2bc2ec50000614f92565b8111156126785760405162461bcd60e51b815260206004820152600d60248201526c0a4c2e8ca40e8dede40d0d2ced609b1b6044820152606401610a68565b61268181613038565b604f80546001600160401b0392909216600160801b0267ffffffffffffffff60801b199092169190911790556040518181527fef46f143af5fead0010484fe7d6ec2e2972420faa76157f5a6075aa72e614cb59060200160405180910390a15050565b6126ec6129d5565b6127085760405162461bcd60e51b8152600401610a6890614e0a565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d90602001610adb565b6119b66132fa565b6060603680548060200260200160405190810160405280929190818152602001828054801561279d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161277f575b5050505050905090565b6127af6129d5565b6127cb5760405162461bcd60e51b8152600401610a6890614e0a565b600054610100900460ff16806127e4575060005460ff16155b6128475760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a68565b600054610100900460ff16158015612869576000805461ffff19166101011790555b6001600160a01b0382166128b85760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b6044820152606401610a68565b603c80546001600160a01b0384166001600160a01b03199091161790556037805461ffff60a01b1916600160a81b1790556000603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b55604080519182526020820190819052905161292891603691614b02565b50604f805467ffffffffffffffff60401b19166a093a8000000000000000001790558015610cd8576000805461ff00191690555050565b603f546001600160a01b031633148061297b575061297b6129d5565b6129975760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b60006129ed6000805160206151908339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612a225750612a226129d5565b612a3e5760405162461bcd60e51b8152600401610a6890614dc2565b611a5d6143c5565b612a4e6129d5565b612a6a5760405162461bcd60e51b8152600401610a6890614e0a565b612a92817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612ab26000805160206151908339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000610c1961445a565b6000612b7d603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b709190614f15565b612b7861445a565b6144ae565b50919050565b603754600090600160a81b900460ff1615612bb05760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101612be25760405162461bcd60e51b8152600401610a6890614e69565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115612c2357612c216132fa565b505b612c2c846134d6565b9250612c626001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130a4565b612c946117b084601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b5060019055919050565b603754600090600160a01b900460ff1615612ced5760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b6044820152606401610a68565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612d37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d5b9190614f15565b90506000612d6761445a565b905081600003612d7a5791506130359050565b600080612d8784846144ae565b90925090506000612d988386614f66565b90508481111580612da857508381115b15612db7575091949350505050565b612dc8826001600160401b03614681565b604f805477ffffffffffffffffffffffffffffffff000000000000000016600160c01b6001600160401b039384160267ffffffffffffffff19161742929092169190911790556042546001600160a01b031660008115612f045761271060435486612e339190614fb4565b612e3d9190614f92565b90508015612f0457848110612e9f5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b6064820152608401610a68565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612ed19085908590600401614f79565b600060405180830381600087803b158015612eeb57600080fd5b505af1158015612eff573d6000803e3d6000fd5b505050505b604080516001600160a01b0384168152602081018790529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a1603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc59190614f15565b83111561302b57603c546040516339a7919f60e01b8152600481018590526001600160a01b03909116906339a7919f90602401600060405180830381600087803b15801561301257600080fd5b505af1158015613026573d6000803e3d6000fd5b505050505b5093955050505050505b90565b60006001600160401b038211156130a05760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610a68565b5090565b6110dd8363a9059cbb60e01b84846040516024016130c3929190614f79565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614697565b6000811161314a5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a68565b600061317b82601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b90507f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516131ae929190614f79565b60405180910390a1603754600160a01b900460ff161580156131d25750603b548110155b156131e1576131df612c9e565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132139033908590600401614f79565b600060405180830381600087803b15801561322d57600080fd5b505af1158015613241573d6000803e3d6000fd5b5061327c9250506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169050333085614769565b6132846132fa565b50603a548110610cd857610cd861400b565b6000818311156132c6576132bf6132ad8385614eec565b6132b890600a6150b2565b85906147a7565b93506132f0565b818310156132f0576132ed6132db8484614eec565b6132e690600a6150b2565b85906147b3565b93505b50825b9392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c548084169686019690965292909404166060830152600092839161334c916150be565b6001600160801b03169050806000036133685760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156133cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133f39190614f15565b905060008360400151846020015161340b91906150be565b6001600160801b0316905080821161342857600094505050505090565b60006134348284614eec565b90508084106134435780613445565b835b955060008686602001516001600160801b03166134629190614f66565b905061346d81613fa2565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f463333906134c59083908a90918252602082015260400190565b60405180910390a150505050505090565b600080604e54116135295760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a68565b6000828152604d6020908152604091829020825160a08101845281546001600160a01b038116825260ff600160a01b82041615158285015264ffffffffff600160a81b90910481168286019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915288519081018952604b548084168252849004831697810197909752604c54808316988801989098529190960490951694840194909452604e549151909342926135f092909116614f66565b11156136345760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b6044820152606401610a68565b80602001516001600160801b031682608001516001600160801b0316111561369e5760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c69717569646974790000000000000000006044820152606401610a68565b81516001600160a01b031633146136e75760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b6044820152606401610a68565b60208201511561372b5760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b6044820152606401610a68565b6000848152604d60205260409020805460ff60a01b1916600160a01b179055606082015161378b906120a3906001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b816040015161379a91906150dd565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a361382f82606001516001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b949350505050565b6000603b5482101580156138555750603754600160a01b900460ff16155b1561386957613862612c9e565b9050613874565b61387161445a565b90505b60415415610cd857600081116138cc5760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e672072657175657374730000006044820152606401610a68565b600061394f82603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613925573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139499190614f15565b906147bf565b9050604154670de0b6b3a7640000821161397a5761397582670de0b6b3a7640000614eec565b61398c565b61398c670de0b6b3a764000083614eec565b11156110dd5760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f7200006044820152606401610a68565b6001600160a01b03811660009081526035602052604090205460ff16613a425760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f72746564000000000000006044820152606401610a68565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a8257600080fd5b505af1158015613a96573d6000803e3d6000fd5b505050506110dd6132fa565b6001600160a01b038116613af85760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610a68565b6119b6816147e0565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614613b4457506000919050565b6040516370a0823160e01b815230600482015282906001600160a01b038216906370a0823190602401602060405180830381865afa158015613b8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bae9190614f15565b60365490925060005b81811015613cd357600060368281548110613bd457613bd4614ec0565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af690602401602060405180830381865afa158015613c2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4e9190614f44565b15613cca57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f51522690602401602060405180830381865afa158015613c99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cbd9190614f15565b613cc79086614f66565b94505b50600101613bb7565b5060408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529091613d219086614f66565b1015613d3257506000949350505050565b805160408201516001600160801b0391821691613d50911686614f66565b613d5a9190614eec565b95945050505050565b6001600160a01b03851660009081526035602052604090205460ff16613dc15760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b6044820152606401610a68565b600183148015613dd15750600181145b8015613e3557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684846000818110613e1557613e15614ec0565b9050602002016020810190613e2a9190614c05565b6001600160a01b0316145b613e815760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920617373657420697320737570706f727465640000000000000000006044820152606401610a68565b613e89614847565b82826000818110613e9c57613e9c614ec0565b905060200201351115613ef15760405162461bcd60e51b815260206004820152601b60248201527f4e6f7420656e6f7567682061737365747320617661696c61626c6500000000006044820152606401610a68565b613f488583836000818110613f0857613f08614ec0565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166130a49092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613f8357600080fd5b505af1158015613f97573d6000803e3d6000fd5b505050505050505050565b60006001600160801b038211156130a05760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610a68565b6050546001600160a01b03168061401f5750565b6000614029614847565b905080600003614037575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015614081573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140a59190614f15565b905060006140ee7f000000000000000000000000000000000000000000000000000000000000000060ff1660126140e76039548661495590919063ffffffff16565b9190613296565b90508083116140fd5750505050565b60006141098285614eec565b9050846141406001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682846130a4565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061418e907f0000000000000000000000000000000000000000000000000000000000000000908690600401614f79565b600060405180830381600087803b1580156141a857600080fd5b505af11580156141bc573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b6001600160a01b03851660009081526035602052604090205460ff166142945760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b6044820152606401610a68565b8281146142e35760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d61746368000000000000006044820152606401610a68565b8260005b818110156143b257866001600160a01b031663d9caed128988888581811061431157614311614ec0565b90506020020160208101906143269190614c05565b87878681811061433857614338614ec0565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561438f57600080fd5b505af11580156143a3573d6000803e3d6000fd5b505050508060010190506142e7565b506143bb6132fa565b5050505050505050565b60365460005b8181101561445157603681815481106143e6576143e6614ec0565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b15801561442e57600080fd5b505af1158015614442573d6000803e3d6000fd5b505050508060010190506143cb565b50610cd86132fa565b6000610c1960127f000000000000000000000000000000000000000000000000000000000000000060ff166140e77f0000000000000000000000000000000000000000000000000000000000000000613b01565b6000806000603c60009054906101000a90046001600160a01b03166001600160a01b031663e696393a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614506573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061452a9190614f15565b905060006145388287614eec565b604f54909150600090614554906001600160401b031642614eec565b604f54600160c01b90046001600160401b031694509050801580614576575081155b8061458057508587115b8061459257506001600160401b034210155b156145a3576000945050505061467a565b6145ad8787614eec565b604f54909550600160401b90046001600160401b03166001811115614612576145ea856145db836002614fb4565b6145e59089614f92565b61496a565b94506145ff856145fa8389614f92565b614681565b945061460f866145fa8488614fb4565b95505b604f54614653908790670de0b6b3a764000090600160801b90046001600160401b031661463f8688614fb4565b6146499190614fb4565b6145fa9190614f92565b955061467386670de0b6b3a764000061464966470de4df82000087614fb4565b9550505050505b9250929050565b600081831061469057816132f3565b5090919050565b60006146ec826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166149799092919063ffffffff16565b8051909150156110dd578080602001905181019061470a9190614f44565b6110dd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a68565b6040516001600160a01b03808516602483015283166044820152606481018290526147a19085906323b872dd60e01b906084016130c3565b50505050565b60006132f38284614fb4565b60006132f38284614f92565b6000806147d484670de0b6b3a76400006147a7565b905061382f81846147b3565b806001600160a01b03166148006000805160206151908339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a360008051602061519083398151915255565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c5480831695850186905292909204166060830152600092839161489791906150be565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561490c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149309190614f15565b9050818111614943576000935050505090565b61494d8282614eec565b935050505090565b60006132f38383670de0b6b3a7640000614988565b600081831161469057816132f3565b606061382f84846000856149a1565b60008061499585856147a7565b9050613d5a81846147b3565b606082471015614a025760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a68565b843b614a505760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a68565b600080866001600160a01b03168587604051614a6c9190615120565b60006040518083038185875af1925050503d8060008114614aa9576040519150601f19603f3d011682016040523d82523d6000602084013e614aae565b606091505b5091509150614abe828286614ac9565b979650505050505050565b60608315614ad85750816132f3565b825115614ae85782518084602001fd5b8160405162461bcd60e51b8152600401610a68919061513c565b828054828255906000526020600020908101928215614b57579160200282015b82811115614b5757825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614b22565b506130a09291505b808211156130a05760008155600101614b5f565b600060208284031215614b8557600080fd5b5035919050565b80356001600160a01b0381168114614ba357600080fd5b919050565b60008060408385031215614bbb57600080fd5b614bc483614b8c565b946020939093013593505050565b600080600060608486031215614be757600080fd5b614bf084614b8c565b95602085013595506040909401359392505050565b600060208284031215614c1757600080fd5b6132f382614b8c565b602080825282518282018190526000918401906040840190835b81811015614c615783516001600160a01b0316835260209384019390920191600101614c3a565b509095945050505050565b60008083601f840112614c7e57600080fd5b5081356001600160401b03811115614c9557600080fd5b6020830191508360208260051b850101111561467a57600080fd5b60008060208385031215614cc357600080fd5b82356001600160401b03811115614cd957600080fd5b614ce585828601614c6c565b90969095509350505050565b6040808252835190820181905260009060208501906060840190835b81811015614d2b578351835260209384019390920191600101614d0d565b5050602093909301939093525092915050565b600080600080600060608688031215614d5657600080fd5b614d5f86614b8c565b945060208601356001600160401b03811115614d7a57600080fd5b614d8688828901614c6c565b90955093505060408601356001600160401b03811115614da557600080fd5b614db188828901614c6c565b969995985093965092949392505050565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60208082526015908201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115611a6a57611a6a614ed6565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614f2757600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215614f5657600080fd5b815180151581146132f357600080fd5b80820180821115611a6a57611a6a614ed6565b6001600160a01b03929092168252602082015260400190565b600082614faf57634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417611a6a57611a6a614ed6565b6001815b600184111561500657808504811115614fea57614fea614ed6565b6001841615614ff857908102905b60019390931c928002614fcf565b935093915050565b60008261501d57506001611a6a565b8161502a57506000611a6a565b8160018114615040576002811461504a57615066565b6001915050611a6a565b60ff84111561505b5761505b614ed6565b50506001821b611a6a565b5060208310610133831016604e8410600b8410161715615089575081810a611a6a565b6150966000198484614fcb565b80600019048211156150aa576150aa614ed6565b029392505050565b60006132f3838361500e565b6001600160801b038281168282160390811115611a6a57611a6a614ed6565b6001600160801b038181168382160190811115611a6a57611a6a614ed6565b60005b838110156151175781810151838201526020016150ff565b50506000910152565b600082516151328184602087016150fc565b9190910192915050565b602081526000825180602084015261515b8160408501602087016150fc565b601f01601f1916919091016040019291505056fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220ad2bbf11f4c3aba5417c05c51e1987c17591311a3639bb4da53d878f94bbcc7864736f6c634300081c0033", + "numDeployments": 3, + "solcInputHash": "f4384e86fd2a870879603d18d53c5b16", + "metadata": "{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"AllocateThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"AssetAllocated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"DefaultStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dripDuration\",\"type\":\"uint256\"}],\"name\":\"DripDurationChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"MaxSupplyDiffChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newOperator\",\"type\":\"address\"}],\"name\":\"OperatorUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebasePaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rebaseRatePerSecond\",\"type\":\"uint256\"}],\"name\":\"RebasePerSecondMaxChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebaseUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"StrategistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyAddedToMintWhitelist\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyRemovedFromMintWhitelist\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"TrusteeAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"TrusteeFeeBpsChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"VaultBufferUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newDelay\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_claimable\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newClaimable\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimable\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_queued\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_yield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"YieldDistribution\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddr\",\"type\":\"address\"}],\"name\":\"addStrategyToMintWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"addWithdrawalQueueLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"allocate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"approveStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"asset\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"autoAllocateThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"burnForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capitalPaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"claimWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_requestIds\",\"type\":\"uint256[]\"}],\"name\":\"claimWithdrawals\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"totalAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultStrategy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyToAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"depositToStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dripDuration\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAssets\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllStrategies\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAssetCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStrategyCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_oToken\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isMintWhitelistedStrategy\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"isSupportedAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRebase\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxSupplyDiff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mintForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oToken\",\"outputs\":[{\"internalType\":\"contract OUSD\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oUSD\",\"outputs\":[{\"internalType\":\"contract OUSD\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatorAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previewYield\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"yield\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePerSecondMax\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePerSecondTarget\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"removeStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddr\",\"type\":\"address\"}],\"name\":\"removeStrategyFromMintWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"requestWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"queued\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setAutoAllocateThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"setDefaultStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dripDuration\",\"type\":\"uint256\"}],\"name\":\"setDripDuration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"setMaxSupplyDiff\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_operator\",\"type\":\"address\"}],\"name\":\"setOperatorAddr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"apr\",\"type\":\"uint256\"}],\"name\":\"setRebaseRateMax\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setStrategistAddr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setTrusteeAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"setTrusteeFeeBps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"setVaultBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_delay\",\"type\":\"uint256\"}],\"name\":\"setWithdrawalClaimDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"strategies\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isSupported\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"_deprecated\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategistAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"transferToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAllFromStrategies\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"}],\"name\":\"withdrawAllFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyFromAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"withdrawFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalClaimDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalQueueMetadata\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimable\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimed\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"nextWithdrawalIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"withdrawalRequests\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"claimed\",\"type\":\"bool\"},{\"internalType\":\"uint40\",\"name\":\"timestamp\",\"type\":\"uint40\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"addStrategyToMintWhitelist(address)\":{\"params\":{\"strategyAddr\":\"Strategy address\"}},\"addWithdrawalQueueLiquidity()\":{\"details\":\"is called from the Native Staking strategy when validator withdrawals are processed. It also called before any WETH is allocated to a strategy.\"},\"approveStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to add\"}},\"burnForStrategy(uint256)\":{\"details\":\"Notice: can't use `nonReentrant` modifier since the `redeem` function could require withdrawal on an AMO strategy and that one can call `burnForStrategy` while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\",\"params\":{\"_amount\":\"Amount of OToken to burn\"}},\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of asset\"},\"returns\":{\"_0\":\"uint256 Balance of asset in decimals of asset\"}},\"claimWithdrawal(uint256)\":{\"params\":{\"_requestId\":\"Unique ID for the withdrawal request\"},\"returns\":{\"amount\":\"Amount of asset transferred to the withdrawer\"}},\"claimWithdrawals(uint256[])\":{\"params\":{\"_requestIds\":\"Unique ID of each withdrawal request\"},\"returns\":{\"amounts\":\"Amount of asset received for each request\",\"totalAmount\":\"Total amount of asset transferred to the withdrawer\"}},\"depositToStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to deposit.\",\"_assets\":\"Array of asset address that will be deposited into the strategy.\",\"_strategyToAddress\":\"Address of the Strategy to deposit asset into.\"}},\"isSupportedAsset(address)\":{\"params\":{\"_asset\":\"address of the asset\"},\"returns\":{\"_0\":\"true if supported\"}},\"mint(address,uint256,uint256)\":{\"details\":\"Deprecated: use `mint(uint256 _amount)` instead.Deprecated: param _asset Address of the asset being depositedDeprecated: param _minimumOusdAmount Minimum OTokens to mint\",\"params\":{\"_amount\":\"Amount of the asset being deposited\"}},\"mint(uint256)\":{\"params\":{\"_amount\":\"Amount of the asset being deposited\"}},\"mintForStrategy(uint256)\":{\"params\":{\"_amount\":\"Amount of OToken to mint Notice: can't use `nonReentrant` modifier since the `mint` function can call `allocate`, and that can trigger an AMO strategy to call this function while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\"}},\"previewYield()\":{\"returns\":{\"yield\":\"amount of expected yield\"}},\"rebase()\":{\"details\":\"Restricted to the Operator, Strategist or Governor.\"},\"removeStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to remove\"}},\"removeStrategyFromMintWhitelist(address)\":{\"params\":{\"strategyAddr\":\"Strategy address\"}},\"requestWithdrawal(uint256)\":{\"params\":{\"_amount\":\"Amount of OToken to burn.\"},\"returns\":{\"queued\":\"Cumulative total of all asset queued including already claimed requests.\",\"requestId\":\"Unique ID for the withdrawal request\"}},\"setAutoAllocateThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setDefaultStrategy(address)\":{\"params\":{\"_strategy\":\"Address of the Strategy\"}},\"setDripDuration(uint256)\":{\"params\":{\"_dripDuration\":\"Time in seconds to target a constant yield rate\"}},\"setOperatorAddr(address)\":{\"params\":{\"_operator\":\"New operator address. May be set to the zero address to disable operator-initiated rebases.\"}},\"setRebaseRateMax(uint256)\":{\"params\":{\"apr\":\"in 1e18 notation. 3 * 1e18 = 3% APR\"}},\"setStrategistAddr(address)\":{\"params\":{\"_address\":\"Address of Strategist\"}},\"setVaultBuffer(uint256)\":{\"params\":{\"_vaultBuffer\":\"Percentage using 18 decimals. 100% = 1e18.\"}},\"setWithdrawalClaimDelay(uint256)\":{\"params\":{\"_delay\":\"Delay period (should be between 10 mins to 7 days). Set to 0 to disable async withdrawals\"}},\"totalValue()\":{\"returns\":{\"value\":\"Total value in USD/ETH (1e18)\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"transferToken(address,uint256)\":{\"params\":{\"_amount\":\"Amount of the asset to transfer\",\"_asset\":\"Address for the asset\"}},\"withdrawAllFromStrategy(address)\":{\"params\":{\"_strategyAddr\":\"Strategy address.\"}},\"withdrawFromStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to withdraw.\",\"_assets\":\"Array of asset address that will be withdrawn from the strategy.\",\"_strategyFromAddress\":\"Address of the Strategy to withdraw asset from.\"}}},\"title\":\"OETH VaultAdmin Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"addStrategyToMintWhitelist(address)\":{\"notice\":\"Adds a strategy to the mint whitelist. Reverts if strategy isn't approved on Vault.\"},\"addWithdrawalQueueLiquidity()\":{\"notice\":\"Adds WETH to the withdrawal queue if there is a funding shortfall.\"},\"allocate()\":{\"notice\":\"Allocate unallocated funds on Vault to strategies.\"},\"approveStrategy(address)\":{\"notice\":\"Add a strategy to the Vault.\"},\"autoAllocateThreshold()\":{\"notice\":\"OToken mints over this amount automatically allocate funds. 18 decimals.\"},\"burnForStrategy(uint256)\":{\"notice\":\"Burn OTokens for an allowed Strategy\"},\"capitalPaused()\":{\"notice\":\"pause operations that change the OToken supply. eg mint, redeem, allocate, mint/burn for strategy\"},\"checkBalance(address)\":{\"notice\":\"Get the balance of an asset held in Vault and all strategies.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"claimWithdrawal(uint256)\":{\"notice\":\"Claim a previously requested withdrawal once it is claimable. This request can be claimed once the withdrawal queue's `claimable` amount is greater than or equal this request's `queued` amount and 10 minutes has passed. If the requests is not claimable, the transaction will revert with `Queue pending liquidity`. If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`. OToken is converted to asset at 1:1.\"},\"claimWithdrawals(uint256[])\":{\"notice\":\"Claim a previously requested withdrawals once they are claimable. This requests can be claimed once the withdrawal queue's `claimable` amount is greater than or equal each request's `queued` amount and 10 minutes has passed. If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`. If one of the requests is not older than 10 minutes, the whole transaction will revert with `Claim delay not met`.\"},\"defaultStrategy()\":{\"notice\":\"Default strategy for asset\"},\"depositToStrategy(address,address[],uint256[])\":{\"notice\":\"Deposit multiple asset from the vault into the strategy.\"},\"dripDuration()\":{\"notice\":\"Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\"},\"getAllAssets()\":{\"notice\":\"Return all vault asset addresses in order\"},\"getAllStrategies()\":{\"notice\":\"Return the array of all strategies\"},\"getAssetCount()\":{\"notice\":\"Return the number of asset supported by the Vault.\"},\"getStrategyCount()\":{\"notice\":\"Return the number of strategies active on the Vault.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"isSupportedAsset(address)\":{\"notice\":\"Returns whether the vault supports the asset\"},\"lastRebase()\":{\"notice\":\"Time in seconds that the vault last rebased yield.\"},\"maxSupplyDiff()\":{\"notice\":\"Max difference between total supply and total value of assets. 18 decimals.\"},\"mint(address,uint256,uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mint(uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mintForStrategy(uint256)\":{\"notice\":\"Mint OTokens for an allowed Strategy\"},\"oUSD()\":{\"notice\":\"Deprecated: use `oToken()` instead.\"},\"operatorAddr()\":{\"notice\":\"Address authorized to call `rebase()` directly. The Governor and Strategist are always allowed in addition to this address.\"},\"pauseCapital()\":{\"notice\":\"Set the deposit paused flag to true to prevent capital movement.\"},\"pauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to prevent rebasing.\"},\"previewYield()\":{\"notice\":\"Calculates the amount that would rebase at next rebase. This is before any fees.\"},\"rebase()\":{\"notice\":\"Calculate the total value of asset held by the Vault and all strategies and update the supply of OTokens.\"},\"rebasePaused()\":{\"notice\":\"pause rebasing if true\"},\"rebasePerSecondMax()\":{\"notice\":\"max rebase percentage per second Can be used to set maximum yield of the protocol, spreading out yield over time\"},\"rebasePerSecondTarget()\":{\"notice\":\"target rebase rate limit, based on past rates and funds available.\"},\"removeStrategy(address)\":{\"notice\":\"Remove a strategy from the Vault.\"},\"removeStrategyFromMintWhitelist(address)\":{\"notice\":\"Removes a strategy from the mint whitelist.\"},\"requestWithdrawal(uint256)\":{\"notice\":\"Request an asynchronous withdrawal of asset in exchange for OToken. The OToken is burned on request and the asset is transferred to the withdrawer on claim. This request can be claimed once the withdrawal queue's `claimable` amount is greater than or equal this request's `queued` amount. There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue. OToken is converted to asset at 1:1.\"},\"setAutoAllocateThreshold(uint256)\":{\"notice\":\"Sets the minimum amount of OTokens in a mint to trigger an automatic allocation of funds afterwords.\"},\"setDefaultStrategy(address)\":{\"notice\":\"Set the default Strategy for asset, i.e. the one which the asset will be automatically allocated to and withdrawn from\"},\"setDripDuration(uint256)\":{\"notice\":\"Set the drip duration period\"},\"setMaxSupplyDiff(uint256)\":{\"notice\":\"Sets the maximum allowable difference between total supply and asset' value.\"},\"setOperatorAddr(address)\":{\"notice\":\"Set the address authorized to call `rebase()`.\"},\"setRebaseRateMax(uint256)\":{\"notice\":\"Set a yield streaming max rate. This spreads yield over time if it is above the max rate. This is a per rebase APR which due to compounding differs from the yearly APR. Governance should consider this fact when picking a desired APR\"},\"setStrategistAddr(address)\":{\"notice\":\"Set address of Strategist\"},\"setTrusteeAddress(address)\":{\"notice\":\"Sets the trusteeAddress that can receive a portion of yield. Setting to the zero address disables this feature.\"},\"setTrusteeFeeBps(uint256)\":{\"notice\":\"Sets the TrusteeFeeBps to the percentage of yield that should be received in basis points.\"},\"setVaultBuffer(uint256)\":{\"notice\":\"Set a buffer of asset to keep in the Vault to handle most redemptions without needing to spend gas unwinding asset from a Strategy.\"},\"setWithdrawalClaimDelay(uint256)\":{\"notice\":\"Changes the async withdrawal claim period for OETH & superOETHb\"},\"strategistAddr()\":{\"notice\":\"Address of the Strategist\"},\"totalValue()\":{\"notice\":\"Determine the total value of asset held by the vault and its strategies.\"},\"transferGovernance(address)\":{\"notice\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\"},\"transferToken(address,uint256)\":{\"notice\":\"Transfer token to governor. Intended for recovering tokens stuck in contract, i.e. mistaken sends.\"},\"trusteeAddress()\":{\"notice\":\"Trustee contract that can collect a percentage of yield\"},\"trusteeFeeBps()\":{\"notice\":\"Amount of yield collected in basis points. eg 2000 = 20%\"},\"unpauseCapital()\":{\"notice\":\"Set the deposit paused flag to false to enable capital movement.\"},\"unpauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to allow rebasing.\"},\"vaultBuffer()\":{\"notice\":\"Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\"},\"withdrawAllFromStrategies()\":{\"notice\":\"Withdraws all asset from all the strategies and sends asset to the Vault.\"},\"withdrawAllFromStrategy(address)\":{\"notice\":\"Withdraws all asset from the strategy and sends asset to the Vault.\"},\"withdrawFromStrategy(address,address[],uint256[])\":{\"notice\":\"Withdraw multiple asset from the strategy to the vault.\"},\"withdrawalClaimDelay()\":{\"notice\":\"Sets a minimum delay that is required to elapse between requesting async withdrawals and claiming the request. When set to 0 async withdrawals are disabled.\"},\"withdrawalQueueMetadata()\":{\"notice\":\"Global metadata for the withdrawal queue including: queued - cumulative total of all withdrawal requests included the ones that have already been claimed claimable - cumulative total of all the requests that can be claimed including the ones already claimed claimed - total of all the requests that have been claimed nextWithdrawalIndex - index of the next withdrawal request starting at 0\"},\"withdrawalRequests(uint256)\":{\"notice\":\"Mapping of withdrawal request indices to the user withdrawal request data\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/vault/OETHVault.sol\":\"OETHVault\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0x61437cb513a887a1bbad006e7b1c8b414478427d33de47c5600af3c748f108da\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeCast.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\\n * checks.\\n *\\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\\n * easily result in undesired exploitation or bugs, since developers usually\\n * assume that overflows raise errors. `SafeCast` restores this intuition by\\n * reverting the transaction when such an operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n *\\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\\n * all math on `uint256` and `int256` and then downcasting.\\n */\\nlibrary SafeCast {\\n /**\\n * @dev Returns the downcasted uint224 from uint256, reverting on\\n * overflow (when the input is greater than largest uint224).\\n *\\n * Counterpart to Solidity's `uint224` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 224 bits\\n */\\n function toUint224(uint256 value) internal pure returns (uint224) {\\n require(value <= type(uint224).max, \\\"SafeCast: value doesn't fit in 224 bits\\\");\\n return uint224(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint128 from uint256, reverting on\\n * overflow (when the input is greater than largest uint128).\\n *\\n * Counterpart to Solidity's `uint128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n */\\n function toUint128(uint256 value) internal pure returns (uint128) {\\n require(value <= type(uint128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return uint128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint96 from uint256, reverting on\\n * overflow (when the input is greater than largest uint96).\\n *\\n * Counterpart to Solidity's `uint96` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 96 bits\\n */\\n function toUint96(uint256 value) internal pure returns (uint96) {\\n require(value <= type(uint96).max, \\\"SafeCast: value doesn't fit in 96 bits\\\");\\n return uint96(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint64 from uint256, reverting on\\n * overflow (when the input is greater than largest uint64).\\n *\\n * Counterpart to Solidity's `uint64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n */\\n function toUint64(uint256 value) internal pure returns (uint64) {\\n require(value <= type(uint64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return uint64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint32 from uint256, reverting on\\n * overflow (when the input is greater than largest uint32).\\n *\\n * Counterpart to Solidity's `uint32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n */\\n function toUint32(uint256 value) internal pure returns (uint32) {\\n require(value <= type(uint32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return uint32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint16 from uint256, reverting on\\n * overflow (when the input is greater than largest uint16).\\n *\\n * Counterpart to Solidity's `uint16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n */\\n function toUint16(uint256 value) internal pure returns (uint16) {\\n require(value <= type(uint16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return uint16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint8 from uint256, reverting on\\n * overflow (when the input is greater than largest uint8).\\n *\\n * Counterpart to Solidity's `uint8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits.\\n */\\n function toUint8(uint256 value) internal pure returns (uint8) {\\n require(value <= type(uint8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return uint8(value);\\n }\\n\\n /**\\n * @dev Converts a signed int256 into an unsigned uint256.\\n *\\n * Requirements:\\n *\\n * - input must be greater than or equal to 0.\\n */\\n function toUint256(int256 value) internal pure returns (uint256) {\\n require(value >= 0, \\\"SafeCast: value must be positive\\\");\\n return uint256(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int128 from int256, reverting on\\n * overflow (when the input is less than smallest int128 or\\n * greater than largest int128).\\n *\\n * Counterpart to Solidity's `int128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt128(int256 value) internal pure returns (int128) {\\n require(value >= type(int128).min && value <= type(int128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return int128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int64 from int256, reverting on\\n * overflow (when the input is less than smallest int64 or\\n * greater than largest int64).\\n *\\n * Counterpart to Solidity's `int64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt64(int256 value) internal pure returns (int64) {\\n require(value >= type(int64).min && value <= type(int64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return int64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int32 from int256, reverting on\\n * overflow (when the input is less than smallest int32 or\\n * greater than largest int32).\\n *\\n * Counterpart to Solidity's `int32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt32(int256 value) internal pure returns (int32) {\\n require(value >= type(int32).min && value <= type(int32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return int32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int16 from int256, reverting on\\n * overflow (when the input is less than smallest int16 or\\n * greater than largest int16).\\n *\\n * Counterpart to Solidity's `int16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt16(int256 value) internal pure returns (int16) {\\n require(value >= type(int16).min && value <= type(int16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return int16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int8 from int256, reverting on\\n * overflow (when the input is less than smallest int8 or\\n * greater than largest int8).\\n *\\n * Counterpart to Solidity's `int8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits.\\n *\\n * _Available since v3.1._\\n */\\n function toInt8(int256 value) internal pure returns (int8) {\\n require(value >= type(int8).min && value <= type(int8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return int8(value);\\n }\\n\\n /**\\n * @dev Converts an unsigned uint256 into a signed int256.\\n *\\n * Requirements:\\n *\\n * - input must be less than or equal to maxInt256.\\n */\\n function toInt256(uint256 value) internal pure returns (int256) {\\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\\n require(value <= uint256(type(int256).max), \\\"SafeCast: value doesn't fit in an int256\\\");\\n return int256(value);\\n }\\n}\\n\",\"keccak256\":\"0x5c6caab697d302ad7eb59c234a4d2dbc965c1bae87709bd2850060b7695b28c7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa2f576be637946f767aa56601c26d717f48a0aff44f82e46f13807eea1009a21\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @notice Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @notice Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n emit GovernorshipTransferred(_governor(), newGovernor);\\n\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0xf32f873c8bfbacf2e5f01d0cf37bc7f54fbd5aa656e95c8a599114229946f107\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xa562062698aa12572123b36dfd2072f1a39e44fed2031cc19c2c9fd522f96ec2\",\"license\":\"MIT\"},\"contracts/interfaces/IStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\\n */\\ninterface IStrategy {\\n /**\\n * @dev Deposit the given asset to platform\\n * @param _asset asset address\\n * @param _amount Amount to deposit\\n */\\n function deposit(address _asset, uint256 _amount) external;\\n\\n /**\\n * @dev Deposit the entire balance of all supported assets in the Strategy\\n * to the platform\\n */\\n function depositAll() external;\\n\\n /**\\n * @dev Withdraw given asset from Lending platform\\n */\\n function withdraw(\\n address _recipient,\\n address _asset,\\n uint256 _amount\\n ) external;\\n\\n /**\\n * @dev Liquidate all assets in strategy and return them to Vault.\\n */\\n function withdrawAll() external;\\n\\n /**\\n * @dev Returns the current balance of the given asset.\\n */\\n function checkBalance(address _asset)\\n external\\n view\\n returns (uint256 balance);\\n\\n /**\\n * @dev Returns bool indicating whether strategy supports asset.\\n */\\n function supportsAsset(address _asset) external view returns (bool);\\n\\n /**\\n * @dev Collect reward tokens from the Strategy.\\n */\\n function collectRewardTokens() external;\\n\\n /**\\n * @dev The address array of the reward tokens for the Strategy.\\n */\\n function getRewardTokenAddresses() external view returns (address[] memory);\\n\\n function harvesterAddress() external view returns (address);\\n\\n function transferToken(address token, uint256 amount) external;\\n\\n function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\\n external;\\n}\\n\",\"keccak256\":\"0x79ca47defb3b5a56bba13f14c440838152fd1c1aa640476154516a16da4da8ba\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/IVault.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { VaultStorage } from \\\"../vault/VaultStorage.sol\\\";\\n\\ninterface IVault {\\n // slither-disable-start constable-states\\n\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event DefaultStrategyUpdated(address _strategy);\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\\n event DripDurationChanged(uint256 dripDuration);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\\n\\n // Governable.sol\\n function transferGovernance(address _newGovernor) external;\\n\\n function claimGovernance() external;\\n\\n function governor() external view returns (address);\\n\\n // VaultAdmin.sol\\n function setVaultBuffer(uint256 _vaultBuffer) external;\\n\\n function vaultBuffer() external view returns (uint256);\\n\\n function setAutoAllocateThreshold(uint256 _threshold) external;\\n\\n function autoAllocateThreshold() external view returns (uint256);\\n\\n function setStrategistAddr(address _address) external;\\n\\n function strategistAddr() external view returns (address);\\n\\n function setOperatorAddr(address _operator) external;\\n\\n function operatorAddr() external view returns (address);\\n\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\\n\\n function maxSupplyDiff() external view returns (uint256);\\n\\n function setTrusteeAddress(address _address) external;\\n\\n function trusteeAddress() external view returns (address);\\n\\n function setTrusteeFeeBps(uint256 _basis) external;\\n\\n function trusteeFeeBps() external view returns (uint256);\\n\\n function approveStrategy(address _addr) external;\\n\\n function removeStrategy(address _addr) external;\\n\\n function setDefaultStrategy(address _strategy) external;\\n\\n function defaultStrategy() external view returns (address);\\n\\n function pauseRebase() external;\\n\\n function unpauseRebase() external;\\n\\n function rebasePaused() external view returns (bool);\\n\\n function pauseCapital() external;\\n\\n function unpauseCapital() external;\\n\\n function capitalPaused() external view returns (bool);\\n\\n function transferToken(address _asset, uint256 _amount) external;\\n\\n function withdrawAllFromStrategy(address _strategyAddr) external;\\n\\n function withdrawAllFromStrategies() external;\\n\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n // VaultCore.sol\\n function mint(uint256 _amount) external;\\n\\n function mintForStrategy(uint256 _amount) external;\\n\\n function burnForStrategy(uint256 _amount) external;\\n\\n function allocate() external;\\n\\n function rebase() external;\\n\\n function totalValue() external view returns (uint256 value);\\n\\n function checkBalance(address _asset) external view returns (uint256);\\n\\n function getAssetCount() external view returns (uint256);\\n\\n function getAllAssets() external view returns (address[] memory);\\n\\n function getStrategyCount() external view returns (uint256);\\n\\n function getAllStrategies() external view returns (address[] memory);\\n\\n function strategies(address _addr)\\n external\\n view\\n returns (VaultStorage.Strategy memory);\\n\\n /// @notice Deprecated: use `asset()` instead.\\n function isSupportedAsset(address _asset) external view returns (bool);\\n\\n function asset() external view returns (address);\\n\\n function oToken() external view returns (address);\\n\\n function initialize(address) external;\\n\\n function addWithdrawalQueueLiquidity() external;\\n\\n function requestWithdrawal(uint256 _amount)\\n external\\n returns (uint256 requestId, uint256 queued);\\n\\n function claimWithdrawal(uint256 requestId)\\n external\\n returns (uint256 amount);\\n\\n function claimWithdrawals(uint256[] memory requestIds)\\n external\\n returns (uint256[] memory amounts, uint256 totalAmount);\\n\\n function withdrawalQueueMetadata()\\n external\\n view\\n returns (VaultStorage.WithdrawalQueueMetadata memory);\\n\\n function withdrawalRequests(uint256 requestId)\\n external\\n view\\n returns (VaultStorage.WithdrawalRequest memory);\\n\\n function addStrategyToMintWhitelist(address strategyAddr) external;\\n\\n function removeStrategyFromMintWhitelist(address strategyAddr) external;\\n\\n function isMintWhitelistedStrategy(address strategyAddr)\\n external\\n view\\n returns (bool);\\n\\n function withdrawalClaimDelay() external view returns (uint256);\\n\\n function setWithdrawalClaimDelay(uint256 newDelay) external;\\n\\n function lastRebase() external view returns (uint64);\\n\\n function dripDuration() external view returns (uint64);\\n\\n function setDripDuration(uint256 _dripDuration) external;\\n\\n function rebasePerSecondMax() external view returns (uint64);\\n\\n function setRebaseRateMax(uint256 yearlyApr) external;\\n\\n function rebasePerSecondTarget() external view returns (uint64);\\n\\n function previewYield() external view returns (uint256 yield);\\n\\n // slither-disable-end constable-states\\n}\\n\",\"keccak256\":\"0x573ee781634813c659362ca2950f439711c2d2b1f79b285d22ecd14c8c32fb9d\",\"license\":\"BUSL-1.1\"},\"contracts/token/OUSD.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OUSD Token Contract\\n * @dev ERC20 compatible contract for OUSD\\n * @dev Implements an elastic supply\\n * @author Origin Protocol Inc\\n */\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\ncontract OUSD is Governable {\\n using SafeCast for int256;\\n using SafeCast for uint256;\\n\\n /// @dev Event triggered when the supply changes\\n /// @param totalSupply Updated token total supply\\n /// @param rebasingCredits Updated token rebasing credits\\n /// @param rebasingCreditsPerToken Updated token rebasing credits per token\\n event TotalSupplyUpdatedHighres(\\n uint256 totalSupply,\\n uint256 rebasingCredits,\\n uint256 rebasingCreditsPerToken\\n );\\n /// @dev Event triggered when an account opts in for rebasing\\n /// @param account Address of the account\\n event AccountRebasingEnabled(address account);\\n /// @dev Event triggered when an account opts out of rebasing\\n /// @param account Address of the account\\n event AccountRebasingDisabled(address account);\\n /// @dev Emitted when `value` tokens are moved from one account `from` to\\n /// another `to`.\\n /// @param from Address of the account tokens are moved from\\n /// @param to Address of the account tokens are moved to\\n /// @param value Amount of tokens transferred\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n /// @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n /// a call to {approve}. `value` is the new allowance.\\n /// @param owner Address of the owner approving allowance\\n /// @param spender Address of the spender allowance is granted to\\n /// @param value Amount of tokens spender can transfer\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 value\\n );\\n /// @dev Yield resulting from {changeSupply} that a `source` account would\\n /// receive is directed to `target` account.\\n /// @param source Address of the source forwarding the yield\\n /// @param target Address of the target receiving the yield\\n event YieldDelegated(address source, address target);\\n /// @dev Yield delegation from `source` account to the `target` account is\\n /// suspended.\\n /// @param source Address of the source suspending yield forwarding\\n /// @param target Address of the target no longer receiving yield from `source`\\n /// account\\n event YieldUndelegated(address source, address target);\\n\\n enum RebaseOptions {\\n NotSet,\\n StdNonRebasing,\\n StdRebasing,\\n YieldDelegationSource,\\n YieldDelegationTarget\\n }\\n\\n uint256[154] private _gap; // Slots to align with deployed contract\\n uint256 private constant MAX_SUPPLY = type(uint128).max;\\n /// @dev The amount of tokens in existence\\n uint256 public totalSupply;\\n mapping(address => mapping(address => uint256)) private allowances;\\n /// @dev The vault with privileges to execute {mint}, {burn}\\n /// and {changeSupply}\\n address public vaultAddress;\\n mapping(address => uint256) internal creditBalances;\\n // the 2 storage variables below need trailing underscores to not name collide with public functions\\n uint256 private rebasingCredits_; // Sum of all rebasing credits (creditBalances for rebasing accounts)\\n uint256 private rebasingCreditsPerToken_;\\n /// @dev The amount of tokens that are not rebasing - receiving yield\\n uint256 public nonRebasingSupply;\\n mapping(address => uint256) internal alternativeCreditsPerToken;\\n /// @dev A map of all addresses and their respective RebaseOptions\\n mapping(address => RebaseOptions) public rebaseState;\\n mapping(address => uint256) private __deprecated_isUpgraded;\\n /// @dev A map of addresses that have yields forwarded to. This is an\\n /// inverse mapping of {yieldFrom}\\n /// Key Account forwarding yield\\n /// Value Account receiving yield\\n mapping(address => address) public yieldTo;\\n /// @dev A map of addresses that are receiving the yield. This is an\\n /// inverse mapping of {yieldTo}\\n /// Key Account receiving yield\\n /// Value Account forwarding yield\\n mapping(address => address) public yieldFrom;\\n\\n uint256 private constant RESOLUTION_INCREASE = 1e9;\\n uint256[34] private __gap; // including below gap totals up to 200\\n\\n /// @dev Verifies that the caller is the Governor or Strategist.\\n modifier onlyGovernorOrStrategist() {\\n require(\\n isGovernor() || msg.sender == IVault(vaultAddress).strategistAddr(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n /// @dev Initializes the contract and sets necessary variables.\\n /// @param _vaultAddress Address of the vault contract\\n /// @param _initialCreditsPerToken The starting rebasing credits per token.\\n function initialize(address _vaultAddress, uint256 _initialCreditsPerToken)\\n external\\n onlyGovernor\\n {\\n require(_vaultAddress != address(0), \\\"Zero vault address\\\");\\n require(vaultAddress == address(0), \\\"Already initialized\\\");\\n\\n rebasingCreditsPerToken_ = _initialCreditsPerToken;\\n vaultAddress = _vaultAddress;\\n }\\n\\n /// @dev Returns the symbol of the token, a shorter version\\n /// of the name.\\n function symbol() external pure virtual returns (string memory) {\\n return \\\"OUSD\\\";\\n }\\n\\n /// @dev Returns the name of the token.\\n function name() external pure virtual returns (string memory) {\\n return \\\"Origin Dollar\\\";\\n }\\n\\n /// @dev Returns the number of decimals used to get its user representation.\\n function decimals() external pure virtual returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev Verifies that the caller is the Vault contract\\n */\\n modifier onlyVault() {\\n require(vaultAddress == msg.sender, \\\"Caller is not the Vault\\\");\\n _;\\n }\\n\\n /**\\n * @return High resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerTokenHighres() external view returns (uint256) {\\n return rebasingCreditsPerToken_;\\n }\\n\\n /**\\n * @return Low resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerToken() external view returns (uint256) {\\n return rebasingCreditsPerToken_ / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return High resolution total number of rebasing credits\\n */\\n function rebasingCreditsHighres() external view returns (uint256) {\\n return rebasingCredits_;\\n }\\n\\n /**\\n * @return Low resolution total number of rebasing credits\\n */\\n function rebasingCredits() external view returns (uint256) {\\n return rebasingCredits_ / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @notice Gets the balance of the specified address.\\n * @param _account Address to query the balance of.\\n * @return A uint256 representing the amount of base units owned by the\\n * specified address.\\n */\\n function balanceOf(address _account) public view returns (uint256) {\\n RebaseOptions state = rebaseState[_account];\\n if (state == RebaseOptions.YieldDelegationSource) {\\n // Saves a slot read when transferring to or from a yield delegating source\\n // since we know creditBalances equals the balance.\\n return creditBalances[_account];\\n }\\n uint256 baseBalance = (creditBalances[_account] * 1e18) /\\n _creditsPerToken(_account);\\n if (state == RebaseOptions.YieldDelegationTarget) {\\n // creditBalances of yieldFrom accounts equals token balances\\n return baseBalance - creditBalances[yieldFrom[_account]];\\n }\\n return baseBalance;\\n }\\n\\n /**\\n * @notice Gets the credits balance of the specified address.\\n * @dev Backwards compatible with old low res credits per token.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256) Credit balance and credits per token of the\\n * address\\n */\\n function creditsBalanceOf(address _account)\\n external\\n view\\n returns (uint256, uint256)\\n {\\n uint256 cpt = _creditsPerToken(_account);\\n if (cpt == 1e27) {\\n // For a period before the resolution upgrade, we created all new\\n // contract accounts at high resolution. Since they are not changing\\n // as a result of this upgrade, we will return their true values\\n return (creditBalances[_account], cpt);\\n } else {\\n return (\\n creditBalances[_account] / RESOLUTION_INCREASE,\\n cpt / RESOLUTION_INCREASE\\n );\\n }\\n }\\n\\n /**\\n * @notice Gets the credits balance of the specified address.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\\n * address, and isUpgraded\\n */\\n function creditsBalanceOfHighres(address _account)\\n external\\n view\\n returns (\\n uint256,\\n uint256,\\n bool\\n )\\n {\\n return (\\n creditBalances[_account],\\n _creditsPerToken(_account),\\n true // all accounts have their resolution \\\"upgraded\\\"\\n );\\n }\\n\\n // Backwards compatible view\\n function nonRebasingCreditsPerToken(address _account)\\n external\\n view\\n returns (uint256)\\n {\\n return alternativeCreditsPerToken[_account];\\n }\\n\\n /**\\n * @notice Transfer tokens to a specified address.\\n * @param _to the address to transfer to.\\n * @param _value the amount to be transferred.\\n * @return true on success.\\n */\\n function transfer(address _to, uint256 _value) external returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n\\n _executeTransfer(msg.sender, _to, _value);\\n\\n emit Transfer(msg.sender, _to, _value);\\n return true;\\n }\\n\\n /**\\n * @notice Transfer tokens from one address to another.\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value The amount of tokens to be transferred.\\n * @return true on success.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n uint256 userAllowance = allowances[_from][msg.sender];\\n require(_value <= userAllowance, \\\"Allowance exceeded\\\");\\n\\n unchecked {\\n allowances[_from][msg.sender] = userAllowance - _value;\\n }\\n\\n _executeTransfer(_from, _to, _value);\\n\\n emit Transfer(_from, _to, _value);\\n return true;\\n }\\n\\n function _executeTransfer(\\n address _from,\\n address _to,\\n uint256 _value\\n ) internal {\\n (\\n int256 fromRebasingCreditsDiff,\\n int256 fromNonRebasingSupplyDiff\\n ) = _adjustAccount(_from, -_value.toInt256());\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_to, _value.toInt256());\\n\\n _adjustGlobals(\\n fromRebasingCreditsDiff + toRebasingCreditsDiff,\\n fromNonRebasingSupplyDiff + toNonRebasingSupplyDiff\\n );\\n }\\n\\n function _adjustAccount(address _account, int256 _balanceChange)\\n internal\\n returns (int256 rebasingCreditsDiff, int256 nonRebasingSupplyDiff)\\n {\\n RebaseOptions state = rebaseState[_account];\\n int256 currentBalance = balanceOf(_account).toInt256();\\n if (currentBalance + _balanceChange < 0) {\\n revert(\\\"Transfer amount exceeds balance\\\");\\n }\\n uint256 newBalance = (currentBalance + _balanceChange).toUint256();\\n\\n if (state == RebaseOptions.YieldDelegationSource) {\\n address target = yieldTo[_account];\\n uint256 targetOldBalance = balanceOf(target);\\n uint256 targetNewCredits = _balanceToRebasingCredits(\\n targetOldBalance + newBalance\\n );\\n rebasingCreditsDiff =\\n targetNewCredits.toInt256() -\\n creditBalances[target].toInt256();\\n\\n creditBalances[_account] = newBalance;\\n creditBalances[target] = targetNewCredits;\\n } else if (state == RebaseOptions.YieldDelegationTarget) {\\n uint256 newCredits = _balanceToRebasingCredits(\\n newBalance + creditBalances[yieldFrom[_account]]\\n );\\n rebasingCreditsDiff =\\n newCredits.toInt256() -\\n creditBalances[_account].toInt256();\\n creditBalances[_account] = newCredits;\\n } else {\\n _autoMigrate(_account);\\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\\n _account\\n ];\\n if (alternativeCreditsPerTokenMem > 0) {\\n nonRebasingSupplyDiff = _balanceChange;\\n if (alternativeCreditsPerTokenMem != 1e18) {\\n alternativeCreditsPerToken[_account] = 1e18;\\n }\\n creditBalances[_account] = newBalance;\\n } else {\\n uint256 newCredits = _balanceToRebasingCredits(newBalance);\\n rebasingCreditsDiff =\\n newCredits.toInt256() -\\n creditBalances[_account].toInt256();\\n creditBalances[_account] = newCredits;\\n }\\n }\\n }\\n\\n function _adjustGlobals(\\n int256 _rebasingCreditsDiff,\\n int256 _nonRebasingSupplyDiff\\n ) internal {\\n if (_rebasingCreditsDiff != 0) {\\n rebasingCredits_ = (rebasingCredits_.toInt256() +\\n _rebasingCreditsDiff).toUint256();\\n }\\n if (_nonRebasingSupplyDiff != 0) {\\n nonRebasingSupply = (nonRebasingSupply.toInt256() +\\n _nonRebasingSupplyDiff).toUint256();\\n }\\n }\\n\\n /**\\n * @notice Function to check the amount of tokens that _owner has allowed\\n * to `_spender`.\\n * @param _owner The address which owns the funds.\\n * @param _spender The address which will spend the funds.\\n * @return The number of tokens still available for the _spender.\\n */\\n function allowance(address _owner, address _spender)\\n external\\n view\\n returns (uint256)\\n {\\n return allowances[_owner][_spender];\\n }\\n\\n /**\\n * @notice Approve the passed address to spend the specified amount of\\n * tokens on behalf of msg.sender.\\n * @param _spender The address which will spend the funds.\\n * @param _value The amount of tokens to be spent.\\n * @return true on success.\\n */\\n function approve(address _spender, uint256 _value) external returns (bool) {\\n allowances[msg.sender][_spender] = _value;\\n emit Approval(msg.sender, _spender, _value);\\n return true;\\n }\\n\\n /**\\n * @notice Creates `_amount` tokens and assigns them to `_account`,\\n * increasing the total supply.\\n */\\n function mint(address _account, uint256 _amount) external onlyVault {\\n require(_account != address(0), \\\"Mint to the zero address\\\");\\n\\n // Account\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_account, _amount.toInt256());\\n // Globals\\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\\n totalSupply = totalSupply + _amount;\\n\\n require(totalSupply < MAX_SUPPLY, \\\"Max supply\\\");\\n emit Transfer(address(0), _account, _amount);\\n }\\n\\n /**\\n * @notice Destroys `_amount` tokens from `_account`,\\n * reducing the total supply.\\n */\\n function burn(address _account, uint256 _amount) external onlyVault {\\n require(_account != address(0), \\\"Burn from the zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n\\n // Account\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_account, -_amount.toInt256());\\n // Globals\\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\\n totalSupply = totalSupply - _amount;\\n\\n emit Transfer(_account, address(0), _amount);\\n }\\n\\n /**\\n * @dev Get the credits per token for an account. Returns a fixed amount\\n * if the account is non-rebasing.\\n * @param _account Address of the account.\\n */\\n function _creditsPerToken(address _account)\\n internal\\n view\\n returns (uint256)\\n {\\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\\n _account\\n ];\\n if (alternativeCreditsPerTokenMem != 0) {\\n return alternativeCreditsPerTokenMem;\\n } else {\\n return rebasingCreditsPerToken_;\\n }\\n }\\n\\n /**\\n * @dev Auto migrate contracts to be non rebasing,\\n * unless they have opted into yield.\\n * @param _account Address of the account.\\n */\\n function _autoMigrate(address _account) internal {\\n uint256 codeLen = _account.code.length;\\n bool isEOA = (codeLen == 0) ||\\n (codeLen == 23 && bytes3(_account.code) == 0xef0100);\\n // In previous code versions, contracts would not have had their\\n // rebaseState[_account] set to RebaseOptions.NonRebasing when migrated\\n // therefore we check the actual accounting used on the account as well.\\n if (\\n (!isEOA) &&\\n rebaseState[_account] == RebaseOptions.NotSet &&\\n alternativeCreditsPerToken[_account] == 0\\n ) {\\n _rebaseOptOut(_account);\\n }\\n }\\n\\n /**\\n * @dev Calculates credits from contract's global rebasingCreditsPerToken_, and\\n * also balance that corresponds to those credits. The latter is important\\n * when adjusting the contract's global nonRebasingSupply to circumvent any\\n * possible rounding errors.\\n *\\n * @param _balance Balance of the account.\\n */\\n function _balanceToRebasingCredits(uint256 _balance)\\n internal\\n view\\n returns (uint256 rebasingCredits)\\n {\\n // Rounds up, because we need to ensure that accounts always have\\n // at least the balance that they should have.\\n // Note this should always be used on an absolute account value,\\n // not on a possibly negative diff, because then the rounding would be wrong.\\n return ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18;\\n }\\n\\n /**\\n * @notice The calling account will start receiving yield after a successful call.\\n * @param _account Address of the account.\\n */\\n function governanceRebaseOptIn(address _account) external onlyGovernor {\\n require(_account != address(0), \\\"Zero address not allowed\\\");\\n _rebaseOptIn(_account);\\n }\\n\\n /**\\n * @notice The calling account will start receiving yield after a successful call.\\n */\\n function rebaseOptIn() external {\\n _rebaseOptIn(msg.sender);\\n }\\n\\n function _rebaseOptIn(address _account) internal {\\n uint256 balance = balanceOf(_account);\\n\\n // prettier-ignore\\n require(\\n alternativeCreditsPerToken[_account] > 0 ||\\n // Accounts may explicitly `rebaseOptIn` regardless of\\n // accounting if they have a 0 balance.\\n creditBalances[_account] == 0\\n ,\\n \\\"Account must be non-rebasing\\\"\\n );\\n RebaseOptions state = rebaseState[_account];\\n // prettier-ignore\\n require(\\n state == RebaseOptions.StdNonRebasing ||\\n state == RebaseOptions.NotSet,\\n \\\"Only standard non-rebasing accounts can opt in\\\"\\n );\\n\\n uint256 newCredits = _balanceToRebasingCredits(balance);\\n\\n // Account\\n rebaseState[_account] = RebaseOptions.StdRebasing;\\n alternativeCreditsPerToken[_account] = 0;\\n creditBalances[_account] = newCredits;\\n // Globals\\n _adjustGlobals(newCredits.toInt256(), -balance.toInt256());\\n\\n emit AccountRebasingEnabled(_account);\\n }\\n\\n /**\\n * @notice The calling account will no longer receive yield\\n */\\n function rebaseOptOut() external {\\n _rebaseOptOut(msg.sender);\\n }\\n\\n function _rebaseOptOut(address _account) internal {\\n require(\\n alternativeCreditsPerToken[_account] == 0,\\n \\\"Account must be rebasing\\\"\\n );\\n RebaseOptions state = rebaseState[_account];\\n require(\\n state == RebaseOptions.StdRebasing || state == RebaseOptions.NotSet,\\n \\\"Only standard rebasing accounts can opt out\\\"\\n );\\n\\n uint256 oldCredits = creditBalances[_account];\\n uint256 balance = balanceOf(_account);\\n\\n // Account\\n rebaseState[_account] = RebaseOptions.StdNonRebasing;\\n alternativeCreditsPerToken[_account] = 1e18;\\n creditBalances[_account] = balance;\\n // Globals\\n _adjustGlobals(-oldCredits.toInt256(), balance.toInt256());\\n\\n emit AccountRebasingDisabled(_account);\\n }\\n\\n /**\\n * @notice Distribute yield to users. This changes the exchange rate\\n * between \\\"credits\\\" and OUSD tokens to change rebasing user's balances.\\n * @param _newTotalSupply New total supply of OUSD.\\n */\\n function changeSupply(uint256 _newTotalSupply) external onlyVault {\\n require(totalSupply > 0, \\\"Cannot increase 0 supply\\\");\\n\\n if (totalSupply == _newTotalSupply) {\\n emit TotalSupplyUpdatedHighres(\\n totalSupply,\\n rebasingCredits_,\\n rebasingCreditsPerToken_\\n );\\n return;\\n }\\n\\n totalSupply = _newTotalSupply > MAX_SUPPLY\\n ? MAX_SUPPLY\\n : _newTotalSupply;\\n\\n uint256 rebasingSupply = totalSupply - nonRebasingSupply;\\n // round up in the favour of the protocol\\n rebasingCreditsPerToken_ =\\n (rebasingCredits_ * 1e18 + rebasingSupply - 1) /\\n rebasingSupply;\\n\\n require(rebasingCreditsPerToken_ > 0, \\\"Invalid change in supply\\\");\\n\\n emit TotalSupplyUpdatedHighres(\\n totalSupply,\\n rebasingCredits_,\\n rebasingCreditsPerToken_\\n );\\n }\\n\\n /*\\n * @notice Send the yield from one account to another account.\\n * Each account keeps its own balances.\\n */\\n function delegateYield(address _from, address _to)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_from != address(0), \\\"Zero from address not allowed\\\");\\n require(_to != address(0), \\\"Zero to address not allowed\\\");\\n\\n require(_from != _to, \\\"Cannot delegate to self\\\");\\n require(\\n yieldFrom[_to] == address(0) &&\\n yieldTo[_to] == address(0) &&\\n yieldFrom[_from] == address(0) &&\\n yieldTo[_from] == address(0),\\n \\\"Blocked by existing yield delegation\\\"\\n );\\n RebaseOptions stateFrom = rebaseState[_from];\\n RebaseOptions stateTo = rebaseState[_to];\\n\\n require(\\n stateFrom == RebaseOptions.NotSet ||\\n stateFrom == RebaseOptions.StdNonRebasing ||\\n stateFrom == RebaseOptions.StdRebasing,\\n \\\"Invalid rebaseState from\\\"\\n );\\n\\n require(\\n stateTo == RebaseOptions.NotSet ||\\n stateTo == RebaseOptions.StdNonRebasing ||\\n stateTo == RebaseOptions.StdRebasing,\\n \\\"Invalid rebaseState to\\\"\\n );\\n\\n if (alternativeCreditsPerToken[_from] == 0) {\\n _rebaseOptOut(_from);\\n }\\n if (alternativeCreditsPerToken[_to] > 0) {\\n _rebaseOptIn(_to);\\n }\\n\\n uint256 fromBalance = balanceOf(_from);\\n uint256 toBalance = balanceOf(_to);\\n uint256 oldToCredits = creditBalances[_to];\\n uint256 newToCredits = _balanceToRebasingCredits(\\n fromBalance + toBalance\\n );\\n\\n // Set up the bidirectional links\\n yieldTo[_from] = _to;\\n yieldFrom[_to] = _from;\\n\\n // Local\\n rebaseState[_from] = RebaseOptions.YieldDelegationSource;\\n alternativeCreditsPerToken[_from] = 1e18;\\n creditBalances[_from] = fromBalance;\\n rebaseState[_to] = RebaseOptions.YieldDelegationTarget;\\n creditBalances[_to] = newToCredits;\\n\\n // Global\\n int256 creditsChange = newToCredits.toInt256() -\\n oldToCredits.toInt256();\\n _adjustGlobals(creditsChange, -(fromBalance).toInt256());\\n emit YieldDelegated(_from, _to);\\n }\\n\\n /*\\n * @notice Stop sending the yield from one account to another account.\\n */\\n function undelegateYield(address _from) external onlyGovernorOrStrategist {\\n // Require a delegation, which will also ensure a valid delegation\\n require(yieldTo[_from] != address(0), \\\"Zero address not allowed\\\");\\n\\n address to = yieldTo[_from];\\n uint256 fromBalance = balanceOf(_from);\\n uint256 toBalance = balanceOf(to);\\n uint256 oldToCredits = creditBalances[to];\\n uint256 newToCredits = _balanceToRebasingCredits(toBalance);\\n\\n // Remove the bidirectional links\\n yieldFrom[to] = address(0);\\n yieldTo[_from] = address(0);\\n\\n // Local\\n rebaseState[_from] = RebaseOptions.StdNonRebasing;\\n // alternativeCreditsPerToken[from] already 1e18 from `delegateYield()`\\n creditBalances[_from] = fromBalance;\\n rebaseState[to] = RebaseOptions.StdRebasing;\\n // alternativeCreditsPerToken[to] already 0 from `delegateYield()`\\n creditBalances[to] = newToCredits;\\n\\n // Global\\n int256 creditsChange = newToCredits.toInt256() -\\n oldToCredits.toInt256();\\n _adjustGlobals(creditsChange, fromBalance.toInt256());\\n emit YieldUndelegated(_from, to);\\n }\\n}\\n\",\"keccak256\":\"0x73439bef6569f5adf6f5ce2cb54a5f0d3109d4819457532236e172a7091980a9\",\"license\":\"BUSL-1.1\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { IBasicToken } from \\\"../interfaces/IBasicToken.sol\\\";\\n\\nlibrary Helpers {\\n /**\\n * @notice Fetch the `symbol()` from an ERC20 token\\n * @dev Grabs the `symbol()` from a contract\\n * @param _token Address of the ERC20 token\\n * @return string Symbol of the ERC20 token\\n */\\n function getSymbol(address _token) internal view returns (string memory) {\\n string memory symbol = IBasicToken(_token).symbol();\\n return symbol;\\n }\\n\\n /**\\n * @notice Fetch the `decimals()` from an ERC20 token\\n * @dev Grabs the `decimals()` from a contract and fails if\\n * the decimal value does not live within a certain range\\n * @param _token Address of the ERC20 token\\n * @return uint256 Decimals of the ERC20 token\\n */\\n function getDecimals(address _token) internal view returns (uint256) {\\n uint256 decimals = IBasicToken(_token).decimals();\\n require(\\n decimals >= 4 && decimals <= 18,\\n \\\"Token must have sufficient decimal places\\\"\\n );\\n\\n return decimals;\\n }\\n}\\n\",\"keccak256\":\"0x4366f8d90b34c1eef8bbaaf369b1e5cd59f04027bb3c111f208eaee65bbc0346\",\"license\":\"BUSL-1.1\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base contract any contracts that need to initialize state after deployment.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0x50d39ebf38a3d3111f2b77a6c75ece1d4ae731552fec4697ab16fcf6c0d4d5e8\",\"license\":\"BUSL-1.1\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n // slither-disable-next-line divide-before-multiply\\n x = x.div(10**(from - to));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e36 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0x71d6ed0053a1e5ef018d27c3b6d024f336d8157ab6f6859e400b3243a50a71b7\",\"license\":\"BUSL-1.1\"},\"contracts/vault/OETHVault.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { VaultAdmin } from \\\"./VaultAdmin.sol\\\";\\n\\n/**\\n * @title OETH VaultAdmin Contract\\n * @author Origin Protocol Inc\\n */\\ncontract OETHVault is VaultAdmin {\\n constructor(address _weth) VaultAdmin(_weth) {}\\n}\\n\",\"keccak256\":\"0x4941cf6a70075b74b021ec51482e11fdcae242db6e83e0d43cd5049011e45fbb\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultAdmin contract\\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\nimport \\\"./VaultCore.sol\\\";\\n\\nabstract contract VaultAdmin is VaultCore {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n using SafeCast for uint256;\\n\\n /**\\n * @dev Verifies that the caller is the Governor or Strategist.\\n */\\n modifier onlyGovernorOrStrategist() {\\n require(\\n msg.sender == strategistAddr || isGovernor(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n constructor(address _asset) VaultCore(_asset) {}\\n\\n /***************************************\\n Configuration\\n ****************************************/\\n /**\\n * @notice Set a buffer of asset to keep in the Vault to handle most\\n * redemptions without needing to spend gas unwinding asset from a Strategy.\\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\\n */\\n function setVaultBuffer(uint256 _vaultBuffer)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_vaultBuffer <= 1e18, \\\"Invalid value\\\");\\n vaultBuffer = _vaultBuffer;\\n emit VaultBufferUpdated(_vaultBuffer);\\n }\\n\\n /**\\n * @notice Sets the minimum amount of OTokens in a mint to trigger an\\n * automatic allocation of funds afterwords.\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setAutoAllocateThreshold(uint256 _threshold)\\n external\\n onlyGovernor\\n {\\n autoAllocateThreshold = _threshold;\\n emit AllocateThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set address of Strategist\\n * @param _address Address of Strategist\\n */\\n function setStrategistAddr(address _address) external onlyGovernor {\\n strategistAddr = _address;\\n emit StrategistUpdated(_address);\\n }\\n\\n /**\\n * @notice Set the address authorized to call `rebase()`.\\n * @param _operator New operator address. May be set to the zero address\\n * to disable operator-initiated rebases.\\n */\\n function setOperatorAddr(address _operator) external onlyGovernor {\\n operatorAddr = _operator;\\n emit OperatorUpdated(_operator);\\n }\\n\\n /**\\n * @notice Set the default Strategy for asset, i.e. the one which\\n * the asset will be automatically allocated to and withdrawn from\\n * @param _strategy Address of the Strategy\\n */\\n function setDefaultStrategy(address _strategy)\\n external\\n onlyGovernorOrStrategist\\n {\\n emit DefaultStrategyUpdated(_strategy);\\n // If its a zero address being passed for the strategy we are removing\\n // the default strategy\\n if (_strategy != address(0)) {\\n // Make sure the strategy meets some criteria\\n require(strategies[_strategy].isSupported, \\\"Strategy not approved\\\");\\n require(\\n IStrategy(_strategy).supportsAsset(asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n }\\n defaultStrategy = _strategy;\\n }\\n\\n /**\\n * @notice Changes the async withdrawal claim period for OETH & superOETHb\\n * @param _delay Delay period (should be between 10 mins to 7 days).\\n * Set to 0 to disable async withdrawals\\n */\\n function setWithdrawalClaimDelay(uint256 _delay) external onlyGovernor {\\n require(\\n _delay == 0 || (_delay >= 10 minutes && _delay <= 15 days),\\n \\\"Invalid claim delay period\\\"\\n );\\n withdrawalClaimDelay = _delay;\\n emit WithdrawalClaimDelayUpdated(_delay);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Set a yield streaming max rate. This spreads yield over\\n * time if it is above the max rate. This is a per rebase APR which\\n * due to compounding differs from the yearly APR. Governance should\\n * consider this fact when picking a desired APR\\n * @param apr in 1e18 notation. 3 * 1e18 = 3% APR\\n */\\n function setRebaseRateMax(uint256 apr) external onlyGovernorOrStrategist {\\n // The old yield will be at the old rate\\n _rebase();\\n // Change the rate\\n uint256 newPerSecond = apr / 100 / 365 days;\\n require(newPerSecond <= MAX_REBASE_PER_SECOND, \\\"Rate too high\\\");\\n rebasePerSecondMax = newPerSecond.toUint64();\\n emit RebasePerSecondMaxChanged(newPerSecond);\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Set the drip duration period\\n * @param _dripDuration Time in seconds to target a constant yield rate\\n */\\n function setDripDuration(uint256 _dripDuration)\\n external\\n onlyGovernorOrStrategist\\n {\\n // The old yield will be at the old rate\\n _rebase();\\n dripDuration = _dripDuration.toUint64();\\n emit DripDurationChanged(_dripDuration);\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /***************************************\\n Strategy Config\\n ****************************************/\\n\\n /**\\n * @notice Add a strategy to the Vault.\\n * @param _addr Address of the strategy to add\\n */\\n function approveStrategy(address _addr) external onlyGovernor {\\n require(!strategies[_addr].isSupported, \\\"Strategy already approved\\\");\\n require(\\n IStrategy(_addr).supportsAsset(asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\\n allStrategies.push(_addr);\\n emit StrategyApproved(_addr);\\n }\\n\\n /**\\n * @notice Remove a strategy from the Vault.\\n * @param _addr Address of the strategy to remove\\n */\\n\\n function removeStrategy(address _addr) external onlyGovernor {\\n require(strategies[_addr].isSupported, \\\"Strategy not approved\\\");\\n require(defaultStrategy != _addr, \\\"Strategy is default for asset\\\");\\n\\n // Initialize strategyIndex with out of bounds result so function will\\n // revert if no valid index found\\n uint256 stratCount = allStrategies.length;\\n uint256 strategyIndex = stratCount;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n if (allStrategies[i] == _addr) {\\n strategyIndex = i;\\n break;\\n }\\n }\\n\\n if (strategyIndex < stratCount) {\\n allStrategies[strategyIndex] = allStrategies[stratCount - 1];\\n allStrategies.pop();\\n\\n // Withdraw all assets BEFORE marking as unsupported so that AMO\\n // strategies can call burnForStrategy/mintForStrategy during withdrawAll\\n IStrategy strategy = IStrategy(_addr);\\n // slither-disable-next-line reentrancy-no-eth\\n strategy.withdrawAll();\\n\\n // Mark the strategy as not supported\\n strategies[_addr].isSupported = false;\\n isMintWhitelistedStrategy[_addr] = false;\\n\\n // 1e13 for 18 decimals. And 1e1(10) for 6 decimals\\n uint256 maxDustBalance = uint256(1e13).scaleBy(assetDecimals, 18);\\n\\n /*\\n * Some strategies are not able to withdraw all of their funds in a synchronous call.\\n * Prevent the possible accidental removal of such strategies before their funds are withdrawn.\\n */\\n require(\\n strategy.checkBalance(asset) < maxDustBalance,\\n \\\"Strategy has funds\\\"\\n );\\n emit StrategyRemoved(_addr);\\n }\\n }\\n\\n /**\\n * @notice Adds a strategy to the mint whitelist.\\n * Reverts if strategy isn't approved on Vault.\\n * @param strategyAddr Strategy address\\n */\\n function addStrategyToMintWhitelist(address strategyAddr)\\n external\\n onlyGovernor\\n {\\n require(strategies[strategyAddr].isSupported, \\\"Strategy not approved\\\");\\n\\n require(\\n !isMintWhitelistedStrategy[strategyAddr],\\n \\\"Already whitelisted\\\"\\n );\\n\\n isMintWhitelistedStrategy[strategyAddr] = true;\\n\\n emit StrategyAddedToMintWhitelist(strategyAddr);\\n }\\n\\n /**\\n * @notice Removes a strategy from the mint whitelist.\\n * @param strategyAddr Strategy address\\n */\\n function removeStrategyFromMintWhitelist(address strategyAddr)\\n external\\n onlyGovernor\\n {\\n // Intentionally skipping `strategies.isSupported` check since\\n // we may wanna remove an address even after removing the strategy\\n\\n require(isMintWhitelistedStrategy[strategyAddr], \\\"Not whitelisted\\\");\\n\\n isMintWhitelistedStrategy[strategyAddr] = false;\\n\\n emit StrategyRemovedFromMintWhitelist(strategyAddr);\\n }\\n\\n /***************************************\\n Strategies\\n ****************************************/\\n\\n /**\\n * @notice Deposit multiple asset from the vault into the strategy.\\n * @param _strategyToAddress Address of the Strategy to deposit asset into.\\n * @param _assets Array of asset address that will be deposited into the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to deposit.\\n */\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _depositToStrategy(_strategyToAddress, _assets, _amounts);\\n }\\n\\n function _depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyToAddress].isSupported,\\n \\\"Invalid to Strategy\\\"\\n );\\n require(\\n _assets.length == 1 && _amounts.length == 1 && _assets[0] == asset,\\n \\\"Only asset is supported\\\"\\n );\\n\\n // Check the there is enough asset to transfer once the backing\\n // asset reserved for the withdrawal queue is accounted for\\n require(\\n _amounts[0] <= _assetAvailable(),\\n \\\"Not enough assets available\\\"\\n );\\n\\n // Send required amount of funds to the strategy\\n IERC20(asset).safeTransfer(_strategyToAddress, _amounts[0]);\\n\\n // Deposit all the funds that have been sent to the strategy\\n IStrategy(_strategyToAddress).depositAll();\\n }\\n\\n /**\\n * @notice Withdraw multiple asset from the strategy to the vault.\\n * @param _strategyFromAddress Address of the Strategy to withdraw asset from.\\n * @param _assets Array of asset address that will be withdrawn from the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to withdraw.\\n */\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _withdrawFromStrategy(\\n address(this),\\n _strategyFromAddress,\\n _assets,\\n _amounts\\n );\\n }\\n\\n /**\\n * @param _recipient can either be a strategy or the Vault\\n */\\n function _withdrawFromStrategy(\\n address _recipient,\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyFromAddress].isSupported,\\n \\\"Invalid from Strategy\\\"\\n );\\n require(_assets.length == _amounts.length, \\\"Parameter length mismatch\\\");\\n\\n uint256 assetCount = _assets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n // Withdraw from Strategy to the recipient\\n IStrategy(_strategyFromAddress).withdraw(\\n _recipient,\\n _assets[i],\\n _amounts[i]\\n );\\n }\\n\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @notice Sets the maximum allowable difference between\\n * total supply and asset' value.\\n */\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\\n maxSupplyDiff = _maxSupplyDiff;\\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\\n }\\n\\n /**\\n * @notice Sets the trusteeAddress that can receive a portion of yield.\\n * Setting to the zero address disables this feature.\\n */\\n function setTrusteeAddress(address _address) external onlyGovernor {\\n trusteeAddress = _address;\\n emit TrusteeAddressChanged(_address);\\n }\\n\\n /**\\n * @notice Sets the TrusteeFeeBps to the percentage of yield that should be\\n * received in basis points.\\n */\\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\\n require(_basis <= 5000, \\\"basis cannot exceed 50%\\\");\\n trusteeFeeBps = _basis;\\n emit TrusteeFeeBpsChanged(_basis);\\n }\\n\\n /***************************************\\n Pause\\n ****************************************/\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent rebasing.\\n */\\n function pauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = true;\\n emit RebasePaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to allow rebasing.\\n */\\n function unpauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = false;\\n emit RebaseUnpaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent capital movement.\\n */\\n function pauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = true;\\n emit CapitalPaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to false to enable capital movement.\\n */\\n function unpauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = false;\\n emit CapitalUnpaused();\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\\n * contract, i.e. mistaken sends.\\n * @param _asset Address for the asset\\n * @param _amount Amount of the asset to transfer\\n */\\n function transferToken(address _asset, uint256 _amount)\\n external\\n onlyGovernor\\n {\\n require(asset != _asset, \\\"Only unsupported asset\\\");\\n IERC20(_asset).safeTransfer(governor(), _amount);\\n }\\n\\n /***************************************\\n Strategies Admin\\n ****************************************/\\n\\n /**\\n * @notice Withdraws all asset from the strategy and sends asset to the Vault.\\n * @param _strategyAddr Strategy address.\\n */\\n function withdrawAllFromStrategy(address _strategyAddr)\\n external\\n onlyGovernorOrStrategist\\n {\\n _withdrawAllFromStrategy(_strategyAddr);\\n }\\n\\n function _withdrawAllFromStrategy(address _strategyAddr) internal virtual {\\n require(\\n strategies[_strategyAddr].isSupported,\\n \\\"Strategy is not supported\\\"\\n );\\n IStrategy strategy = IStrategy(_strategyAddr);\\n strategy.withdrawAll();\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @notice Withdraws all asset from all the strategies and sends asset to the Vault.\\n */\\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\\n _withdrawAllFromStrategies();\\n }\\n\\n function _withdrawAllFromStrategies() internal virtual {\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy(allStrategies[i]).withdrawAll();\\n }\\n _addWithdrawalQueueLiquidity();\\n }\\n}\\n\",\"keccak256\":\"0xa9489d6c1c248bbf2d022d50dcc494f97f85b6d0fe40a13ab8516bd1ffda75ef\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultCore.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultCore contract\\n * @notice The Vault contract stores asset. On a deposit, OTokens will be minted\\n and sent to the depositor. On a withdrawal, OTokens will be burned and\\n asset will be sent to the withdrawer. The Vault accepts deposits of\\n interest from yield bearing strategies which will modify the supply\\n of OTokens.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\n\\nimport \\\"./VaultInitializer.sol\\\";\\n\\nabstract contract VaultCore is VaultInitializer {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n\\n /**\\n * @dev Verifies that the rebasing is not paused.\\n */\\n modifier whenNotRebasePaused() {\\n require(!rebasePaused, \\\"Rebasing paused\\\");\\n _;\\n }\\n\\n /**\\n * @dev Verifies that the deposits are not paused.\\n */\\n modifier whenNotCapitalPaused() {\\n require(!capitalPaused, \\\"Capital paused\\\");\\n _;\\n }\\n\\n constructor(address _asset) VaultInitializer(_asset) {}\\n\\n ////////////////////////////////////////////////////\\n /// MINT / BURN ///\\n ////////////////////////////////////////////////////\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @dev Deprecated: use `mint(uint256 _amount)` instead.\\n * @dev Deprecated: param _asset Address of the asset being deposited\\n * @param _amount Amount of the asset being deposited\\n * @dev Deprecated: param _minimumOusdAmount Minimum OTokens to mint\\n */\\n function mint(\\n address,\\n uint256 _amount,\\n uint256\\n ) external whenNotCapitalPaused nonReentrant {\\n _mint(_amount);\\n }\\n\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @param _amount Amount of the asset being deposited\\n */\\n function mint(uint256 _amount) external whenNotCapitalPaused nonReentrant {\\n _mint(_amount);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @dev Deposit a supported asset and mint OTokens.\\n * @param _amount Amount of the asset being deposited\\n */\\n function _mint(uint256 _amount) internal virtual {\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n\\n // Scale amount to 18 decimals\\n uint256 scaledAmount = _amount.scaleBy(18, assetDecimals);\\n\\n emit Mint(msg.sender, scaledAmount);\\n\\n // Mint oTokens\\n oToken.mint(msg.sender, scaledAmount);\\n\\n IERC20(asset).safeTransferFrom(msg.sender, address(this), _amount);\\n\\n // Give priority to the withdrawal queue for the new asset liquidity\\n _addWithdrawalQueueLiquidity();\\n\\n // Auto-allocate if necessary\\n if (scaledAmount >= autoAllocateThreshold) {\\n _allocate();\\n }\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /**\\n * @notice Mint OTokens for an allowed Strategy\\n * @param _amount Amount of OToken to mint\\n *\\n * Notice: can't use `nonReentrant` modifier since the `mint` function can\\n * call `allocate`, and that can trigger an AMO strategy to call this function\\n * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function mintForStrategy(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n {\\n require(\\n strategies[msg.sender].isSupported == true,\\n \\\"Unsupported strategy\\\"\\n );\\n require(\\n isMintWhitelistedStrategy[msg.sender] == true,\\n \\\"Not whitelisted strategy\\\"\\n );\\n\\n emit Mint(msg.sender, _amount);\\n // Mint matching amount of OTokens\\n oToken.mint(msg.sender, _amount);\\n }\\n\\n /**\\n * @notice Burn OTokens for an allowed Strategy\\n * @param _amount Amount of OToken to burn\\n *\\n * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could\\n * require withdrawal on an AMO strategy and that one can call `burnForStrategy`\\n * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function burnForStrategy(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n {\\n require(\\n strategies[msg.sender].isSupported == true,\\n \\\"Unsupported strategy\\\"\\n );\\n require(\\n isMintWhitelistedStrategy[msg.sender] == true,\\n \\\"Not whitelisted strategy\\\"\\n );\\n\\n emit Redeem(msg.sender, _amount);\\n\\n // Burn OTokens\\n oToken.burn(msg.sender, _amount);\\n }\\n\\n ////////////////////////////////////////////////////\\n /// ASYNC WITHDRAWALS ///\\n ////////////////////////////////////////////////////\\n /**\\n * @notice Request an asynchronous withdrawal of asset in exchange for OToken.\\n * The OToken is burned on request and the asset is transferred to the withdrawer on claim.\\n * This request can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal this request's `queued` amount.\\n * There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs\\n * enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue.\\n * OToken is converted to asset at 1:1.\\n * @param _amount Amount of OToken to burn.\\n * @return requestId Unique ID for the withdrawal request\\n * @return queued Cumulative total of all asset queued including already claimed requests.\\n */\\n function requestWithdrawal(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 requestId, uint256 queued)\\n {\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n require(withdrawalClaimDelay > 0, \\\"Async withdrawals not enabled\\\");\\n\\n // The check that the requester has enough OToken is done in to later burn call\\n\\n requestId = withdrawalQueueMetadata.nextWithdrawalIndex;\\n queued =\\n withdrawalQueueMetadata.queued +\\n _amount.scaleBy(assetDecimals, 18);\\n\\n // Store the next withdrawal request\\n withdrawalQueueMetadata.nextWithdrawalIndex = SafeCast.toUint128(\\n requestId + 1\\n );\\n // Store the updated queued amount which reserves asset in the withdrawal queue\\n // and reduces the vault's total asset\\n withdrawalQueueMetadata.queued = SafeCast.toUint128(queued);\\n // Store the user's withdrawal request\\n // `queued` is in asset decimals, while `amount` is in OToken decimals (18)\\n withdrawalRequests[requestId] = WithdrawalRequest({\\n withdrawer: msg.sender,\\n claimed: false,\\n timestamp: uint40(block.timestamp),\\n amount: SafeCast.toUint128(_amount),\\n queued: SafeCast.toUint128(queued)\\n });\\n\\n // Burn the user's OToken\\n oToken.burn(msg.sender, _amount);\\n\\n // Prevent withdrawal if the vault is solvent by more than the allowed percentage\\n _postRedeem();\\n\\n emit WithdrawalRequested(msg.sender, requestId, _amount, queued);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Claim a previously requested withdrawal once it is claimable.\\n * This request can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal this request's `queued` amount and 10 minutes has passed.\\n * If the requests is not claimable, the transaction will revert with `Queue pending liquidity`.\\n * If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`.\\n * OToken is converted to asset at 1:1.\\n * @param _requestId Unique ID for the withdrawal request\\n * @return amount Amount of asset transferred to the withdrawer\\n */\\n function claimWithdrawal(uint256 _requestId)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 amount)\\n {\\n // Try and get more liquidity if there is not enough available\\n if (\\n withdrawalRequests[_requestId].queued >\\n withdrawalQueueMetadata.claimable\\n ) {\\n // Add any asset to the withdrawal queue\\n // this needs to remain here as:\\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\\n // - funds can be withdrawn from a strategy\\n //\\n // Those funds need to be added to withdrawal queue liquidity\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n // Scale amount to asset decimals\\n amount = _claimWithdrawal(_requestId);\\n\\n // transfer asset from the vault to the withdrawer\\n IERC20(asset).safeTransfer(msg.sender, amount);\\n\\n // Prevent insolvency\\n _postRedeem();\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n /**\\n * @notice Claim a previously requested withdrawals once they are claimable.\\n * This requests can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal each request's `queued` amount and 10 minutes has passed.\\n * If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`.\\n * If one of the requests is not older than 10 minutes,\\n * the whole transaction will revert with `Claim delay not met`.\\n * @param _requestIds Unique ID of each withdrawal request\\n * @return amounts Amount of asset received for each request\\n * @return totalAmount Total amount of asset transferred to the withdrawer\\n */\\n function claimWithdrawals(uint256[] calldata _requestIds)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256[] memory amounts, uint256 totalAmount)\\n {\\n // Add any asset to the withdrawal queue\\n // this needs to remain here as:\\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\\n // - funds can be withdrawn from a strategy\\n //\\n // Those funds need to be added to withdrawal queue liquidity\\n _addWithdrawalQueueLiquidity();\\n\\n amounts = new uint256[](_requestIds.length);\\n for (uint256 i; i < _requestIds.length; ++i) {\\n // Scale all amounts to asset decimals, thus totalAmount is also in asset decimals\\n amounts[i] = _claimWithdrawal(_requestIds[i]);\\n totalAmount += amounts[i];\\n }\\n\\n // transfer all the claimed asset from the vault to the withdrawer\\n IERC20(asset).safeTransfer(msg.sender, totalAmount);\\n\\n // Prevent insolvency\\n _postRedeem();\\n\\n return (amounts, totalAmount);\\n }\\n\\n function _claimWithdrawal(uint256 requestId)\\n internal\\n returns (uint256 amount)\\n {\\n require(withdrawalClaimDelay > 0, \\\"Async withdrawals not enabled\\\");\\n\\n // Load the structs from storage into memory\\n WithdrawalRequest memory request = withdrawalRequests[requestId];\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n require(\\n request.timestamp + withdrawalClaimDelay <= block.timestamp,\\n \\\"Claim delay not met\\\"\\n );\\n // If there isn't enough reserved liquidity in the queue to claim\\n require(request.queued <= queue.claimable, \\\"Queue pending liquidity\\\");\\n require(request.withdrawer == msg.sender, \\\"Not requester\\\");\\n require(request.claimed == false, \\\"Already claimed\\\");\\n\\n // Store the request as claimed\\n withdrawalRequests[requestId].claimed = true;\\n // Store the updated claimed amount\\n withdrawalQueueMetadata.claimed =\\n queue.claimed +\\n SafeCast.toUint128(\\n StableMath.scaleBy(request.amount, assetDecimals, 18)\\n );\\n\\n emit WithdrawalClaimed(msg.sender, requestId, request.amount);\\n\\n return StableMath.scaleBy(request.amount, assetDecimals, 18);\\n }\\n\\n function _postRedeem() internal view {\\n // Until we can prove that we won't affect the prices of our asset\\n // by withdrawing them, this should be here.\\n // It's possible that a strategy was off on its asset total, perhaps\\n // a reward token sold for more or for less than anticipated.\\n uint256 totalUnits = _totalValue();\\n\\n // Check that the OTokens are backed by enough asset\\n if (maxSupplyDiff > 0) {\\n // If there are more outstanding withdrawal requests than asset in the vault and strategies\\n // then the available asset will be negative and totalUnits will be rounded up to zero.\\n // As we don't know the exact shortfall amount, we will reject all redeem and withdrawals\\n require(totalUnits > 0, \\\"Too many outstanding requests\\\");\\n\\n // Allow a max difference of maxSupplyDiff% between\\n // asset value and OUSD total supply\\n uint256 diff = oToken.totalSupply().divPrecisely(totalUnits);\\n require(\\n (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,\\n \\\"Backing supply liquidity error\\\"\\n );\\n }\\n }\\n\\n /**\\n * @notice Allocate unallocated funds on Vault to strategies.\\n */\\n function allocate() external virtual whenNotCapitalPaused nonReentrant {\\n // Add any unallocated asset to the withdrawal queue first\\n _addWithdrawalQueueLiquidity();\\n\\n _allocate();\\n }\\n\\n /**\\n * @dev Allocate asset (eg. WETH or USDC) to the default asset strategy\\n * if there is excess to the Vault buffer.\\n * This is called from either `mint` or `allocate` and assumes `_addWithdrawalQueueLiquidity`\\n * has been called before this function.\\n */\\n function _allocate() internal virtual {\\n // No need to do anything if no default strategy for asset\\n address depositStrategyAddr = defaultStrategy;\\n if (depositStrategyAddr == address(0)) return;\\n\\n uint256 assetAvailableInVault = _assetAvailable();\\n // No need to do anything if there isn't any asset in the vault to allocate\\n if (assetAvailableInVault == 0) return;\\n\\n // Calculate the target buffer for the vault using the total supply\\n uint256 totalSupply = oToken.totalSupply();\\n // Scaled to asset decimals\\n uint256 targetBuffer = totalSupply.mulTruncate(vaultBuffer).scaleBy(\\n assetDecimals,\\n 18\\n );\\n\\n // If available asset in the Vault is below or equal the target buffer then there's nothing to allocate\\n if (assetAvailableInVault <= targetBuffer) return;\\n\\n // The amount of asset to allocate to the default strategy\\n uint256 allocateAmount = assetAvailableInVault - targetBuffer;\\n\\n IStrategy strategy = IStrategy(depositStrategyAddr);\\n // Transfer asset to the strategy and call the strategy's deposit function\\n IERC20(asset).safeTransfer(address(strategy), allocateAmount);\\n strategy.deposit(asset, allocateAmount);\\n\\n emit AssetAllocated(asset, depositStrategyAddr, allocateAmount);\\n }\\n\\n /**\\n * @notice Calculate the total value of asset held by the Vault and all\\n * strategies and update the supply of OTokens.\\n * @dev Restricted to the Operator, Strategist or Governor.\\n */\\n function rebase() external virtual nonReentrant {\\n require(\\n msg.sender == operatorAddr ||\\n msg.sender == strategistAddr ||\\n isGovernor(),\\n \\\"Caller not authorized\\\"\\n );\\n _rebase();\\n }\\n\\n /**\\n * @dev Calculate the total value of asset held by the Vault and all\\n * strategies and update the supply of OTokens, optionally sending a\\n * portion of the yield to the trustee.\\n * @return totalUnits Total balance of Vault in units\\n */\\n function _rebase() internal whenNotRebasePaused returns (uint256) {\\n uint256 supply = oToken.totalSupply();\\n uint256 vaultValue = _totalValue();\\n // If no supply yet, do not rebase\\n if (supply == 0) {\\n return vaultValue;\\n }\\n\\n // Calculate yield and new supply\\n (uint256 yield, uint256 targetRate) = _nextYield(supply, vaultValue);\\n uint256 newSupply = supply + yield;\\n // Only rebase upwards and if we have enough backing funds\\n if (newSupply <= supply || newSupply > vaultValue) {\\n return vaultValue;\\n }\\n\\n rebasePerSecondTarget = uint64(_min(targetRate, type(uint64).max));\\n lastRebase = uint64(block.timestamp); // Intentional cast\\n\\n // Fee collection on yield\\n address _trusteeAddress = trusteeAddress; // gas savings\\n uint256 fee = 0;\\n if (_trusteeAddress != address(0)) {\\n fee = (yield * trusteeFeeBps) / 1e4;\\n if (fee > 0) {\\n require(fee < yield, \\\"Fee must not be greater than yield\\\");\\n oToken.mint(_trusteeAddress, fee);\\n }\\n }\\n emit YieldDistribution(_trusteeAddress, yield, fee);\\n\\n // Only ratchet OToken supply upwards\\n // Final check uses latest totalSupply\\n if (newSupply > oToken.totalSupply()) {\\n oToken.changeSupply(newSupply);\\n }\\n return vaultValue;\\n }\\n\\n /**\\n * @notice Calculates the amount that would rebase at next rebase.\\n * This is before any fees.\\n * @return yield amount of expected yield\\n */\\n function previewYield() external view returns (uint256 yield) {\\n (yield, ) = _nextYield(oToken.totalSupply(), _totalValue());\\n return yield;\\n }\\n\\n /**\\n * @dev Calculates the amount that would rebase at next rebase.\\n * See this Readme for detailed explanation:\\n * contracts/contracts/vault/README - Yield Limits.md\\n */\\n function _nextYield(uint256 supply, uint256 vaultValue)\\n internal\\n view\\n virtual\\n returns (uint256 yield, uint256 targetRate)\\n {\\n uint256 nonRebasing = oToken.nonRebasingSupply();\\n uint256 rebasing = supply - nonRebasing;\\n uint256 elapsed = block.timestamp - lastRebase;\\n targetRate = rebasePerSecondTarget;\\n\\n if (\\n elapsed == 0 || // Yield only once per block.\\n rebasing == 0 || // No yield if there are no rebasing tokens to give it to.\\n supply > vaultValue || // No yield if we do not have yield to give.\\n block.timestamp >= type(uint64).max // No yield if we are too far in the future to calculate it correctly.\\n ) {\\n return (0, targetRate);\\n }\\n\\n // Start with the full difference available\\n yield = vaultValue - supply;\\n\\n // Cap via optional automatic duration smoothing\\n uint256 _dripDuration = dripDuration;\\n if (_dripDuration > 1) {\\n // If we are able to sustain an increased drip rate for\\n // double the duration, then increase the target drip rate\\n targetRate = _max(targetRate, yield / (_dripDuration * 2));\\n // If we cannot sustain the target rate any more,\\n // then rebase what we can, and reduce the target\\n targetRate = _min(targetRate, yield / _dripDuration);\\n // drip at the new target rate\\n yield = _min(yield, targetRate * elapsed);\\n }\\n\\n // Cap per second. elapsed is not 1e18 denominated\\n yield = _min(yield, (rebasing * elapsed * rebasePerSecondMax) / 1e18);\\n\\n // Cap at a hard max per rebase, to avoid long durations resulting in huge rebases\\n yield = _min(yield, (rebasing * MAX_REBASE) / 1e18);\\n\\n return (yield, targetRate);\\n }\\n\\n /**\\n * @notice Determine the total value of asset held by the vault and its\\n * strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function totalValue() external view virtual returns (uint256 value) {\\n value = _totalValue();\\n }\\n\\n /**\\n * @dev Internal Calculate the total value of the asset held by the\\n * vault and its strategies.\\n * @dev The total value of all WETH held by the vault and all its strategies\\n * less any WETH that is reserved for the withdrawal queue.\\n * If there is not enough WETH in the vault and all strategies to cover\\n * all outstanding withdrawal requests then return a total value of 0.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValue() internal view virtual returns (uint256 value) {\\n // As asset is the only asset, just return the asset balance\\n value = _checkBalance(asset).scaleBy(18, assetDecimals);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @param _asset Address of asset\\n * @return uint256 Balance of asset in decimals of asset\\n */\\n function checkBalance(address _asset) external view returns (uint256) {\\n return _checkBalance(_asset);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @dev Get the balance of an asset held in Vault and all strategies\\n * less any asset that is reserved for the withdrawal queue.\\n * BaseAsset is the only asset that can return a non-zero balance.\\n * All other asset will return 0 even if there is some dust amounts left in the Vault.\\n * For example, there is 1 wei left of stETH (or USDC) in the OETH (or OUSD) Vault but\\n * will return 0 in this function.\\n *\\n * If there is not enough asset in the vault and all strategies to cover all outstanding\\n * withdrawal requests then return a asset balance of 0\\n * @param _asset Address of asset\\n * @return balance Balance of asset in decimals of asset\\n */\\n function _checkBalance(address _asset)\\n internal\\n view\\n virtual\\n returns (uint256 balance)\\n {\\n if (_asset != asset) return 0;\\n\\n // Get the asset in the vault and the strategies\\n IERC20 asset = IERC20(_asset);\\n balance = asset.balanceOf(address(this));\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy strategy = IStrategy(allStrategies[i]);\\n if (strategy.supportsAsset(_asset)) {\\n balance = balance + strategy.checkBalance(_asset);\\n }\\n }\\n\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // If the vault becomes insolvent enough that the total value in the vault and all strategies\\n // is less than the outstanding withdrawals.\\n // For example, there was a mass slashing event and most users request a withdrawal.\\n if (balance + queue.claimed < queue.queued) {\\n return 0;\\n }\\n\\n // Need to remove asset that is reserved for the withdrawal queue\\n return balance + queue.claimed - queue.queued;\\n }\\n\\n /**\\n * @notice Adds WETH to the withdrawal queue if there is a funding shortfall.\\n * @dev is called from the Native Staking strategy when validator withdrawals are processed.\\n * It also called before any WETH is allocated to a strategy.\\n */\\n function addWithdrawalQueueLiquidity() external {\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @dev Adds asset (eg. WETH or USDC) to the withdrawal queue if there is a funding shortfall.\\n * This assumes 1 asset equal 1 corresponding OToken.\\n */\\n function _addWithdrawalQueueLiquidity()\\n internal\\n returns (uint256 addedClaimable)\\n {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // Check if the claimable asset is less than the queued amount\\n uint256 queueShortfall = queue.queued - queue.claimable;\\n\\n // No need to do anything is the withdrawal queue is full funded\\n if (queueShortfall == 0) {\\n return 0;\\n }\\n\\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\\n\\n // Of the claimable withdrawal requests, how much is unclaimed?\\n // That is, the amount of asset that is currently allocated for the withdrawal queue\\n uint256 allocatedBaseAsset = queue.claimable - queue.claimed;\\n\\n // If there is no unallocated asset then there is nothing to add to the queue\\n if (assetBalance <= allocatedBaseAsset) {\\n return 0;\\n }\\n\\n uint256 unallocatedBaseAsset = assetBalance - allocatedBaseAsset;\\n // the new claimable amount is the smaller of the queue shortfall or unallocated asset\\n addedClaimable = queueShortfall < unallocatedBaseAsset\\n ? queueShortfall\\n : unallocatedBaseAsset;\\n uint256 newClaimable = queue.claimable + addedClaimable;\\n\\n // Store the new claimable amount back to storage\\n withdrawalQueueMetadata.claimable = SafeCast.toUint128(newClaimable);\\n\\n // emit a WithdrawalClaimable event\\n emit WithdrawalClaimable(newClaimable, addedClaimable);\\n }\\n\\n /**\\n * @dev Calculate how much asset (eg. WETH or USDC) in the vault is not reserved for the withdrawal queue.\\n * That is, it is available to be redeemed or deposited into a strategy.\\n */\\n function _assetAvailable() internal view returns (uint256 assetAvailable) {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // The amount of asset that is still to be claimed in the withdrawal queue\\n uint256 outstandingWithdrawals = queue.queued - queue.claimed;\\n\\n // The amount of sitting in asset in the vault\\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\\n // If there is not enough asset in the vault to cover the outstanding withdrawals\\n if (assetBalance <= outstandingWithdrawals) return 0;\\n\\n return assetBalance - outstandingWithdrawals;\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Return the number of asset supported by the Vault.\\n */\\n function getAssetCount() public view returns (uint256) {\\n return 1;\\n }\\n\\n /**\\n * @notice Return all vault asset addresses in order\\n */\\n function getAllAssets() external view returns (address[] memory) {\\n address[] memory a = new address[](1);\\n a[0] = asset;\\n return a;\\n }\\n\\n /**\\n * @notice Return the number of strategies active on the Vault.\\n */\\n function getStrategyCount() external view returns (uint256) {\\n return allStrategies.length;\\n }\\n\\n /**\\n * @notice Return the array of all strategies\\n */\\n function getAllStrategies() external view returns (address[] memory) {\\n return allStrategies;\\n }\\n\\n /**\\n * @notice Returns whether the vault supports the asset\\n * @param _asset address of the asset\\n * @return true if supported\\n */\\n function isSupportedAsset(address _asset) external view returns (bool) {\\n return asset == _asset;\\n }\\n\\n function _min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n function _max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a > b ? a : b;\\n }\\n}\\n\",\"keccak256\":\"0xc2080a50088fc275eddea5784cef6a561280918679c846de48a8983613acf56e\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultInitializer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultInitializer contract\\n * @notice The Vault contract initializes the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport \\\"./VaultStorage.sol\\\";\\n\\nabstract contract VaultInitializer is VaultStorage {\\n constructor(address _asset) VaultStorage(_asset) {}\\n\\n function initialize(address _oToken) external onlyGovernor initializer {\\n require(_oToken != address(0), \\\"oToken address is zero\\\");\\n\\n oToken = OUSD(_oToken);\\n\\n rebasePaused = false;\\n capitalPaused = true;\\n\\n // Initial Vault buffer of 0%\\n vaultBuffer = 0;\\n // Initial allocate threshold of 25,000 OUSD\\n autoAllocateThreshold = 25000e18;\\n // Initialize all strategies\\n allStrategies = new address[](0);\\n // Start with drip duration: 7 days\\n dripDuration = 604800;\\n }\\n}\\n\",\"keccak256\":\"0x5198442b36146a9c1c1f38294866f4b3a12344ccf67dd9dd2e3958243bbd9c98\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultStorage.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultStorage contract\\n * @notice The VaultStorage contract defines the storage for the Vault contracts\\n * @author Origin Protocol Inc\\n */\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { IERC20Metadata } from \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { OUSD } from \\\"../token/OUSD.sol\\\";\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport \\\"../utils/Helpers.sol\\\";\\n\\nabstract contract VaultStorage is Initializable, Governable {\\n using SafeERC20 for IERC20;\\n\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event DefaultStrategyUpdated(address _strategy);\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\\n event DripDurationChanged(uint256 dripDuration);\\n event OperatorUpdated(address newOperator);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\\n\\n // Since we are proxy, all state should be uninitalized.\\n // Since this storage contract does not have logic directly on it\\n // we should not be checking for to see if these variables can be constant.\\n // slither-disable-start uninitialized-state\\n // slither-disable-start constable-states\\n\\n /// @dev mapping of supported vault assets to their configuration\\n uint256 private _deprecated_assets;\\n /// @dev list of all assets supported by the vault.\\n address[] private _deprecated_allAssets;\\n\\n // Strategies approved for use by the Vault\\n struct Strategy {\\n bool isSupported;\\n uint256 _deprecated; // Deprecated storage slot\\n }\\n /// @dev mapping of strategy contracts to their configuration\\n mapping(address => Strategy) public strategies;\\n /// @dev list of all vault strategies\\n address[] internal allStrategies;\\n\\n /// @notice Address of the Oracle price provider contract\\n address private _deprecated_priceProvider;\\n /// @notice pause rebasing if true\\n bool public rebasePaused;\\n /// @notice pause operations that change the OToken supply.\\n /// eg mint, redeem, allocate, mint/burn for strategy\\n bool public capitalPaused;\\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\\n uint256 private _deprecated_redeemFeeBps;\\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\\n uint256 public vaultBuffer;\\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\\n uint256 public autoAllocateThreshold;\\n /// @dev Deprecated. Was the auto-rebase trigger threshold for mint/redeem.\\n /// Storage slot retained for proxy compatibility; no longer read or written.\\n uint256 internal __deprecatedRebaseThreshold;\\n\\n /// @dev Address of the OToken token. eg OUSD or OETH.\\n OUSD public oToken;\\n\\n /// @dev Address of the contract responsible for post rebase syncs with AMMs\\n address private _deprecated_rebaseHooksAddr = address(0);\\n\\n /// @dev Deprecated: Address of Uniswap\\n address private _deprecated_uniswapAddr = address(0);\\n\\n /// @notice Address of the Strategist\\n address public strategistAddr = address(0);\\n\\n /// @notice Mapping of asset address to the Strategy that they should automatically\\n // be allocated to\\n uint256 private _deprecated_assetDefaultStrategies;\\n\\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\\n uint256 public maxSupplyDiff;\\n\\n /// @notice Trustee contract that can collect a percentage of yield\\n address public trusteeAddress;\\n\\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\\n uint256 public trusteeFeeBps;\\n\\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\\n address[] private _deprecated_swapTokens;\\n\\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\\n\\n address private _deprecated_ousdMetaStrategy;\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n int256 private _deprecated_netOusdMintedForStrategy;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n uint256 private _deprecated_netOusdMintForStrategyThreshold;\\n\\n uint256 private _deprecated_swapConfig;\\n\\n // List of strategies that can mint oTokens directly\\n // Used in OETHBaseVaultCore\\n mapping(address => bool) public isMintWhitelistedStrategy;\\n\\n /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\\n /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\\n address private _deprecated_dripper;\\n\\n /// Withdrawal Queue Storage /////\\n\\n struct WithdrawalQueueMetadata {\\n // cumulative total of all withdrawal requests included the ones that have already been claimed\\n uint128 queued;\\n // cumulative total of all the requests that can be claimed including the ones that have already been claimed\\n uint128 claimable;\\n // total of all the requests that have been claimed\\n uint128 claimed;\\n // index of the next withdrawal request starting at 0\\n uint128 nextWithdrawalIndex;\\n }\\n\\n /// @notice Global metadata for the withdrawal queue including:\\n /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed\\n /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed\\n /// claimed - total of all the requests that have been claimed\\n /// nextWithdrawalIndex - index of the next withdrawal request starting at 0\\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\\n\\n struct WithdrawalRequest {\\n address withdrawer;\\n bool claimed;\\n uint40 timestamp; // timestamp of the withdrawal request\\n // Amount of oTokens to redeem. eg OETH\\n uint128 amount;\\n // cumulative total of all withdrawal requests including this one.\\n // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\\n uint128 queued;\\n }\\n\\n /// @notice Mapping of withdrawal request indices to the user withdrawal request data\\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\\n\\n /// @notice Sets a minimum delay that is required to elapse between\\n /// requesting async withdrawals and claiming the request.\\n /// When set to 0 async withdrawals are disabled.\\n uint256 public withdrawalClaimDelay;\\n\\n /// @notice Time in seconds that the vault last rebased yield.\\n uint64 public lastRebase;\\n\\n /// @notice Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\\n uint64 public dripDuration;\\n\\n /// @notice max rebase percentage per second\\n /// Can be used to set maximum yield of the protocol,\\n /// spreading out yield over time\\n uint64 public rebasePerSecondMax;\\n\\n /// @notice target rebase rate limit, based on past rates and funds available.\\n uint64 public rebasePerSecondTarget;\\n\\n uint256 internal constant MAX_REBASE = 0.02 ether;\\n uint256 internal constant MAX_REBASE_PER_SECOND =\\n uint256(0.05 ether) / 1 days;\\n\\n /// @notice Default strategy for asset\\n address public defaultStrategy;\\n\\n /// @notice Address authorized to call `rebase()` directly. The Governor\\n /// and Strategist are always allowed in addition to this address.\\n address public operatorAddr;\\n\\n // For future use\\n uint256[41] private __gap;\\n\\n /// @notice Index of WETH asset in allAssets array\\n /// Legacy OETHVaultCore code, relocated here for vault consistency.\\n uint256 private _deprecated_wethAssetIndex;\\n\\n /// @dev Address of the asset (eg. WETH or USDC)\\n address public immutable asset;\\n uint8 internal immutable assetDecimals;\\n\\n // slither-disable-end constable-states\\n // slither-disable-end uninitialized-state\\n\\n constructor(address _asset) {\\n uint8 _decimals = IERC20Metadata(_asset).decimals();\\n require(_decimals <= 18, \\\"invalid asset decimals\\\");\\n asset = _asset;\\n assetDecimals = _decimals;\\n }\\n\\n /// @notice Deprecated: use `oToken()` instead.\\n function oUSD() external view returns (OUSD) {\\n return oToken;\\n }\\n}\\n\",\"keccak256\":\"0x9245e680c777afc86fc97e0101940bd0d702b206e49b940c42c574be92860e4f\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x60c0604052603d80546001600160a01b0319908116909155603e805482169055603f8054909116905534801561003457600080fd5b5060405161541938038061541983398101604081905261005391610133565b808080806000816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100bb9190610163565b905060128160ff1611156101155760405162461bcd60e51b815260206004820152601660248201527f696e76616c696420617373657420646563696d616c7300000000000000000000604482015260640160405180910390fd5b6001600160a01b0390911660805260ff1660a0525061018692505050565b60006020828403121561014557600080fd5b81516001600160a01b038116811461015c57600080fd5b9392505050565b60006020828403121561017557600080fd5b815160ff8116811461015c57600080fd5b60805160a0516151c661025360003960008181610fbb015281816120ac0152818161319201528181613773015281816138170152818161408f01526144440152600081816105870152818161088b01528181610c5801528181610ff9015281816112e80152818161144d0152818161176c0152818161187a01528181612ca1015281816132630152818161339101528181613ae601528181613dbb01528181613ef2015281816140fa01528181614145015281816141ad0152818161446b01526148a601526151c66000f3fe608060405234801561001057600080fd5b50600436106104075760003560e01c8063663e64ce11610220578063ae69f3cb11610130578063c7af3352116100b8578063e6cc543211610087578063e6cc5432146109e5578063ea33b8e4146109f9578063f3f18c3714610a01578063f844443614610a14578063fac5bb9b14610a2757600080fd5b8063c7af3352146109ba578063c9919112146109c2578063d38bfff4146109ca578063d4c3eea0146109dd57600080fd5b8063b9b17f9f116100ff578063b9b17f9f14610975578063bb7a632e1461097d578063c3b2886414610997578063c4d66de81461099f578063c5f00841146109b257600080fd5b8063ae69f3cb14610934578063af14052c14610947578063b2c9336d1461094f578063b4925a201461096257600080fd5b806395b166bc116101b35780639fa1826e116101825780639fa1826e146108f6578063a0712d68146108ff578063a0aead4d14610912578063ab80dafb14610919578063abaa99161461092c57600080fd5b806395b166bc146108685780639be918e61461087b5780639e428552146108bb5780639ee679e8146108ce57600080fd5b80638e510b52116101ef5780638e510b521461079c5780638ec489a2146107a5578063937b2581146107b857806394828ffd1461086057600080fd5b8063663e64ce14610750578063773540b31461076357806378f353a114610776578063840c4c7a1461078957600080fd5b806339ebf8231161031b578063527e83a8116102ae5780635802a1721161027d5780635802a172146106fe578063597c89101461070f5780635d36b190146107225780635f5152261461072a5780636217f3ea1461073d57600080fd5b8063527e83a8146106aa57806353ca9f24146106c4578063570d8e1d146106d857806357bee944146106eb57600080fd5b806345e4213b116102ea57806345e4213b1461063b57806348e30f541461064457806349c1d54d146106655780634d5f46291461067857600080fd5b806339ebf823146105a95780633b8ae397146105ed5780633dbc911f146106005780634530820a1461060857600080fd5b80631a32aad61161039e5780632acada4d1161036d5780632acada4d146104f35780632da845a81461050857806331e19cfa1461051b578063362bd1a31461052357806338d52e0f1461058257600080fd5b80631a32aad6146104ad5780631cfbe7bc146104c05780631edfe3da146104d3578063207134b0146104ea57600080fd5b80631072cbea116103da5780631072cbea14610461578063156e29f614610474578063175188e8146104875780631816dd4a1461049a57600080fd5b80630493a0fa1461040c57806309f49bf5146104215780630acbda75146104295780630c340a241461043c575b600080fd5b61041f61041a366004614b54565b610a3a565b005b61041f610af0565b61041f610437366004614b54565b610b60565b610444610c0b565b6040516001600160a01b0390911681526020015b60405180910390f35b61041f61046f366004614b89565b610c28565b61041f610482366004614bb3565b610ce6565b61041f610495366004614be6565b610d59565b61041f6104a8366004614be6565b6110f7565b603c54610444906001600160a01b031681565b61041f6104ce366004614b54565b6111fe565b6104dc60395481565b604051908152602001610458565b6104dc60435481565b6104fb6112c0565b6040516104589190614c01565b61041f610516366004614be6565b611337565b6036546104dc565b604b54604c5461054f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610458565b6104447f000000000000000000000000000000000000000000000000000000000000000081565b6105d66105b7366004614be6565b6035602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610458565b61041f6105fb366004614be6565b6113a9565b61041f6115bc565b61062b610616366004614be6565b60496020526000908152604090205460ff1681565b6040519015158152602001610458565b6104dc604e5481565b610657610652366004614c91565b611632565b604051610458929190614cd2565b604254610444906001600160a01b031681565b604f5461069290600160c01b90046001600160401b031681565b6040516001600160401b039091168152602001610458565b604f5461069290600160801b90046001600160401b031681565b60375461062b90600160a01b900460ff1681565b603f54610444906001600160a01b031681565b61041f6106f9366004614be6565b6117a8565b603c546001600160a01b0316610444565b61041f61071d366004614be6565b61195b565b61041f61199f565b6104dc610738366004614be6565b611a45565b61041f61074b366004614b54565b611a56565b61041f61075e366004614b54565b611bda565b61041f610771366004614be6565b611c33565b604f54610692906001600160401b031681565b61041f610797366004614d1f565b611ca5565b6104dc60415481565b61041f6107b3366004614b54565b611d2c565b6108196107c6366004614b54565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a001610458565b61041f611de1565b61041f610876366004614be6565b611e51565b61062b610889366004614be6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b61041f6108c9366004614be6565b611f18565b6108e16108dc366004614b54565b611f8a565b60408051928352602083019190915201610458565b6104dc603a5481565b61041f61090d366004614b54565b6122ca565b60016104dc565b61041f610927366004614b54565b61233b565b61041f61248a565b61041f610942366004614d1f565b612502565b61041f61257e565b61041f61095d366004614b54565b612639565b61041f610970366004614b54565b612692565b61041f6127b0565b604f5461069290600160401b90046001600160401b031681565b6104fb6127b8565b61041f6109ad366004614be6565b61281a565b61041f6129c5565b61062b612a3b565b61041f612a6c565b61041f6109d8366004614be6565b612aac565b6104dc612b50565b60375461062b90600160a81b900460ff1681565b6104dc612b5a565b605154610444906001600160a01b031681565b6104dc610a22366004614b54565b612be9565b605054610444906001600160a01b031681565b603f546001600160a01b0316331480610a565750610a56612a3b565b610a7b5760405162461bcd60e51b8152600401610a7290614da3565b60405180910390fd5b610a83612cda565b50610a8d81613074565b604f80546001600160401b0392909216600160401b0267ffffffffffffffff60401b199092169190911790556040518181527f406e15fbca1d8ded2dbb06765fea3a54f18395c54125a4c9916dd00ea14ee15e906020015b60405180910390a150565b603f546001600160a01b0316331480610b0c5750610b0c612a3b565b610b285760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b610b68612a3b565b610b845760405162461bcd60e51b8152600401610a7290614deb565b611388811115610bd65760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f7420657863656564203530250000000000000000006044820152606401610a72565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c790602001610ae5565b6000610c236000805160206151718339815191525490565b905090565b610c30612a3b565b610c4c5760405162461bcd60e51b8152600401610a7290614deb565b816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610cc65760405162461bcd60e51b815260206004820152601660248201527513db9b1e481d5b9cdd5c1c1bdc9d195908185cdcd95d60521b6044820152606401610a72565b610ce2610cd1610c0b565b6001600160a01b03841690836130e0565b5050565b603754600160a81b900460ff1615610d105760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101610d425760405162461bcd60e51b8152600401610a7290614e4a565b60028255610d4f84613136565b5060019055505050565b610d61612a3b565b610d7d5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff16610db55760405162461bcd60e51b8152600401610a7290614e72565b6050546001600160a01b03808316911603610e125760405162461bcd60e51b815260206004820152601d60248201527f53747261746567792069732064656661756c7420666f722061737365740000006044820152606401610a72565b6036548060005b82811015610e6857836001600160a01b031660368281548110610e3e57610e3e614ea1565b6000918252602090912001546001600160a01b031603610e6057809150610e68565b600101610e19565b50818110156110f2576036610e7e600184614ecd565b81548110610e8e57610e8e614ea1565b600091825260209091200154603680546001600160a01b039092169183908110610eba57610eba614ea1565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610ef957610ef9614ee0565b6001900381819060005260206000200160006101000a8154906001600160a01b03021916905590556000839050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610f6157600080fd5b505af1158015610f75573d6000803e3d6000fd5b505050506001600160a01b0384166000908152603560209081526040808320805460ff199081169091556049909252822080549091169055610fe26509184e72a00060ff7f00000000000000000000000000000000000000000000000000000000000000001660126132a7565b604051632fa8a91360e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192508291841690635f51522690602401602060405180830381865afa15801561104d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110719190614ef6565b106110b35760405162461bcd60e51b81526020600482015260126024820152715374726174656779206861732066756e647360701b6044820152606401610a72565b6040516001600160a01b03861681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49060200160405180910390a150505b505050565b6110ff612a3b565b61111b5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff166111535760405162461bcd60e51b8152600401610a7290614e72565b6001600160a01b03811660009081526049602052604090205460ff16156111b25760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481dda1a5d195b1a5cdd1959606a1b6044820152606401610a72565b6001600160a01b038116600081815260496020526040808220805460ff19166001179055517f47c8c96a5942f094264111c5fe7f6a4fe86efe63254a6fa7afa5fc84f07d58e89190a250565b611206612a3b565b6112225760405162461bcd60e51b8152600401610a7290614deb565b80158061123f5750610258811015801561123f57506213c6808111155b61128b5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636c61696d2064656c617920706572696f640000000000006044820152606401610a72565b604e8190556040518181527fc59f5e32049abab44ddea11021f5abb89422a2f550837afcf25df9fc8d0db6b090602001610ae5565b60408051600180825281830190925260609160009190602080830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061131a5761131a614ea1565b6001600160a01b0390921660209283029190910190910152919050565b61133f612a3b565b61135b5760405162461bcd60e51b8152600401610a7290614deb565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610ae5565b6113b1612a3b565b6113cd5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff16156114365760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f766564000000000000006044820152606401610a72565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa15801561149c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c09190614f25565b61150c5760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a72565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610ae5565b603f546001600160a01b03163314806115d857506115d8612a3b565b6115f45760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b603754606090600090600160a81b900460ff16156116625760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016116945760405162461bcd60e51b8152600401610a7290614e4a565b600282556116a061330b565b50846001600160401b038111156116b9576116b9614f0f565b6040519080825280602002602001820160405280156116e2578160200160208202803683370190505b50935060005b8581101561175e5761171187878381811061170557611705614ea1565b905060200201356134e7565b85828151811061172357611723614ea1565b60200260200101818152505084818151811061174157611741614ea1565b6020026020010151846117549190614f47565b93506001016116e8565b506117936001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130e0565b61179b613848565b6001825550509250929050565b603f546001600160a01b03163314806117c457506117c4612a3b565b6117e05760405162461bcd60e51b8152600401610a7290614da3565b6040516001600160a01b03821681527f45a9e715f8779ebeab88d3e8d081fb8b484b7730857e7c4478a95a5b1d8f79489060200160405180910390a16001600160a01b03811615611939576001600160a01b03811660009081526035602052604090205460ff166118635760405162461bcd60e51b8152600401610a7290614e72565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa1580156118c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ed9190614f25565b6119395760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a72565b605080546001600160a01b0319166001600160a01b0392909216919091179055565b603f546001600160a01b03163314806119775750611977612a3b565b6119935760405162461bcd60e51b8152600401610a7290614da3565b61199c816139bb565b50565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614611a3a5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610a72565b611a4333613a83565b565b6000611a5082613ae2565b92915050565b603754600160a81b900460ff1615611a805760405162461bcd60e51b8152600401610a7290614e22565b3360009081526035602052604090205460ff161515600114611adb5760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a72565b3360009081526049602052604090205460ff161515600114611b3a5760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a72565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051611b6b929190614f5a565b60405180910390a1603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90611ba59033908590600401614f5a565b600060405180830381600087803b158015611bbf57600080fd5b505af1158015611bd3573d6000803e3d6000fd5b5050505050565b611be2612a3b565b611bfe5760405162461bcd60e51b8152600401610a7290614deb565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610ae5565b611c3b612a3b565b611c575760405162461bcd60e51b8152600401610a7290614deb565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610ae5565b603f546001600160a01b0316331480611cc15750611cc1612a3b565b611cdd5760405162461bcd60e51b8152600401610a7290614da3565b60008051602061515183398151915280546001198101611d0f5760405162461bcd60e51b8152600401610a7290614e4a565b60028255611d208787878787613d44565b50600190555050505050565b603f546001600160a01b0316331480611d485750611d48612a3b565b611d645760405162461bcd60e51b8152600401610a7290614da3565b670de0b6b3a7640000811115611dac5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b6044820152606401610a72565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610ae5565b603f546001600160a01b0316331480611dfd5750611dfd612a3b565b611e195760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e59612a3b565b611e755760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526049602052604090205460ff16611ecf5760405162461bcd60e51b815260206004820152600f60248201526e139bdd081dda1a5d195b1a5cdd1959608a1b6044820152606401610a72565b6001600160a01b038116600081815260496020526040808220805460ff19169055517f0ec40967a61509853550658e51d0e4297f7cba244fe4adc8ba18b5631ac20e2f9190a250565b611f20612a3b565b611f3c5760405162461bcd60e51b8152600401610a7290614deb565b605180546001600160a01b0319166001600160a01b0383169081179091556040519081527fb3b3f5f64ab192e4b5fefde1f51ce9733bbdcf831951543b325aebd49cc27ec490602001610ae5565b6037546000908190600160a81b900460ff1615611fb95760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101611feb5760405162461bcd60e51b8152600401610a7290614e4a565b600282556000851161203f5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a72565b6000604e54116120915760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a72565b604c54600160801b90046001600160801b031693506120d5857f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b604b546120eb91906001600160801b0316614f47565b92506121006120fb856001614f47565b613f83565b604c80546001600160801b03928316600160801b02921691909117905561212683613f83565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff16918101919091526060810161217687613f83565b6001600160801b0316815260200161218d85613f83565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906122489033908990600401614f5a565b600060405180830381600087803b15801561226257600080fd5b505af1158015612276573d6000803e3d6000fd5b50505050612282613848565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff16156122f45760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016123265760405162461bcd60e51b8152600401610a7290614e4a565b6002825561233383613136565b506001905550565b603754600160a81b900460ff16156123655760405162461bcd60e51b8152600401610a7290614e22565b3360009081526035602052604090205460ff1615156001146123c05760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a72565b3360009081526049602052604090205460ff16151560011461241f5760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a72565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853382604051612450929190614f5a565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611ba59033908590600401614f5a565b603754600160a81b900460ff16156124b45760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016124e65760405162461bcd60e51b8152600401610a7290614e4a565b600282556124f261330b565b506124fb613fec565b5060019055565b603f546001600160a01b031633148061251e575061251e612a3b565b61253a5760405162461bcd60e51b8152600401610a7290614da3565b6000805160206151518339815191528054600119810161256c5760405162461bcd60e51b8152600401610a7290614e4a565b60028255611d20308888888888614215565b600080516020615151833981519152805460011981016125b05760405162461bcd60e51b8152600401610a7290614e4a565b600282556051546001600160a01b03163314806125d75750603f546001600160a01b031633145b806125e557506125e5612a3b565b6126295760405162461bcd60e51b815260206004820152601560248201527410d85b1b195c881b9bdd08185d5d1a1bdc9a5e9959605a1b6044820152606401610a72565b612631612cda565b505060019055565b612641612a3b565b61265d5760405162461bcd60e51b8152600401610a7290614deb565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610ae5565b603f546001600160a01b03163314806126ae57506126ae612a3b565b6126ca5760405162461bcd60e51b8152600401610a7290614da3565b6126d2612cda565b5060006301e133806126e5606484614f73565b6126ef9190614f73565b90506127056201518066b1a2bc2ec50000614f73565b8111156127445760405162461bcd60e51b815260206004820152600d60248201526c0a4c2e8ca40e8dede40d0d2ced609b1b6044820152606401610a72565b61274d81613074565b604f80546001600160401b0392909216600160801b0267ffffffffffffffff60801b199092169190911790556040518181527fef46f143af5fead0010484fe7d6ec2e2972420faa76157f5a6075aa72e614cb59060200160405180910390a15050565b61199c61330b565b6060603680548060200260200160405190810160405280929190818152602001828054801561281057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116127f2575b5050505050905090565b612822612a3b565b61283e5760405162461bcd60e51b8152600401610a7290614deb565b600054610100900460ff1680612857575060005460ff16155b6128ba5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a72565b600054610100900460ff161580156128dc576000805461ffff19166101011790555b6001600160a01b03821661292b5760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b6044820152606401610a72565b603c80546001600160a01b0384166001600160a01b03199091161790556037805461ffff60a01b1916600160a81b1790556000603981905569054b40b1f852bda00000603a55604080519182526020820190819052905161298e91603691614ae3565b50604f805467ffffffffffffffff60401b19166a093a8000000000000000001790558015610ce2576000805461ff00191690555050565b603f546001600160a01b03163314806129e157506129e1612a3b565b6129fd5760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b6000612a536000805160206151718339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612a885750612a88612a3b565b612aa45760405162461bcd60e51b8152600401610a7290614da3565b611a436143a6565b612ab4612a3b565b612ad05760405162461bcd60e51b8152600401610a7290614deb565b612af8817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612b186000805160206151718339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000610c2361443b565b6000612be3603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd69190614ef6565b612bde61443b565b61448f565b50919050565b603754600090600160a81b900460ff1615612c165760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101612c485760405162461bcd60e51b8152600401610a7290614e4a565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115612c8957612c8761330b565b505b612c92846134e7565b9250612cc86001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130e0565b612cd0613848565b5060019055919050565b603754600090600160a01b900460ff1615612d295760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b6044820152606401610a72565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612d73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d979190614ef6565b90506000612da361443b565b905081600003612db65791506130719050565b600080612dc3848461448f565b90925090506000612dd48386614f47565b90508481111580612de457508381115b15612df3575091949350505050565b612e04826001600160401b03614662565b604f805477ffffffffffffffffffffffffffffffff000000000000000016600160c01b6001600160401b039384160267ffffffffffffffff19161742929092169190911790556042546001600160a01b031660008115612f405761271060435486612e6f9190614f95565b612e799190614f73565b90508015612f4057848110612edb5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b6064820152608401610a72565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612f0d9085908590600401614f5a565b600060405180830381600087803b158015612f2757600080fd5b505af1158015612f3b573d6000803e3d6000fd5b505050505b604080516001600160a01b0384168152602081018790529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a1603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fdd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130019190614ef6565b83111561306757603c546040516339a7919f60e01b8152600481018590526001600160a01b03909116906339a7919f90602401600060405180830381600087803b15801561304e57600080fd5b505af1158015613062573d6000803e3d6000fd5b505050505b5093955050505050505b90565b60006001600160401b038211156130dc5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610a72565b5090565b6110f28363a9059cbb60e01b84846040516024016130ff929190614f5a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614678565b600081116131865760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a72565b60006131b782601260ff7f0000000000000000000000000000000000000000000000000000000000000000166132a7565b90507f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516131ea929190614f5a565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132249033908590600401614f5a565b600060405180830381600087803b15801561323e57600080fd5b505af1158015613252573d6000803e3d6000fd5b5061328d9250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016905033308561474a565b61329561330b565b50603a548110610ce257610ce2613fec565b6000818311156132d7576132d06132be8385614ecd565b6132c990600a615093565b8590614788565b9350613301565b81831015613301576132fe6132ec8484614ecd565b6132f790600a615093565b8590614794565b93505b50825b9392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c548084169686019690965292909404166060830152600092839161335d9161509f565b6001600160801b03169050806000036133795760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156133e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134049190614ef6565b905060008360400151846020015161341c919061509f565b6001600160801b0316905080821161343957600094505050505090565b60006134458284614ecd565b90508084106134545780613456565b835b955060008686602001516001600160801b03166134739190614f47565b905061347e81613f83565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f463333906134d69083908a90918252602082015260400190565b60405180910390a150505050505090565b600080604e541161353a5760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a72565b6000828152604d6020908152604091829020825160a08101845281546001600160a01b038116825260ff600160a01b82041615158285015264ffffffffff600160a81b90910481168286019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915288519081018952604b548084168252849004831697810197909752604c54808316988801989098529190960490951694840194909452604e5491519093429261360192909116614f47565b11156136455760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b6044820152606401610a72565b80602001516001600160801b031682608001516001600160801b031611156136af5760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c69717569646974790000000000000000006044820152606401610a72565b81516001600160a01b031633146136f85760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b6044820152606401610a72565b60208201511561373c5760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b6044820152606401610a72565b6000848152604d60205260409020805460ff60a01b1916600160a01b179055606082015161379c906120fb906001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b81604001516137ab91906150be565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a361384082606001516001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b949350505050565b600061385261443b565b6041549091501561199c57600081116138ad5760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e672072657175657374730000006044820152606401610a72565b600061393082603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613906573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061392a9190614ef6565b906147a0565b9050604154670de0b6b3a7640000821161395b5761395682670de0b6b3a7640000614ecd565b61396d565b61396d670de0b6b3a764000083614ecd565b1115610ce25760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f7200006044820152606401610a72565b6001600160a01b03811660009081526035602052604090205460ff16613a235760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f72746564000000000000006044820152606401610a72565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a6357600080fd5b505af1158015613a77573d6000803e3d6000fd5b505050506110f261330b565b6001600160a01b038116613ad95760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610a72565b61199c816147c1565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614613b2557506000919050565b6040516370a0823160e01b815230600482015282906001600160a01b038216906370a0823190602401602060405180830381865afa158015613b6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b8f9190614ef6565b60365490925060005b81811015613cb457600060368281548110613bb557613bb5614ea1565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af690602401602060405180830381865afa158015613c0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c2f9190614f25565b15613cab57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f51522690602401602060405180830381865afa158015613c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c9e9190614ef6565b613ca89086614f47565b94505b50600101613b98565b5060408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529091613d029086614f47565b1015613d1357506000949350505050565b805160408201516001600160801b0391821691613d31911686614f47565b613d3b9190614ecd565b95945050505050565b6001600160a01b03851660009081526035602052604090205460ff16613da25760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b6044820152606401610a72565b600183148015613db25750600181145b8015613e1657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684846000818110613df657613df6614ea1565b9050602002016020810190613e0b9190614be6565b6001600160a01b0316145b613e625760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920617373657420697320737570706f727465640000000000000000006044820152606401610a72565b613e6a614828565b82826000818110613e7d57613e7d614ea1565b905060200201351115613ed25760405162461bcd60e51b815260206004820152601b60248201527f4e6f7420656e6f7567682061737365747320617661696c61626c6500000000006044820152606401610a72565b613f298583836000818110613ee957613ee9614ea1565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166130e09092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613f6457600080fd5b505af1158015613f78573d6000803e3d6000fd5b505050505050505050565b60006001600160801b038211156130dc5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610a72565b6050546001600160a01b0316806140005750565b600061400a614828565b905080600003614018575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015614062573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140869190614ef6565b905060006140cf7f000000000000000000000000000000000000000000000000000000000000000060ff1660126140c86039548661493690919063ffffffff16565b91906132a7565b90508083116140de5750505050565b60006140ea8285614ecd565b9050846141216001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682846130e0565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061416f907f0000000000000000000000000000000000000000000000000000000000000000908690600401614f5a565b600060405180830381600087803b15801561418957600080fd5b505af115801561419d573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b6001600160a01b03851660009081526035602052604090205460ff166142755760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b6044820152606401610a72565b8281146142c45760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d61746368000000000000006044820152606401610a72565b8260005b8181101561439357866001600160a01b031663d9caed12898888858181106142f2576142f2614ea1565b90506020020160208101906143079190614be6565b87878681811061431957614319614ea1565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561437057600080fd5b505af1158015614384573d6000803e3d6000fd5b505050508060010190506142c8565b5061439c61330b565b5050505050505050565b60365460005b8181101561443257603681815481106143c7576143c7614ea1565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b15801561440f57600080fd5b505af1158015614423573d6000803e3d6000fd5b505050508060010190506143ac565b50610ce261330b565b6000610c2360127f000000000000000000000000000000000000000000000000000000000000000060ff166140c87f0000000000000000000000000000000000000000000000000000000000000000613ae2565b6000806000603c60009054906101000a90046001600160a01b03166001600160a01b031663e696393a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156144e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061450b9190614ef6565b905060006145198287614ecd565b604f54909150600090614535906001600160401b031642614ecd565b604f54600160c01b90046001600160401b031694509050801580614557575081155b8061456157508587115b8061457357506001600160401b034210155b15614584576000945050505061465b565b61458e8787614ecd565b604f54909550600160401b90046001600160401b031660018111156145f3576145cb856145bc836002614f95565b6145c69089614f73565b61494b565b94506145e0856145db8389614f73565b614662565b94506145f0866145db8488614f95565b95505b604f54614634908790670de0b6b3a764000090600160801b90046001600160401b03166146208688614f95565b61462a9190614f95565b6145db9190614f73565b955061465486670de0b6b3a764000061462a66470de4df82000087614f95565b9550505050505b9250929050565b60008183106146715781613304565b5090919050565b60006146cd826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661495a9092919063ffffffff16565b8051909150156110f257808060200190518101906146eb9190614f25565b6110f25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a72565b6040516001600160a01b03808516602483015283166044820152606481018290526147829085906323b872dd60e01b906084016130ff565b50505050565b60006133048284614f95565b60006133048284614f73565b6000806147b584670de0b6b3a7640000614788565b90506138408184614794565b806001600160a01b03166147e16000805160206151718339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a360008051602061517183398151915255565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301526000928391614878919061509f565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156148ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149119190614ef6565b9050818111614924576000935050505090565b61492e8282614ecd565b935050505090565b60006133048383670de0b6b3a7640000614969565b60008183116146715781613304565b60606138408484600085614982565b6000806149768585614788565b9050613d3b8184614794565b6060824710156149e35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a72565b843b614a315760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a72565b600080866001600160a01b03168587604051614a4d9190615101565b60006040518083038185875af1925050503d8060008114614a8a576040519150601f19603f3d011682016040523d82523d6000602084013e614a8f565b606091505b5091509150614a9f828286614aaa565b979650505050505050565b60608315614ab9575081613304565b825115614ac95782518084602001fd5b8160405162461bcd60e51b8152600401610a72919061511d565b828054828255906000526020600020908101928215614b38579160200282015b82811115614b3857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614b03565b506130dc9291505b808211156130dc5760008155600101614b40565b600060208284031215614b6657600080fd5b5035919050565b80356001600160a01b0381168114614b8457600080fd5b919050565b60008060408385031215614b9c57600080fd5b614ba583614b6d565b946020939093013593505050565b600080600060608486031215614bc857600080fd5b614bd184614b6d565b95602085013595506040909401359392505050565b600060208284031215614bf857600080fd5b61330482614b6d565b602080825282518282018190526000918401906040840190835b81811015614c425783516001600160a01b0316835260209384019390920191600101614c1b565b509095945050505050565b60008083601f840112614c5f57600080fd5b5081356001600160401b03811115614c7657600080fd5b6020830191508360208260051b850101111561465b57600080fd5b60008060208385031215614ca457600080fd5b82356001600160401b03811115614cba57600080fd5b614cc685828601614c4d565b90969095509350505050565b6040808252835190820181905260009060208501906060840190835b81811015614d0c578351835260209384019390920191600101614cee565b5050602093909301939093525092915050565b600080600080600060608688031215614d3757600080fd5b614d4086614b6d565b945060208601356001600160401b03811115614d5b57600080fd5b614d6788828901614c4d565b90955093505060408601356001600160401b03811115614d8657600080fd5b614d9288828901614c4d565b969995985093965092949392505050565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60208082526015908201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115611a5057611a50614eb7565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614f0857600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215614f3757600080fd5b8151801515811461330457600080fd5b80820180821115611a5057611a50614eb7565b6001600160a01b03929092168252602082015260400190565b600082614f9057634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417611a5057611a50614eb7565b6001815b6001841115614fe757808504811115614fcb57614fcb614eb7565b6001841615614fd957908102905b60019390931c928002614fb0565b935093915050565b600082614ffe57506001611a50565b8161500b57506000611a50565b8160018114615021576002811461502b57615047565b6001915050611a50565b60ff84111561503c5761503c614eb7565b50506001821b611a50565b5060208310610133831016604e8410600b841016171561506a575081810a611a50565b6150776000198484614fac565b806000190482111561508b5761508b614eb7565b029392505050565b60006133048383614fef565b6001600160801b038281168282160390811115611a5057611a50614eb7565b6001600160801b038181168382160190811115611a5057611a50614eb7565b60005b838110156150f85781810151838201526020016150e0565b50506000910152565b600082516151138184602087016150dd565b9190910192915050565b602081526000825180602084015261513c8160408501602087016150dd565b601f01601f1916919091016040019291505056fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122069fc8e9ad996fa68679eaf8f924e0739be6ab2c68b05a438e34cfe17d5031eb864736f6c634300081c0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106104075760003560e01c8063663e64ce11610220578063ae69f3cb11610130578063c7af3352116100b8578063e6cc543211610087578063e6cc5432146109e5578063ea33b8e4146109f9578063f3f18c3714610a01578063f844443614610a14578063fac5bb9b14610a2757600080fd5b8063c7af3352146109ba578063c9919112146109c2578063d38bfff4146109ca578063d4c3eea0146109dd57600080fd5b8063b9b17f9f116100ff578063b9b17f9f14610975578063bb7a632e1461097d578063c3b2886414610997578063c4d66de81461099f578063c5f00841146109b257600080fd5b8063ae69f3cb14610934578063af14052c14610947578063b2c9336d1461094f578063b4925a201461096257600080fd5b806395b166bc116101b35780639fa1826e116101825780639fa1826e146108f6578063a0712d68146108ff578063a0aead4d14610912578063ab80dafb14610919578063abaa99161461092c57600080fd5b806395b166bc146108685780639be918e61461087b5780639e428552146108bb5780639ee679e8146108ce57600080fd5b80638e510b52116101ef5780638e510b521461079c5780638ec489a2146107a5578063937b2581146107b857806394828ffd1461086057600080fd5b8063663e64ce14610750578063773540b31461076357806378f353a114610776578063840c4c7a1461078957600080fd5b806339ebf8231161031b578063527e83a8116102ae5780635802a1721161027d5780635802a172146106fe578063597c89101461070f5780635d36b190146107225780635f5152261461072a5780636217f3ea1461073d57600080fd5b8063527e83a8146106aa57806353ca9f24146106c4578063570d8e1d146106d857806357bee944146106eb57600080fd5b806345e4213b116102ea57806345e4213b1461063b57806348e30f541461064457806349c1d54d146106655780634d5f46291461067857600080fd5b806339ebf823146105a95780633b8ae397146105ed5780633dbc911f146106005780634530820a1461060857600080fd5b80631a32aad61161039e5780632acada4d1161036d5780632acada4d146104f35780632da845a81461050857806331e19cfa1461051b578063362bd1a31461052357806338d52e0f1461058257600080fd5b80631a32aad6146104ad5780631cfbe7bc146104c05780631edfe3da146104d3578063207134b0146104ea57600080fd5b80631072cbea116103da5780631072cbea14610461578063156e29f614610474578063175188e8146104875780631816dd4a1461049a57600080fd5b80630493a0fa1461040c57806309f49bf5146104215780630acbda75146104295780630c340a241461043c575b600080fd5b61041f61041a366004614b54565b610a3a565b005b61041f610af0565b61041f610437366004614b54565b610b60565b610444610c0b565b6040516001600160a01b0390911681526020015b60405180910390f35b61041f61046f366004614b89565b610c28565b61041f610482366004614bb3565b610ce6565b61041f610495366004614be6565b610d59565b61041f6104a8366004614be6565b6110f7565b603c54610444906001600160a01b031681565b61041f6104ce366004614b54565b6111fe565b6104dc60395481565b604051908152602001610458565b6104dc60435481565b6104fb6112c0565b6040516104589190614c01565b61041f610516366004614be6565b611337565b6036546104dc565b604b54604c5461054f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610458565b6104447f000000000000000000000000000000000000000000000000000000000000000081565b6105d66105b7366004614be6565b6035602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610458565b61041f6105fb366004614be6565b6113a9565b61041f6115bc565b61062b610616366004614be6565b60496020526000908152604090205460ff1681565b6040519015158152602001610458565b6104dc604e5481565b610657610652366004614c91565b611632565b604051610458929190614cd2565b604254610444906001600160a01b031681565b604f5461069290600160c01b90046001600160401b031681565b6040516001600160401b039091168152602001610458565b604f5461069290600160801b90046001600160401b031681565b60375461062b90600160a01b900460ff1681565b603f54610444906001600160a01b031681565b61041f6106f9366004614be6565b6117a8565b603c546001600160a01b0316610444565b61041f61071d366004614be6565b61195b565b61041f61199f565b6104dc610738366004614be6565b611a45565b61041f61074b366004614b54565b611a56565b61041f61075e366004614b54565b611bda565b61041f610771366004614be6565b611c33565b604f54610692906001600160401b031681565b61041f610797366004614d1f565b611ca5565b6104dc60415481565b61041f6107b3366004614b54565b611d2c565b6108196107c6366004614b54565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a001610458565b61041f611de1565b61041f610876366004614be6565b611e51565b61062b610889366004614be6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b61041f6108c9366004614be6565b611f18565b6108e16108dc366004614b54565b611f8a565b60408051928352602083019190915201610458565b6104dc603a5481565b61041f61090d366004614b54565b6122ca565b60016104dc565b61041f610927366004614b54565b61233b565b61041f61248a565b61041f610942366004614d1f565b612502565b61041f61257e565b61041f61095d366004614b54565b612639565b61041f610970366004614b54565b612692565b61041f6127b0565b604f5461069290600160401b90046001600160401b031681565b6104fb6127b8565b61041f6109ad366004614be6565b61281a565b61041f6129c5565b61062b612a3b565b61041f612a6c565b61041f6109d8366004614be6565b612aac565b6104dc612b50565b60375461062b90600160a81b900460ff1681565b6104dc612b5a565b605154610444906001600160a01b031681565b6104dc610a22366004614b54565b612be9565b605054610444906001600160a01b031681565b603f546001600160a01b0316331480610a565750610a56612a3b565b610a7b5760405162461bcd60e51b8152600401610a7290614da3565b60405180910390fd5b610a83612cda565b50610a8d81613074565b604f80546001600160401b0392909216600160401b0267ffffffffffffffff60401b199092169190911790556040518181527f406e15fbca1d8ded2dbb06765fea3a54f18395c54125a4c9916dd00ea14ee15e906020015b60405180910390a150565b603f546001600160a01b0316331480610b0c5750610b0c612a3b565b610b285760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b610b68612a3b565b610b845760405162461bcd60e51b8152600401610a7290614deb565b611388811115610bd65760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f7420657863656564203530250000000000000000006044820152606401610a72565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c790602001610ae5565b6000610c236000805160206151718339815191525490565b905090565b610c30612a3b565b610c4c5760405162461bcd60e51b8152600401610a7290614deb565b816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610cc65760405162461bcd60e51b815260206004820152601660248201527513db9b1e481d5b9cdd5c1c1bdc9d195908185cdcd95d60521b6044820152606401610a72565b610ce2610cd1610c0b565b6001600160a01b03841690836130e0565b5050565b603754600160a81b900460ff1615610d105760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101610d425760405162461bcd60e51b8152600401610a7290614e4a565b60028255610d4f84613136565b5060019055505050565b610d61612a3b565b610d7d5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff16610db55760405162461bcd60e51b8152600401610a7290614e72565b6050546001600160a01b03808316911603610e125760405162461bcd60e51b815260206004820152601d60248201527f53747261746567792069732064656661756c7420666f722061737365740000006044820152606401610a72565b6036548060005b82811015610e6857836001600160a01b031660368281548110610e3e57610e3e614ea1565b6000918252602090912001546001600160a01b031603610e6057809150610e68565b600101610e19565b50818110156110f2576036610e7e600184614ecd565b81548110610e8e57610e8e614ea1565b600091825260209091200154603680546001600160a01b039092169183908110610eba57610eba614ea1565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610ef957610ef9614ee0565b6001900381819060005260206000200160006101000a8154906001600160a01b03021916905590556000839050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610f6157600080fd5b505af1158015610f75573d6000803e3d6000fd5b505050506001600160a01b0384166000908152603560209081526040808320805460ff199081169091556049909252822080549091169055610fe26509184e72a00060ff7f00000000000000000000000000000000000000000000000000000000000000001660126132a7565b604051632fa8a91360e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192508291841690635f51522690602401602060405180830381865afa15801561104d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110719190614ef6565b106110b35760405162461bcd60e51b81526020600482015260126024820152715374726174656779206861732066756e647360701b6044820152606401610a72565b6040516001600160a01b03861681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49060200160405180910390a150505b505050565b6110ff612a3b565b61111b5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff166111535760405162461bcd60e51b8152600401610a7290614e72565b6001600160a01b03811660009081526049602052604090205460ff16156111b25760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481dda1a5d195b1a5cdd1959606a1b6044820152606401610a72565b6001600160a01b038116600081815260496020526040808220805460ff19166001179055517f47c8c96a5942f094264111c5fe7f6a4fe86efe63254a6fa7afa5fc84f07d58e89190a250565b611206612a3b565b6112225760405162461bcd60e51b8152600401610a7290614deb565b80158061123f5750610258811015801561123f57506213c6808111155b61128b5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636c61696d2064656c617920706572696f640000000000006044820152606401610a72565b604e8190556040518181527fc59f5e32049abab44ddea11021f5abb89422a2f550837afcf25df9fc8d0db6b090602001610ae5565b60408051600180825281830190925260609160009190602080830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061131a5761131a614ea1565b6001600160a01b0390921660209283029190910190910152919050565b61133f612a3b565b61135b5760405162461bcd60e51b8152600401610a7290614deb565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610ae5565b6113b1612a3b565b6113cd5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff16156114365760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f766564000000000000006044820152606401610a72565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa15801561149c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c09190614f25565b61150c5760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a72565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610ae5565b603f546001600160a01b03163314806115d857506115d8612a3b565b6115f45760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b603754606090600090600160a81b900460ff16156116625760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016116945760405162461bcd60e51b8152600401610a7290614e4a565b600282556116a061330b565b50846001600160401b038111156116b9576116b9614f0f565b6040519080825280602002602001820160405280156116e2578160200160208202803683370190505b50935060005b8581101561175e5761171187878381811061170557611705614ea1565b905060200201356134e7565b85828151811061172357611723614ea1565b60200260200101818152505084818151811061174157611741614ea1565b6020026020010151846117549190614f47565b93506001016116e8565b506117936001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130e0565b61179b613848565b6001825550509250929050565b603f546001600160a01b03163314806117c457506117c4612a3b565b6117e05760405162461bcd60e51b8152600401610a7290614da3565b6040516001600160a01b03821681527f45a9e715f8779ebeab88d3e8d081fb8b484b7730857e7c4478a95a5b1d8f79489060200160405180910390a16001600160a01b03811615611939576001600160a01b03811660009081526035602052604090205460ff166118635760405162461bcd60e51b8152600401610a7290614e72565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa1580156118c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ed9190614f25565b6119395760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a72565b605080546001600160a01b0319166001600160a01b0392909216919091179055565b603f546001600160a01b03163314806119775750611977612a3b565b6119935760405162461bcd60e51b8152600401610a7290614da3565b61199c816139bb565b50565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614611a3a5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610a72565b611a4333613a83565b565b6000611a5082613ae2565b92915050565b603754600160a81b900460ff1615611a805760405162461bcd60e51b8152600401610a7290614e22565b3360009081526035602052604090205460ff161515600114611adb5760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a72565b3360009081526049602052604090205460ff161515600114611b3a5760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a72565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051611b6b929190614f5a565b60405180910390a1603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90611ba59033908590600401614f5a565b600060405180830381600087803b158015611bbf57600080fd5b505af1158015611bd3573d6000803e3d6000fd5b5050505050565b611be2612a3b565b611bfe5760405162461bcd60e51b8152600401610a7290614deb565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610ae5565b611c3b612a3b565b611c575760405162461bcd60e51b8152600401610a7290614deb565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610ae5565b603f546001600160a01b0316331480611cc15750611cc1612a3b565b611cdd5760405162461bcd60e51b8152600401610a7290614da3565b60008051602061515183398151915280546001198101611d0f5760405162461bcd60e51b8152600401610a7290614e4a565b60028255611d208787878787613d44565b50600190555050505050565b603f546001600160a01b0316331480611d485750611d48612a3b565b611d645760405162461bcd60e51b8152600401610a7290614da3565b670de0b6b3a7640000811115611dac5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b6044820152606401610a72565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610ae5565b603f546001600160a01b0316331480611dfd5750611dfd612a3b565b611e195760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e59612a3b565b611e755760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526049602052604090205460ff16611ecf5760405162461bcd60e51b815260206004820152600f60248201526e139bdd081dda1a5d195b1a5cdd1959608a1b6044820152606401610a72565b6001600160a01b038116600081815260496020526040808220805460ff19169055517f0ec40967a61509853550658e51d0e4297f7cba244fe4adc8ba18b5631ac20e2f9190a250565b611f20612a3b565b611f3c5760405162461bcd60e51b8152600401610a7290614deb565b605180546001600160a01b0319166001600160a01b0383169081179091556040519081527fb3b3f5f64ab192e4b5fefde1f51ce9733bbdcf831951543b325aebd49cc27ec490602001610ae5565b6037546000908190600160a81b900460ff1615611fb95760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101611feb5760405162461bcd60e51b8152600401610a7290614e4a565b600282556000851161203f5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a72565b6000604e54116120915760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a72565b604c54600160801b90046001600160801b031693506120d5857f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b604b546120eb91906001600160801b0316614f47565b92506121006120fb856001614f47565b613f83565b604c80546001600160801b03928316600160801b02921691909117905561212683613f83565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff16918101919091526060810161217687613f83565b6001600160801b0316815260200161218d85613f83565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906122489033908990600401614f5a565b600060405180830381600087803b15801561226257600080fd5b505af1158015612276573d6000803e3d6000fd5b50505050612282613848565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff16156122f45760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016123265760405162461bcd60e51b8152600401610a7290614e4a565b6002825561233383613136565b506001905550565b603754600160a81b900460ff16156123655760405162461bcd60e51b8152600401610a7290614e22565b3360009081526035602052604090205460ff1615156001146123c05760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a72565b3360009081526049602052604090205460ff16151560011461241f5760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a72565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853382604051612450929190614f5a565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611ba59033908590600401614f5a565b603754600160a81b900460ff16156124b45760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016124e65760405162461bcd60e51b8152600401610a7290614e4a565b600282556124f261330b565b506124fb613fec565b5060019055565b603f546001600160a01b031633148061251e575061251e612a3b565b61253a5760405162461bcd60e51b8152600401610a7290614da3565b6000805160206151518339815191528054600119810161256c5760405162461bcd60e51b8152600401610a7290614e4a565b60028255611d20308888888888614215565b600080516020615151833981519152805460011981016125b05760405162461bcd60e51b8152600401610a7290614e4a565b600282556051546001600160a01b03163314806125d75750603f546001600160a01b031633145b806125e557506125e5612a3b565b6126295760405162461bcd60e51b815260206004820152601560248201527410d85b1b195c881b9bdd08185d5d1a1bdc9a5e9959605a1b6044820152606401610a72565b612631612cda565b505060019055565b612641612a3b565b61265d5760405162461bcd60e51b8152600401610a7290614deb565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610ae5565b603f546001600160a01b03163314806126ae57506126ae612a3b565b6126ca5760405162461bcd60e51b8152600401610a7290614da3565b6126d2612cda565b5060006301e133806126e5606484614f73565b6126ef9190614f73565b90506127056201518066b1a2bc2ec50000614f73565b8111156127445760405162461bcd60e51b815260206004820152600d60248201526c0a4c2e8ca40e8dede40d0d2ced609b1b6044820152606401610a72565b61274d81613074565b604f80546001600160401b0392909216600160801b0267ffffffffffffffff60801b199092169190911790556040518181527fef46f143af5fead0010484fe7d6ec2e2972420faa76157f5a6075aa72e614cb59060200160405180910390a15050565b61199c61330b565b6060603680548060200260200160405190810160405280929190818152602001828054801561281057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116127f2575b5050505050905090565b612822612a3b565b61283e5760405162461bcd60e51b8152600401610a7290614deb565b600054610100900460ff1680612857575060005460ff16155b6128ba5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a72565b600054610100900460ff161580156128dc576000805461ffff19166101011790555b6001600160a01b03821661292b5760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b6044820152606401610a72565b603c80546001600160a01b0384166001600160a01b03199091161790556037805461ffff60a01b1916600160a81b1790556000603981905569054b40b1f852bda00000603a55604080519182526020820190819052905161298e91603691614ae3565b50604f805467ffffffffffffffff60401b19166a093a8000000000000000001790558015610ce2576000805461ff00191690555050565b603f546001600160a01b03163314806129e157506129e1612a3b565b6129fd5760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b6000612a536000805160206151718339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612a885750612a88612a3b565b612aa45760405162461bcd60e51b8152600401610a7290614da3565b611a436143a6565b612ab4612a3b565b612ad05760405162461bcd60e51b8152600401610a7290614deb565b612af8817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612b186000805160206151718339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000610c2361443b565b6000612be3603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd69190614ef6565b612bde61443b565b61448f565b50919050565b603754600090600160a81b900460ff1615612c165760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101612c485760405162461bcd60e51b8152600401610a7290614e4a565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115612c8957612c8761330b565b505b612c92846134e7565b9250612cc86001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130e0565b612cd0613848565b5060019055919050565b603754600090600160a01b900460ff1615612d295760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b6044820152606401610a72565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612d73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d979190614ef6565b90506000612da361443b565b905081600003612db65791506130719050565b600080612dc3848461448f565b90925090506000612dd48386614f47565b90508481111580612de457508381115b15612df3575091949350505050565b612e04826001600160401b03614662565b604f805477ffffffffffffffffffffffffffffffff000000000000000016600160c01b6001600160401b039384160267ffffffffffffffff19161742929092169190911790556042546001600160a01b031660008115612f405761271060435486612e6f9190614f95565b612e799190614f73565b90508015612f4057848110612edb5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b6064820152608401610a72565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612f0d9085908590600401614f5a565b600060405180830381600087803b158015612f2757600080fd5b505af1158015612f3b573d6000803e3d6000fd5b505050505b604080516001600160a01b0384168152602081018790529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a1603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fdd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130019190614ef6565b83111561306757603c546040516339a7919f60e01b8152600481018590526001600160a01b03909116906339a7919f90602401600060405180830381600087803b15801561304e57600080fd5b505af1158015613062573d6000803e3d6000fd5b505050505b5093955050505050505b90565b60006001600160401b038211156130dc5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610a72565b5090565b6110f28363a9059cbb60e01b84846040516024016130ff929190614f5a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614678565b600081116131865760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a72565b60006131b782601260ff7f0000000000000000000000000000000000000000000000000000000000000000166132a7565b90507f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516131ea929190614f5a565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132249033908590600401614f5a565b600060405180830381600087803b15801561323e57600080fd5b505af1158015613252573d6000803e3d6000fd5b5061328d9250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016905033308561474a565b61329561330b565b50603a548110610ce257610ce2613fec565b6000818311156132d7576132d06132be8385614ecd565b6132c990600a615093565b8590614788565b9350613301565b81831015613301576132fe6132ec8484614ecd565b6132f790600a615093565b8590614794565b93505b50825b9392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c548084169686019690965292909404166060830152600092839161335d9161509f565b6001600160801b03169050806000036133795760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156133e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134049190614ef6565b905060008360400151846020015161341c919061509f565b6001600160801b0316905080821161343957600094505050505090565b60006134458284614ecd565b90508084106134545780613456565b835b955060008686602001516001600160801b03166134739190614f47565b905061347e81613f83565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f463333906134d69083908a90918252602082015260400190565b60405180910390a150505050505090565b600080604e541161353a5760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a72565b6000828152604d6020908152604091829020825160a08101845281546001600160a01b038116825260ff600160a01b82041615158285015264ffffffffff600160a81b90910481168286019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915288519081018952604b548084168252849004831697810197909752604c54808316988801989098529190960490951694840194909452604e5491519093429261360192909116614f47565b11156136455760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b6044820152606401610a72565b80602001516001600160801b031682608001516001600160801b031611156136af5760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c69717569646974790000000000000000006044820152606401610a72565b81516001600160a01b031633146136f85760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b6044820152606401610a72565b60208201511561373c5760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b6044820152606401610a72565b6000848152604d60205260409020805460ff60a01b1916600160a01b179055606082015161379c906120fb906001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b81604001516137ab91906150be565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a361384082606001516001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b949350505050565b600061385261443b565b6041549091501561199c57600081116138ad5760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e672072657175657374730000006044820152606401610a72565b600061393082603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613906573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061392a9190614ef6565b906147a0565b9050604154670de0b6b3a7640000821161395b5761395682670de0b6b3a7640000614ecd565b61396d565b61396d670de0b6b3a764000083614ecd565b1115610ce25760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f7200006044820152606401610a72565b6001600160a01b03811660009081526035602052604090205460ff16613a235760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f72746564000000000000006044820152606401610a72565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a6357600080fd5b505af1158015613a77573d6000803e3d6000fd5b505050506110f261330b565b6001600160a01b038116613ad95760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610a72565b61199c816147c1565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614613b2557506000919050565b6040516370a0823160e01b815230600482015282906001600160a01b038216906370a0823190602401602060405180830381865afa158015613b6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b8f9190614ef6565b60365490925060005b81811015613cb457600060368281548110613bb557613bb5614ea1565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af690602401602060405180830381865afa158015613c0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c2f9190614f25565b15613cab57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f51522690602401602060405180830381865afa158015613c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c9e9190614ef6565b613ca89086614f47565b94505b50600101613b98565b5060408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529091613d029086614f47565b1015613d1357506000949350505050565b805160408201516001600160801b0391821691613d31911686614f47565b613d3b9190614ecd565b95945050505050565b6001600160a01b03851660009081526035602052604090205460ff16613da25760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b6044820152606401610a72565b600183148015613db25750600181145b8015613e1657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684846000818110613df657613df6614ea1565b9050602002016020810190613e0b9190614be6565b6001600160a01b0316145b613e625760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920617373657420697320737570706f727465640000000000000000006044820152606401610a72565b613e6a614828565b82826000818110613e7d57613e7d614ea1565b905060200201351115613ed25760405162461bcd60e51b815260206004820152601b60248201527f4e6f7420656e6f7567682061737365747320617661696c61626c6500000000006044820152606401610a72565b613f298583836000818110613ee957613ee9614ea1565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166130e09092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613f6457600080fd5b505af1158015613f78573d6000803e3d6000fd5b505050505050505050565b60006001600160801b038211156130dc5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610a72565b6050546001600160a01b0316806140005750565b600061400a614828565b905080600003614018575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015614062573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140869190614ef6565b905060006140cf7f000000000000000000000000000000000000000000000000000000000000000060ff1660126140c86039548661493690919063ffffffff16565b91906132a7565b90508083116140de5750505050565b60006140ea8285614ecd565b9050846141216001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682846130e0565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061416f907f0000000000000000000000000000000000000000000000000000000000000000908690600401614f5a565b600060405180830381600087803b15801561418957600080fd5b505af115801561419d573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b6001600160a01b03851660009081526035602052604090205460ff166142755760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b6044820152606401610a72565b8281146142c45760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d61746368000000000000006044820152606401610a72565b8260005b8181101561439357866001600160a01b031663d9caed12898888858181106142f2576142f2614ea1565b90506020020160208101906143079190614be6565b87878681811061431957614319614ea1565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561437057600080fd5b505af1158015614384573d6000803e3d6000fd5b505050508060010190506142c8565b5061439c61330b565b5050505050505050565b60365460005b8181101561443257603681815481106143c7576143c7614ea1565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b15801561440f57600080fd5b505af1158015614423573d6000803e3d6000fd5b505050508060010190506143ac565b50610ce261330b565b6000610c2360127f000000000000000000000000000000000000000000000000000000000000000060ff166140c87f0000000000000000000000000000000000000000000000000000000000000000613ae2565b6000806000603c60009054906101000a90046001600160a01b03166001600160a01b031663e696393a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156144e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061450b9190614ef6565b905060006145198287614ecd565b604f54909150600090614535906001600160401b031642614ecd565b604f54600160c01b90046001600160401b031694509050801580614557575081155b8061456157508587115b8061457357506001600160401b034210155b15614584576000945050505061465b565b61458e8787614ecd565b604f54909550600160401b90046001600160401b031660018111156145f3576145cb856145bc836002614f95565b6145c69089614f73565b61494b565b94506145e0856145db8389614f73565b614662565b94506145f0866145db8488614f95565b95505b604f54614634908790670de0b6b3a764000090600160801b90046001600160401b03166146208688614f95565b61462a9190614f95565b6145db9190614f73565b955061465486670de0b6b3a764000061462a66470de4df82000087614f95565b9550505050505b9250929050565b60008183106146715781613304565b5090919050565b60006146cd826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661495a9092919063ffffffff16565b8051909150156110f257808060200190518101906146eb9190614f25565b6110f25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a72565b6040516001600160a01b03808516602483015283166044820152606481018290526147829085906323b872dd60e01b906084016130ff565b50505050565b60006133048284614f95565b60006133048284614f73565b6000806147b584670de0b6b3a7640000614788565b90506138408184614794565b806001600160a01b03166147e16000805160206151718339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a360008051602061517183398151915255565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301526000928391614878919061509f565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156148ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149119190614ef6565b9050818111614924576000935050505090565b61492e8282614ecd565b935050505090565b60006133048383670de0b6b3a7640000614969565b60008183116146715781613304565b60606138408484600085614982565b6000806149768585614788565b9050613d3b8184614794565b6060824710156149e35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a72565b843b614a315760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a72565b600080866001600160a01b03168587604051614a4d9190615101565b60006040518083038185875af1925050503d8060008114614a8a576040519150601f19603f3d011682016040523d82523d6000602084013e614a8f565b606091505b5091509150614a9f828286614aaa565b979650505050505050565b60608315614ab9575081613304565b825115614ac95782518084602001fd5b8160405162461bcd60e51b8152600401610a72919061511d565b828054828255906000526020600020908101928215614b38579160200282015b82811115614b3857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614b03565b506130dc9291505b808211156130dc5760008155600101614b40565b600060208284031215614b6657600080fd5b5035919050565b80356001600160a01b0381168114614b8457600080fd5b919050565b60008060408385031215614b9c57600080fd5b614ba583614b6d565b946020939093013593505050565b600080600060608486031215614bc857600080fd5b614bd184614b6d565b95602085013595506040909401359392505050565b600060208284031215614bf857600080fd5b61330482614b6d565b602080825282518282018190526000918401906040840190835b81811015614c425783516001600160a01b0316835260209384019390920191600101614c1b565b509095945050505050565b60008083601f840112614c5f57600080fd5b5081356001600160401b03811115614c7657600080fd5b6020830191508360208260051b850101111561465b57600080fd5b60008060208385031215614ca457600080fd5b82356001600160401b03811115614cba57600080fd5b614cc685828601614c4d565b90969095509350505050565b6040808252835190820181905260009060208501906060840190835b81811015614d0c578351835260209384019390920191600101614cee565b5050602093909301939093525092915050565b600080600080600060608688031215614d3757600080fd5b614d4086614b6d565b945060208601356001600160401b03811115614d5b57600080fd5b614d6788828901614c4d565b90955093505060408601356001600160401b03811115614d8657600080fd5b614d9288828901614c4d565b969995985093965092949392505050565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60208082526015908201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115611a5057611a50614eb7565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614f0857600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215614f3757600080fd5b8151801515811461330457600080fd5b80820180821115611a5057611a50614eb7565b6001600160a01b03929092168252602082015260400190565b600082614f9057634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417611a5057611a50614eb7565b6001815b6001841115614fe757808504811115614fcb57614fcb614eb7565b6001841615614fd957908102905b60019390931c928002614fb0565b935093915050565b600082614ffe57506001611a50565b8161500b57506000611a50565b8160018114615021576002811461502b57615047565b6001915050611a50565b60ff84111561503c5761503c614eb7565b50506001821b611a50565b5060208310610133831016604e8410600b841016171561506a575081810a611a50565b6150776000198484614fac565b806000190482111561508b5761508b614eb7565b029392505050565b60006133048383614fef565b6001600160801b038281168282160390811115611a5057611a50614eb7565b6001600160801b038181168382160190811115611a5057611a50614eb7565b60005b838110156150f85781810151838201526020016150e0565b50506000910152565b600082516151138184602087016150dd565b9190910192915050565b602081526000825180602084015261513c8160408501602087016150dd565b601f01601f1916919091016040019291505056fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122069fc8e9ad996fa68679eaf8f924e0739be6ab2c68b05a438e34cfe17d5031eb864736f6c634300081c0033", "libraries": {}, "devdoc": { "author": "Origin Protocol Inc", @@ -1518,6 +1518,9 @@ "yield": "amount of expected yield" } }, + "rebase()": { + "details": "Restricted to the Operator, Strategist or Governor." + }, "removeStrategy(address)": { "params": { "_addr": "Address of the strategy to remove" @@ -1552,14 +1555,14 @@ "_dripDuration": "Time in seconds to target a constant yield rate" } }, - "setRebaseRateMax(uint256)": { + "setOperatorAddr(address)": { "params": { - "apr": "in 1e18 notation. 3 * 1e18 = 3% APR" + "_operator": "New operator address. May be set to the zero address to disable operator-initiated rebases." } }, - "setRebaseThreshold(uint256)": { + "setRebaseRateMax(uint256)": { "params": { - "_threshold": "OToken amount with 18 fixed decimals." + "apr": "in 1e18 notation. 3 * 1e18 = 3% APR" } }, "setStrategistAddr(address)": { @@ -1693,6 +1696,9 @@ "oUSD()": { "notice": "Deprecated: use `oToken()` instead." }, + "operatorAddr()": { + "notice": "Address authorized to call `rebase()` directly. The Governor and Strategist are always allowed in addition to this address." + }, "pauseCapital()": { "notice": "Set the deposit paused flag to true to prevent capital movement." }, @@ -1714,9 +1720,6 @@ "rebasePerSecondTarget()": { "notice": "target rebase rate limit, based on past rates and funds available." }, - "rebaseThreshold()": { - "notice": "OToken mints over this amount automatically rebase. 18 decimals." - }, "removeStrategy(address)": { "notice": "Remove a strategy from the Vault." }, @@ -1738,12 +1741,12 @@ "setMaxSupplyDiff(uint256)": { "notice": "Sets the maximum allowable difference between total supply and asset' value." }, + "setOperatorAddr(address)": { + "notice": "Set the address authorized to call `rebase()`." + }, "setRebaseRateMax(uint256)": { "notice": "Set a yield streaming max rate. This spreads yield over time if it is above the max rate. This is a per rebase APR which due to compounding differs from the yearly APR. Governance should consider this fact when picking a desired APR" }, - "setRebaseThreshold(uint256)": { - "notice": "Set a minimum amount of OTokens in a mint or redeem that triggers a rebase" - }, "setStrategistAddr(address)": { "notice": "Set address of Strategist" }, @@ -1810,7 +1813,7 @@ "storageLayout": { "storage": [ { - "astId": 40537, + "astId": 42033, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "initialized", "offset": 0, @@ -1818,7 +1821,7 @@ "type": "t_bool" }, { - "astId": 40540, + "astId": 42036, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "initializing", "offset": 1, @@ -1826,7 +1829,7 @@ "type": "t_bool" }, { - "astId": 40580, + "astId": 42076, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "______gap", "offset": 0, @@ -1834,7 +1837,7 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 44284, + "astId": 45777, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "_deprecated_assets", "offset": 0, @@ -1842,7 +1845,7 @@ "type": "t_uint256" }, { - "astId": 44288, + "astId": 45781, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "_deprecated_allAssets", "offset": 0, @@ -1850,15 +1853,15 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 44299, + "astId": 45792, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "strategies", "offset": 0, "slot": "53", - "type": "t_mapping(t_address,t_struct(Strategy)44293_storage)" + "type": "t_mapping(t_address,t_struct(Strategy)45786_storage)" }, { - "astId": 44303, + "astId": 45796, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "allStrategies", "offset": 0, @@ -1866,7 +1869,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 44306, + "astId": 45799, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "_deprecated_priceProvider", "offset": 0, @@ -1874,7 +1877,7 @@ "type": "t_address" }, { - "astId": 44309, + "astId": 45802, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "rebasePaused", "offset": 20, @@ -1882,7 +1885,7 @@ "type": "t_bool" }, { - "astId": 44312, + "astId": 45805, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "capitalPaused", "offset": 21, @@ -1890,7 +1893,7 @@ "type": "t_bool" }, { - "astId": 44315, + "astId": 45808, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "_deprecated_redeemFeeBps", "offset": 0, @@ -1898,7 +1901,7 @@ "type": "t_uint256" }, { - "astId": 44318, + "astId": 45811, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "vaultBuffer", "offset": 0, @@ -1906,7 +1909,7 @@ "type": "t_uint256" }, { - "astId": 44321, + "astId": 45814, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "autoAllocateThreshold", "offset": 0, @@ -1914,23 +1917,23 @@ "type": "t_uint256" }, { - "astId": 44324, + "astId": 45817, "contract": "contracts/vault/OETHVault.sol:OETHVault", - "label": "rebaseThreshold", + "label": "__deprecatedRebaseThreshold", "offset": 0, "slot": "59", "type": "t_uint256" }, { - "astId": 44328, + "astId": 45821, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "oToken", "offset": 0, "slot": "60", - "type": "t_contract(OUSD)39858" + "type": "t_contract(OUSD)41354" }, { - "astId": 44335, + "astId": 45828, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "_deprecated_rebaseHooksAddr", "offset": 0, @@ -1938,7 +1941,7 @@ "type": "t_address" }, { - "astId": 44342, + "astId": 45835, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "_deprecated_uniswapAddr", "offset": 0, @@ -1946,7 +1949,7 @@ "type": "t_address" }, { - "astId": 44349, + "astId": 45842, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "strategistAddr", "offset": 0, @@ -1954,7 +1957,7 @@ "type": "t_address" }, { - "astId": 44352, + "astId": 45845, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "_deprecated_assetDefaultStrategies", "offset": 0, @@ -1962,7 +1965,7 @@ "type": "t_uint256" }, { - "astId": 44355, + "astId": 45848, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "maxSupplyDiff", "offset": 0, @@ -1970,7 +1973,7 @@ "type": "t_uint256" }, { - "astId": 44358, + "astId": 45851, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "trusteeAddress", "offset": 0, @@ -1978,7 +1981,7 @@ "type": "t_address" }, { - "astId": 44361, + "astId": 45854, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "trusteeFeeBps", "offset": 0, @@ -1986,7 +1989,7 @@ "type": "t_uint256" }, { - "astId": 44365, + "astId": 45858, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "_deprecated_swapTokens", "offset": 0, @@ -1994,7 +1997,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 44368, + "astId": 45861, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "_deprecated_ousdMetaStrategy", "offset": 0, @@ -2002,7 +2005,7 @@ "type": "t_address" }, { - "astId": 44371, + "astId": 45864, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "_deprecated_netOusdMintedForStrategy", "offset": 0, @@ -2010,7 +2013,7 @@ "type": "t_int256" }, { - "astId": 44374, + "astId": 45867, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "_deprecated_netOusdMintForStrategyThreshold", "offset": 0, @@ -2018,7 +2021,7 @@ "type": "t_uint256" }, { - "astId": 44376, + "astId": 45869, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "_deprecated_swapConfig", "offset": 0, @@ -2026,7 +2029,7 @@ "type": "t_uint256" }, { - "astId": 44380, + "astId": 45873, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "isMintWhitelistedStrategy", "offset": 0, @@ -2034,7 +2037,7 @@ "type": "t_mapping(t_address,t_bool)" }, { - "astId": 44383, + "astId": 45876, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "_deprecated_dripper", "offset": 0, @@ -2042,23 +2045,23 @@ "type": "t_address" }, { - "astId": 44397, + "astId": 45890, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "withdrawalQueueMetadata", "offset": 0, "slot": "75", - "type": "t_struct(WithdrawalQueueMetadata)44393_storage" + "type": "t_struct(WithdrawalQueueMetadata)45886_storage" }, { - "astId": 44414, + "astId": 45907, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "withdrawalRequests", "offset": 0, "slot": "77", - "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)44408_storage)" + "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)45901_storage)" }, { - "astId": 44417, + "astId": 45910, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "withdrawalClaimDelay", "offset": 0, @@ -2066,7 +2069,7 @@ "type": "t_uint256" }, { - "astId": 44420, + "astId": 45913, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "lastRebase", "offset": 0, @@ -2074,7 +2077,7 @@ "type": "t_uint64" }, { - "astId": 44423, + "astId": 45916, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "dripDuration", "offset": 8, @@ -2082,7 +2085,7 @@ "type": "t_uint64" }, { - "astId": 44426, + "astId": 45919, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "rebasePerSecondMax", "offset": 16, @@ -2090,7 +2093,7 @@ "type": "t_uint64" }, { - "astId": 44429, + "astId": 45922, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "rebasePerSecondTarget", "offset": 24, @@ -2098,7 +2101,7 @@ "type": "t_uint64" }, { - "astId": 44443, + "astId": 45936, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "defaultStrategy", "offset": 0, @@ -2106,15 +2109,23 @@ "type": "t_address" }, { - "astId": 44447, + "astId": 45939, "contract": "contracts/vault/OETHVault.sol:OETHVault", - "label": "__gap", + "label": "operatorAddr", "offset": 0, "slot": "81", - "type": "t_array(t_uint256)42_storage" + "type": "t_address" + }, + { + "astId": 45943, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "__gap", + "offset": 0, + "slot": "82", + "type": "t_array(t_uint256)41_storage" }, { - "astId": 44450, + "astId": 45946, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "_deprecated_wethAssetIndex", "offset": 0, @@ -2134,11 +2145,11 @@ "label": "address[]", "numberOfBytes": "32" }, - "t_array(t_uint256)42_storage": { + "t_array(t_uint256)41_storage": { "base": "t_uint256", "encoding": "inplace", - "label": "uint256[42]", - "numberOfBytes": "1344" + "label": "uint256[41]", + "numberOfBytes": "1312" }, "t_array(t_uint256)50_storage": { "base": "t_uint256", @@ -2151,7 +2162,7 @@ "label": "bool", "numberOfBytes": "1" }, - "t_contract(OUSD)39858": { + "t_contract(OUSD)41354": { "encoding": "inplace", "label": "contract OUSD", "numberOfBytes": "20" @@ -2168,26 +2179,26 @@ "numberOfBytes": "32", "value": "t_bool" }, - "t_mapping(t_address,t_struct(Strategy)44293_storage)": { + "t_mapping(t_address,t_struct(Strategy)45786_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct VaultStorage.Strategy)", "numberOfBytes": "32", - "value": "t_struct(Strategy)44293_storage" + "value": "t_struct(Strategy)45786_storage" }, - "t_mapping(t_uint256,t_struct(WithdrawalRequest)44408_storage)": { + "t_mapping(t_uint256,t_struct(WithdrawalRequest)45901_storage)": { "encoding": "mapping", "key": "t_uint256", "label": "mapping(uint256 => struct VaultStorage.WithdrawalRequest)", "numberOfBytes": "32", - "value": "t_struct(WithdrawalRequest)44408_storage" + "value": "t_struct(WithdrawalRequest)45901_storage" }, - "t_struct(Strategy)44293_storage": { + "t_struct(Strategy)45786_storage": { "encoding": "inplace", "label": "struct VaultStorage.Strategy", "members": [ { - "astId": 44290, + "astId": 45783, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "isSupported", "offset": 0, @@ -2195,7 +2206,7 @@ "type": "t_bool" }, { - "astId": 44292, + "astId": 45785, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "_deprecated", "offset": 0, @@ -2205,12 +2216,12 @@ ], "numberOfBytes": "64" }, - "t_struct(WithdrawalQueueMetadata)44393_storage": { + "t_struct(WithdrawalQueueMetadata)45886_storage": { "encoding": "inplace", "label": "struct VaultStorage.WithdrawalQueueMetadata", "members": [ { - "astId": 44386, + "astId": 45879, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "queued", "offset": 0, @@ -2218,7 +2229,7 @@ "type": "t_uint128" }, { - "astId": 44388, + "astId": 45881, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "claimable", "offset": 16, @@ -2226,7 +2237,7 @@ "type": "t_uint128" }, { - "astId": 44390, + "astId": 45883, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "claimed", "offset": 0, @@ -2234,7 +2245,7 @@ "type": "t_uint128" }, { - "astId": 44392, + "astId": 45885, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "nextWithdrawalIndex", "offset": 16, @@ -2244,12 +2255,12 @@ ], "numberOfBytes": "64" }, - "t_struct(WithdrawalRequest)44408_storage": { + "t_struct(WithdrawalRequest)45901_storage": { "encoding": "inplace", "label": "struct VaultStorage.WithdrawalRequest", "members": [ { - "astId": 44399, + "astId": 45892, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "withdrawer", "offset": 0, @@ -2257,7 +2268,7 @@ "type": "t_address" }, { - "astId": 44401, + "astId": 45894, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "claimed", "offset": 20, @@ -2265,7 +2276,7 @@ "type": "t_bool" }, { - "astId": 44403, + "astId": 45896, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "timestamp", "offset": 21, @@ -2273,7 +2284,7 @@ "type": "t_uint40" }, { - "astId": 44405, + "astId": 45898, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "amount", "offset": 0, @@ -2281,7 +2292,7 @@ "type": "t_uint128" }, { - "astId": 44407, + "astId": 45900, "contract": "contracts/vault/OETHVault.sol:OETHVault", "label": "queued", "offset": 16, diff --git a/contracts/deployments/mainnet/OUSDVault.json b/contracts/deployments/mainnet/OUSDVault.json index ea0ee9ebe6..a717d6d11a 100644 --- a/contracts/deployments/mainnet/OUSDVault.json +++ b/contracts/deployments/mainnet/OUSDVault.json @@ -1,5 +1,5 @@ { - "address": "0xE3A9F4eDaF8aBD275Beea7e6a19fDbE6B314578e", + "address": "0x82948060c4B72684bEdEdec342350AB344975145", "abi": [ { "inputs": [ @@ -139,6 +139,19 @@ "name": "Mint", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newOperator", + "type": "address" + } + ], + "name": "OperatorUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -177,19 +190,6 @@ "name": "RebasePerSecondMaxChanged", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "_threshold", - "type": "uint256" - } - ], - "name": "RebaseThresholdUpdated", - "type": "event" - }, { "anonymous": false, "inputs": [], @@ -872,6 +872,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "operatorAddr", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "pauseCapital", @@ -945,19 +958,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "rebaseThreshold", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -1063,12 +1063,12 @@ { "inputs": [ { - "internalType": "uint256", - "name": "apr", - "type": "uint256" + "internalType": "address", + "name": "_operator", + "type": "address" } ], - "name": "setRebaseRateMax", + "name": "setOperatorAddr", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -1077,11 +1077,11 @@ "inputs": [ { "internalType": "uint256", - "name": "_threshold", + "name": "apr", "type": "uint256" } ], - "name": "setRebaseThreshold", + "name": "setRebaseRateMax", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -1409,30 +1409,30 @@ "type": "function" } ], - "transactionHash": "0xa361816fd836104b056b300916eba6be18d0c0234466b3545bf2718a589775cf", + "transactionHash": "0x43960e43f6c2de3f160268c2e82250b7c17502261965d57ac8c60631788555be", "receipt": { "to": null, - "from": "0x074105fdD39e982B2ffE749A193c942db1046AB9", - "contractAddress": "0xE3A9F4eDaF8aBD275Beea7e6a19fDbE6B314578e", - "transactionIndex": 16, - "gasUsed": "4601180", + "from": "0x58890A9cB27586E83Cb51d2d26bbE18a1a647245", + "contractAddress": "0x82948060c4B72684bEdEdec342350AB344975145", + "transactionIndex": 41, + "gasUsed": "4594937", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xc0b4bd2c584a48acacf82e025883875e25f323367d309ce5ff8d99fb3895623b", - "transactionHash": "0xa361816fd836104b056b300916eba6be18d0c0234466b3545bf2718a589775cf", + "blockHash": "0x4ddfe068ede840bf370a9fe0cb75539f8ccc680aad51c7c24681ea6b8fa25663", + "transactionHash": "0x43960e43f6c2de3f160268c2e82250b7c17502261965d57ac8c60631788555be", "logs": [], - "blockNumber": 24426857, - "cumulativeGasUsed": "10347312", + "blockNumber": 25063935, + "cumulativeGasUsed": "7057525", "status": 1, "byzantium": true }, "args": [ "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" ], - "numDeployments": 1, - "solcInputHash": "246907a3fd0d7c6bfd72156e1588273e", - "metadata": "{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_usdc\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"AllocateThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"AssetAllocated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"DefaultStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dripDuration\",\"type\":\"uint256\"}],\"name\":\"DripDurationChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"MaxSupplyDiffChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebasePaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rebaseRatePerSecond\",\"type\":\"uint256\"}],\"name\":\"RebasePerSecondMaxChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"RebaseThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebaseUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"StrategistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyAddedToMintWhitelist\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyRemovedFromMintWhitelist\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"TrusteeAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"TrusteeFeeBpsChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"VaultBufferUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newDelay\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_claimable\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newClaimable\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimable\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_queued\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_yield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"YieldDistribution\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddr\",\"type\":\"address\"}],\"name\":\"addStrategyToMintWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"addWithdrawalQueueLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"allocate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"approveStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"asset\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"autoAllocateThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"burnForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capitalPaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"claimWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_requestIds\",\"type\":\"uint256[]\"}],\"name\":\"claimWithdrawals\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"totalAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultStrategy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyToAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"depositToStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dripDuration\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAssets\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllStrategies\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAssetCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStrategyCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_oToken\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isMintWhitelistedStrategy\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"isSupportedAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRebase\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxSupplyDiff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mintForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oToken\",\"outputs\":[{\"internalType\":\"contract OUSD\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oUSD\",\"outputs\":[{\"internalType\":\"contract OUSD\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previewYield\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"yield\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePerSecondMax\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePerSecondTarget\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebaseThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"removeStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddr\",\"type\":\"address\"}],\"name\":\"removeStrategyFromMintWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"requestWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"queued\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setAutoAllocateThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"setDefaultStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dripDuration\",\"type\":\"uint256\"}],\"name\":\"setDripDuration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"setMaxSupplyDiff\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"apr\",\"type\":\"uint256\"}],\"name\":\"setRebaseRateMax\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setRebaseThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setStrategistAddr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setTrusteeAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"setTrusteeFeeBps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"setVaultBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_delay\",\"type\":\"uint256\"}],\"name\":\"setWithdrawalClaimDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"strategies\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isSupported\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"_deprecated\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategistAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"transferToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAllFromStrategies\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"}],\"name\":\"withdrawAllFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyFromAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"withdrawFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalClaimDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalQueueMetadata\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimable\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimed\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"nextWithdrawalIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"withdrawalRequests\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"claimed\",\"type\":\"bool\"},{\"internalType\":\"uint40\",\"name\":\"timestamp\",\"type\":\"uint40\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"addStrategyToMintWhitelist(address)\":{\"params\":{\"strategyAddr\":\"Strategy address\"}},\"addWithdrawalQueueLiquidity()\":{\"details\":\"is called from the Native Staking strategy when validator withdrawals are processed. It also called before any WETH is allocated to a strategy.\"},\"approveStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to add\"}},\"burnForStrategy(uint256)\":{\"details\":\"Notice: can't use `nonReentrant` modifier since the `redeem` function could require withdrawal on an AMO strategy and that one can call `burnForStrategy` while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\",\"params\":{\"_amount\":\"Amount of OToken to burn\"}},\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of asset\"},\"returns\":{\"_0\":\"uint256 Balance of asset in decimals of asset\"}},\"claimWithdrawal(uint256)\":{\"params\":{\"_requestId\":\"Unique ID for the withdrawal request\"},\"returns\":{\"amount\":\"Amount of asset transferred to the withdrawer\"}},\"claimWithdrawals(uint256[])\":{\"params\":{\"_requestIds\":\"Unique ID of each withdrawal request\"},\"returns\":{\"amounts\":\"Amount of asset received for each request\",\"totalAmount\":\"Total amount of asset transferred to the withdrawer\"}},\"depositToStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to deposit.\",\"_assets\":\"Array of asset address that will be deposited into the strategy.\",\"_strategyToAddress\":\"Address of the Strategy to deposit asset into.\"}},\"isSupportedAsset(address)\":{\"params\":{\"_asset\":\"address of the asset\"},\"returns\":{\"_0\":\"true if supported\"}},\"mint(address,uint256,uint256)\":{\"details\":\"Deprecated: use `mint(uint256 _amount)` instead.Deprecated: param _asset Address of the asset being depositedDeprecated: param _minimumOusdAmount Minimum OTokens to mint\",\"params\":{\"_amount\":\"Amount of the asset being deposited\"}},\"mint(uint256)\":{\"params\":{\"_amount\":\"Amount of the asset being deposited\"}},\"mintForStrategy(uint256)\":{\"params\":{\"_amount\":\"Amount of OToken to mint Notice: can't use `nonReentrant` modifier since the `mint` function can call `allocate`, and that can trigger an AMO strategy to call this function while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\"}},\"previewYield()\":{\"returns\":{\"yield\":\"amount of expected yield\"}},\"removeStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to remove\"}},\"removeStrategyFromMintWhitelist(address)\":{\"params\":{\"strategyAddr\":\"Strategy address\"}},\"requestWithdrawal(uint256)\":{\"params\":{\"_amount\":\"Amount of OToken to burn.\"},\"returns\":{\"queued\":\"Cumulative total of all asset queued including already claimed requests.\",\"requestId\":\"Unique ID for the withdrawal request\"}},\"setAutoAllocateThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setDefaultStrategy(address)\":{\"params\":{\"_strategy\":\"Address of the Strategy\"}},\"setDripDuration(uint256)\":{\"params\":{\"_dripDuration\":\"Time in seconds to target a constant yield rate\"}},\"setRebaseRateMax(uint256)\":{\"params\":{\"apr\":\"in 1e18 notation. 3 * 1e18 = 3% APR\"}},\"setRebaseThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setStrategistAddr(address)\":{\"params\":{\"_address\":\"Address of Strategist\"}},\"setVaultBuffer(uint256)\":{\"params\":{\"_vaultBuffer\":\"Percentage using 18 decimals. 100% = 1e18.\"}},\"setWithdrawalClaimDelay(uint256)\":{\"params\":{\"_delay\":\"Delay period (should be between 10 mins to 7 days). Set to 0 to disable async withdrawals\"}},\"totalValue()\":{\"returns\":{\"value\":\"Total value in USD/ETH (1e18)\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"transferToken(address,uint256)\":{\"params\":{\"_amount\":\"Amount of the asset to transfer\",\"_asset\":\"Address for the asset\"}},\"withdrawAllFromStrategy(address)\":{\"params\":{\"_strategyAddr\":\"Strategy address.\"}},\"withdrawFromStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to withdraw.\",\"_assets\":\"Array of asset address that will be withdrawn from the strategy.\",\"_strategyFromAddress\":\"Address of the Strategy to withdraw asset from.\"}}},\"title\":\"OUSD VaultAdmin Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"addStrategyToMintWhitelist(address)\":{\"notice\":\"Adds a strategy to the mint whitelist. Reverts if strategy isn't approved on Vault.\"},\"addWithdrawalQueueLiquidity()\":{\"notice\":\"Adds WETH to the withdrawal queue if there is a funding shortfall.\"},\"allocate()\":{\"notice\":\"Allocate unallocated funds on Vault to strategies.\"},\"approveStrategy(address)\":{\"notice\":\"Add a strategy to the Vault.\"},\"autoAllocateThreshold()\":{\"notice\":\"OToken mints over this amount automatically allocate funds. 18 decimals.\"},\"burnForStrategy(uint256)\":{\"notice\":\"Burn OTokens for an allowed Strategy\"},\"capitalPaused()\":{\"notice\":\"pause operations that change the OToken supply. eg mint, redeem, allocate, mint/burn for strategy\"},\"checkBalance(address)\":{\"notice\":\"Get the balance of an asset held in Vault and all strategies.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"claimWithdrawal(uint256)\":{\"notice\":\"Claim a previously requested withdrawal once it is claimable. This request can be claimed once the withdrawal queue's `claimable` amount is greater than or equal this request's `queued` amount and 10 minutes has passed. If the requests is not claimable, the transaction will revert with `Queue pending liquidity`. If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`. OToken is converted to asset at 1:1.\"},\"claimWithdrawals(uint256[])\":{\"notice\":\"Claim a previously requested withdrawals once they are claimable. This requests can be claimed once the withdrawal queue's `claimable` amount is greater than or equal each request's `queued` amount and 10 minutes has passed. If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`. If one of the requests is not older than 10 minutes, the whole transaction will revert with `Claim delay not met`.\"},\"defaultStrategy()\":{\"notice\":\"Default strategy for asset\"},\"depositToStrategy(address,address[],uint256[])\":{\"notice\":\"Deposit multiple asset from the vault into the strategy.\"},\"dripDuration()\":{\"notice\":\"Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\"},\"getAllAssets()\":{\"notice\":\"Return all vault asset addresses in order\"},\"getAllStrategies()\":{\"notice\":\"Return the array of all strategies\"},\"getAssetCount()\":{\"notice\":\"Return the number of asset supported by the Vault.\"},\"getStrategyCount()\":{\"notice\":\"Return the number of strategies active on the Vault.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"isSupportedAsset(address)\":{\"notice\":\"Returns whether the vault supports the asset\"},\"lastRebase()\":{\"notice\":\"Time in seconds that the vault last rebased yield.\"},\"maxSupplyDiff()\":{\"notice\":\"Max difference between total supply and total value of assets. 18 decimals.\"},\"mint(address,uint256,uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mint(uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mintForStrategy(uint256)\":{\"notice\":\"Mint OTokens for an allowed Strategy\"},\"oUSD()\":{\"notice\":\"Deprecated: use `oToken()` instead.\"},\"pauseCapital()\":{\"notice\":\"Set the deposit paused flag to true to prevent capital movement.\"},\"pauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to prevent rebasing.\"},\"previewYield()\":{\"notice\":\"Calculates the amount that would rebase at next rebase. This is before any fees.\"},\"rebase()\":{\"notice\":\"Calculate the total value of asset held by the Vault and all strategies and update the supply of OTokens.\"},\"rebasePaused()\":{\"notice\":\"pause rebasing if true\"},\"rebasePerSecondMax()\":{\"notice\":\"max rebase percentage per second Can be used to set maximum yield of the protocol, spreading out yield over time\"},\"rebasePerSecondTarget()\":{\"notice\":\"target rebase rate limit, based on past rates and funds available.\"},\"rebaseThreshold()\":{\"notice\":\"OToken mints over this amount automatically rebase. 18 decimals.\"},\"removeStrategy(address)\":{\"notice\":\"Remove a strategy from the Vault.\"},\"removeStrategyFromMintWhitelist(address)\":{\"notice\":\"Removes a strategy from the mint whitelist.\"},\"requestWithdrawal(uint256)\":{\"notice\":\"Request an asynchronous withdrawal of asset in exchange for OToken. The OToken is burned on request and the asset is transferred to the withdrawer on claim. This request can be claimed once the withdrawal queue's `claimable` amount is greater than or equal this request's `queued` amount. There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue. OToken is converted to asset at 1:1.\"},\"setAutoAllocateThreshold(uint256)\":{\"notice\":\"Sets the minimum amount of OTokens in a mint to trigger an automatic allocation of funds afterwords.\"},\"setDefaultStrategy(address)\":{\"notice\":\"Set the default Strategy for asset, i.e. the one which the asset will be automatically allocated to and withdrawn from\"},\"setDripDuration(uint256)\":{\"notice\":\"Set the drip duration period\"},\"setMaxSupplyDiff(uint256)\":{\"notice\":\"Sets the maximum allowable difference between total supply and asset' value.\"},\"setRebaseRateMax(uint256)\":{\"notice\":\"Set a yield streaming max rate. This spreads yield over time if it is above the max rate. This is a per rebase APR which due to compounding differs from the yearly APR. Governance should consider this fact when picking a desired APR\"},\"setRebaseThreshold(uint256)\":{\"notice\":\"Set a minimum amount of OTokens in a mint or redeem that triggers a rebase\"},\"setStrategistAddr(address)\":{\"notice\":\"Set address of Strategist\"},\"setTrusteeAddress(address)\":{\"notice\":\"Sets the trusteeAddress that can receive a portion of yield. Setting to the zero address disables this feature.\"},\"setTrusteeFeeBps(uint256)\":{\"notice\":\"Sets the TrusteeFeeBps to the percentage of yield that should be received in basis points.\"},\"setVaultBuffer(uint256)\":{\"notice\":\"Set a buffer of asset to keep in the Vault to handle most redemptions without needing to spend gas unwinding asset from a Strategy.\"},\"setWithdrawalClaimDelay(uint256)\":{\"notice\":\"Changes the async withdrawal claim period for OETH & superOETHb\"},\"strategistAddr()\":{\"notice\":\"Address of the Strategist\"},\"totalValue()\":{\"notice\":\"Determine the total value of asset held by the vault and its strategies.\"},\"transferGovernance(address)\":{\"notice\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\"},\"transferToken(address,uint256)\":{\"notice\":\"Transfer token to governor. Intended for recovering tokens stuck in contract, i.e. mistaken sends.\"},\"trusteeAddress()\":{\"notice\":\"Trustee contract that can collect a percentage of yield\"},\"trusteeFeeBps()\":{\"notice\":\"Amount of yield collected in basis points. eg 2000 = 20%\"},\"unpauseCapital()\":{\"notice\":\"Set the deposit paused flag to false to enable capital movement.\"},\"unpauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to allow rebasing.\"},\"vaultBuffer()\":{\"notice\":\"Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\"},\"withdrawAllFromStrategies()\":{\"notice\":\"Withdraws all asset from all the strategies and sends asset to the Vault.\"},\"withdrawAllFromStrategy(address)\":{\"notice\":\"Withdraws all asset from the strategy and sends asset to the Vault.\"},\"withdrawFromStrategy(address,address[],uint256[])\":{\"notice\":\"Withdraw multiple asset from the strategy to the vault.\"},\"withdrawalClaimDelay()\":{\"notice\":\"Sets a minimum delay that is required to elapse between requesting async withdrawals and claiming the request. When set to 0 async withdrawals are disabled.\"},\"withdrawalQueueMetadata()\":{\"notice\":\"Global metadata for the withdrawal queue including: queued - cumulative total of all withdrawal requests included the ones that have already been claimed claimable - cumulative total of all the requests that can be claimed including the ones already claimed claimed - total of all the requests that have been claimed nextWithdrawalIndex - index of the next withdrawal request starting at 0\"},\"withdrawalRequests(uint256)\":{\"notice\":\"Mapping of withdrawal request indices to the user withdrawal request data\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/vault/OUSDVault.sol\":\"OUSDVault\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0x61437cb513a887a1bbad006e7b1c8b414478427d33de47c5600af3c748f108da\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeCast.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\\n * checks.\\n *\\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\\n * easily result in undesired exploitation or bugs, since developers usually\\n * assume that overflows raise errors. `SafeCast` restores this intuition by\\n * reverting the transaction when such an operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n *\\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\\n * all math on `uint256` and `int256` and then downcasting.\\n */\\nlibrary SafeCast {\\n /**\\n * @dev Returns the downcasted uint224 from uint256, reverting on\\n * overflow (when the input is greater than largest uint224).\\n *\\n * Counterpart to Solidity's `uint224` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 224 bits\\n */\\n function toUint224(uint256 value) internal pure returns (uint224) {\\n require(value <= type(uint224).max, \\\"SafeCast: value doesn't fit in 224 bits\\\");\\n return uint224(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint128 from uint256, reverting on\\n * overflow (when the input is greater than largest uint128).\\n *\\n * Counterpart to Solidity's `uint128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n */\\n function toUint128(uint256 value) internal pure returns (uint128) {\\n require(value <= type(uint128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return uint128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint96 from uint256, reverting on\\n * overflow (when the input is greater than largest uint96).\\n *\\n * Counterpart to Solidity's `uint96` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 96 bits\\n */\\n function toUint96(uint256 value) internal pure returns (uint96) {\\n require(value <= type(uint96).max, \\\"SafeCast: value doesn't fit in 96 bits\\\");\\n return uint96(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint64 from uint256, reverting on\\n * overflow (when the input is greater than largest uint64).\\n *\\n * Counterpart to Solidity's `uint64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n */\\n function toUint64(uint256 value) internal pure returns (uint64) {\\n require(value <= type(uint64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return uint64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint32 from uint256, reverting on\\n * overflow (when the input is greater than largest uint32).\\n *\\n * Counterpart to Solidity's `uint32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n */\\n function toUint32(uint256 value) internal pure returns (uint32) {\\n require(value <= type(uint32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return uint32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint16 from uint256, reverting on\\n * overflow (when the input is greater than largest uint16).\\n *\\n * Counterpart to Solidity's `uint16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n */\\n function toUint16(uint256 value) internal pure returns (uint16) {\\n require(value <= type(uint16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return uint16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint8 from uint256, reverting on\\n * overflow (when the input is greater than largest uint8).\\n *\\n * Counterpart to Solidity's `uint8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits.\\n */\\n function toUint8(uint256 value) internal pure returns (uint8) {\\n require(value <= type(uint8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return uint8(value);\\n }\\n\\n /**\\n * @dev Converts a signed int256 into an unsigned uint256.\\n *\\n * Requirements:\\n *\\n * - input must be greater than or equal to 0.\\n */\\n function toUint256(int256 value) internal pure returns (uint256) {\\n require(value >= 0, \\\"SafeCast: value must be positive\\\");\\n return uint256(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int128 from int256, reverting on\\n * overflow (when the input is less than smallest int128 or\\n * greater than largest int128).\\n *\\n * Counterpart to Solidity's `int128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt128(int256 value) internal pure returns (int128) {\\n require(value >= type(int128).min && value <= type(int128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return int128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int64 from int256, reverting on\\n * overflow (when the input is less than smallest int64 or\\n * greater than largest int64).\\n *\\n * Counterpart to Solidity's `int64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt64(int256 value) internal pure returns (int64) {\\n require(value >= type(int64).min && value <= type(int64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return int64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int32 from int256, reverting on\\n * overflow (when the input is less than smallest int32 or\\n * greater than largest int32).\\n *\\n * Counterpart to Solidity's `int32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt32(int256 value) internal pure returns (int32) {\\n require(value >= type(int32).min && value <= type(int32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return int32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int16 from int256, reverting on\\n * overflow (when the input is less than smallest int16 or\\n * greater than largest int16).\\n *\\n * Counterpart to Solidity's `int16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt16(int256 value) internal pure returns (int16) {\\n require(value >= type(int16).min && value <= type(int16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return int16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int8 from int256, reverting on\\n * overflow (when the input is less than smallest int8 or\\n * greater than largest int8).\\n *\\n * Counterpart to Solidity's `int8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits.\\n *\\n * _Available since v3.1._\\n */\\n function toInt8(int256 value) internal pure returns (int8) {\\n require(value >= type(int8).min && value <= type(int8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return int8(value);\\n }\\n\\n /**\\n * @dev Converts an unsigned uint256 into a signed int256.\\n *\\n * Requirements:\\n *\\n * - input must be less than or equal to maxInt256.\\n */\\n function toInt256(uint256 value) internal pure returns (int256) {\\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\\n require(value <= uint256(type(int256).max), \\\"SafeCast: value doesn't fit in an int256\\\");\\n return int256(value);\\n }\\n}\\n\",\"keccak256\":\"0x5c6caab697d302ad7eb59c234a4d2dbc965c1bae87709bd2850060b7695b28c7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa2f576be637946f767aa56601c26d717f48a0aff44f82e46f13807eea1009a21\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @notice Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @notice Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n emit GovernorshipTransferred(_governor(), newGovernor);\\n\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0xf32f873c8bfbacf2e5f01d0cf37bc7f54fbd5aa656e95c8a599114229946f107\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xa562062698aa12572123b36dfd2072f1a39e44fed2031cc19c2c9fd522f96ec2\",\"license\":\"MIT\"},\"contracts/interfaces/IStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\\n */\\ninterface IStrategy {\\n /**\\n * @dev Deposit the given asset to platform\\n * @param _asset asset address\\n * @param _amount Amount to deposit\\n */\\n function deposit(address _asset, uint256 _amount) external;\\n\\n /**\\n * @dev Deposit the entire balance of all supported assets in the Strategy\\n * to the platform\\n */\\n function depositAll() external;\\n\\n /**\\n * @dev Withdraw given asset from Lending platform\\n */\\n function withdraw(\\n address _recipient,\\n address _asset,\\n uint256 _amount\\n ) external;\\n\\n /**\\n * @dev Liquidate all assets in strategy and return them to Vault.\\n */\\n function withdrawAll() external;\\n\\n /**\\n * @dev Returns the current balance of the given asset.\\n */\\n function checkBalance(address _asset)\\n external\\n view\\n returns (uint256 balance);\\n\\n /**\\n * @dev Returns bool indicating whether strategy supports asset.\\n */\\n function supportsAsset(address _asset) external view returns (bool);\\n\\n /**\\n * @dev Collect reward tokens from the Strategy.\\n */\\n function collectRewardTokens() external;\\n\\n /**\\n * @dev The address array of the reward tokens for the Strategy.\\n */\\n function getRewardTokenAddresses() external view returns (address[] memory);\\n\\n function harvesterAddress() external view returns (address);\\n\\n function transferToken(address token, uint256 amount) external;\\n\\n function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\\n external;\\n}\\n\",\"keccak256\":\"0x79ca47defb3b5a56bba13f14c440838152fd1c1aa640476154516a16da4da8ba\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/IVault.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { VaultStorage } from \\\"../vault/VaultStorage.sol\\\";\\n\\ninterface IVault {\\n // slither-disable-start constable-states\\n\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event DefaultStrategyUpdated(address _strategy);\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\\n event DripDurationChanged(uint256 dripDuration);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\\n\\n // Governable.sol\\n function transferGovernance(address _newGovernor) external;\\n\\n function claimGovernance() external;\\n\\n function governor() external view returns (address);\\n\\n // VaultAdmin.sol\\n function setVaultBuffer(uint256 _vaultBuffer) external;\\n\\n function vaultBuffer() external view returns (uint256);\\n\\n function setAutoAllocateThreshold(uint256 _threshold) external;\\n\\n function autoAllocateThreshold() external view returns (uint256);\\n\\n function setRebaseThreshold(uint256 _threshold) external;\\n\\n function rebaseThreshold() external view returns (uint256);\\n\\n function setStrategistAddr(address _address) external;\\n\\n function strategistAddr() external view returns (address);\\n\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\\n\\n function maxSupplyDiff() external view returns (uint256);\\n\\n function setTrusteeAddress(address _address) external;\\n\\n function trusteeAddress() external view returns (address);\\n\\n function setTrusteeFeeBps(uint256 _basis) external;\\n\\n function trusteeFeeBps() external view returns (uint256);\\n\\n function approveStrategy(address _addr) external;\\n\\n function removeStrategy(address _addr) external;\\n\\n function setDefaultStrategy(address _strategy) external;\\n\\n function defaultStrategy() external view returns (address);\\n\\n function pauseRebase() external;\\n\\n function unpauseRebase() external;\\n\\n function rebasePaused() external view returns (bool);\\n\\n function pauseCapital() external;\\n\\n function unpauseCapital() external;\\n\\n function capitalPaused() external view returns (bool);\\n\\n function transferToken(address _asset, uint256 _amount) external;\\n\\n function withdrawAllFromStrategy(address _strategyAddr) external;\\n\\n function withdrawAllFromStrategies() external;\\n\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n // VaultCore.sol\\n function mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) external;\\n\\n function mintForStrategy(uint256 _amount) external;\\n\\n function redeem(uint256 _amount, uint256 _minimumUnitAmount) external;\\n\\n function burnForStrategy(uint256 _amount) external;\\n\\n function allocate() external;\\n\\n function rebase() external;\\n\\n function totalValue() external view returns (uint256 value);\\n\\n function checkBalance(address _asset) external view returns (uint256);\\n\\n /// @notice Deprecated: use calculateRedeemOutput\\n function calculateRedeemOutputs(uint256 _amount)\\n external\\n view\\n returns (uint256[] memory);\\n\\n function calculateRedeemOutput(uint256 _amount)\\n external\\n view\\n returns (uint256);\\n\\n function getAssetCount() external view returns (uint256);\\n\\n function getAllAssets() external view returns (address[] memory);\\n\\n function getStrategyCount() external view returns (uint256);\\n\\n function getAllStrategies() external view returns (address[] memory);\\n\\n /// @notice Deprecated.\\n function isSupportedAsset(address _asset) external view returns (bool);\\n\\n function dripper() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function initialize(address) external;\\n\\n function addWithdrawalQueueLiquidity() external;\\n\\n function requestWithdrawal(uint256 _amount)\\n external\\n returns (uint256 requestId, uint256 queued);\\n\\n function claimWithdrawal(uint256 requestId)\\n external\\n returns (uint256 amount);\\n\\n function claimWithdrawals(uint256[] memory requestIds)\\n external\\n returns (uint256[] memory amounts, uint256 totalAmount);\\n\\n function withdrawalQueueMetadata()\\n external\\n view\\n returns (VaultStorage.WithdrawalQueueMetadata memory);\\n\\n function withdrawalRequests(uint256 requestId)\\n external\\n view\\n returns (VaultStorage.WithdrawalRequest memory);\\n\\n function addStrategyToMintWhitelist(address strategyAddr) external;\\n\\n function removeStrategyFromMintWhitelist(address strategyAddr) external;\\n\\n function isMintWhitelistedStrategy(address strategyAddr)\\n external\\n view\\n returns (bool);\\n\\n function withdrawalClaimDelay() external view returns (uint256);\\n\\n function setWithdrawalClaimDelay(uint256 newDelay) external;\\n\\n function lastRebase() external view returns (uint64);\\n\\n function dripDuration() external view returns (uint64);\\n\\n function setDripDuration(uint256 _dripDuration) external;\\n\\n function rebasePerSecondMax() external view returns (uint64);\\n\\n function setRebaseRateMax(uint256 yearlyApr) external;\\n\\n function rebasePerSecondTarget() external view returns (uint64);\\n\\n function previewYield() external view returns (uint256 yield);\\n\\n function weth() external view returns (address);\\n\\n // slither-disable-end constable-states\\n}\\n\",\"keccak256\":\"0x61e2ad6f41abac69275ba86e51d9d3cd95dfd6fc6b81960cf75b1e06adb6251d\",\"license\":\"BUSL-1.1\"},\"contracts/token/OUSD.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OUSD Token Contract\\n * @dev ERC20 compatible contract for OUSD\\n * @dev Implements an elastic supply\\n * @author Origin Protocol Inc\\n */\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\ncontract OUSD is Governable {\\n using SafeCast for int256;\\n using SafeCast for uint256;\\n\\n /// @dev Event triggered when the supply changes\\n /// @param totalSupply Updated token total supply\\n /// @param rebasingCredits Updated token rebasing credits\\n /// @param rebasingCreditsPerToken Updated token rebasing credits per token\\n event TotalSupplyUpdatedHighres(\\n uint256 totalSupply,\\n uint256 rebasingCredits,\\n uint256 rebasingCreditsPerToken\\n );\\n /// @dev Event triggered when an account opts in for rebasing\\n /// @param account Address of the account\\n event AccountRebasingEnabled(address account);\\n /// @dev Event triggered when an account opts out of rebasing\\n /// @param account Address of the account\\n event AccountRebasingDisabled(address account);\\n /// @dev Emitted when `value` tokens are moved from one account `from` to\\n /// another `to`.\\n /// @param from Address of the account tokens are moved from\\n /// @param to Address of the account tokens are moved to\\n /// @param value Amount of tokens transferred\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n /// @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n /// a call to {approve}. `value` is the new allowance.\\n /// @param owner Address of the owner approving allowance\\n /// @param spender Address of the spender allowance is granted to\\n /// @param value Amount of tokens spender can transfer\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 value\\n );\\n /// @dev Yield resulting from {changeSupply} that a `source` account would\\n /// receive is directed to `target` account.\\n /// @param source Address of the source forwarding the yield\\n /// @param target Address of the target receiving the yield\\n event YieldDelegated(address source, address target);\\n /// @dev Yield delegation from `source` account to the `target` account is\\n /// suspended.\\n /// @param source Address of the source suspending yield forwarding\\n /// @param target Address of the target no longer receiving yield from `source`\\n /// account\\n event YieldUndelegated(address source, address target);\\n\\n enum RebaseOptions {\\n NotSet,\\n StdNonRebasing,\\n StdRebasing,\\n YieldDelegationSource,\\n YieldDelegationTarget\\n }\\n\\n uint256[154] private _gap; // Slots to align with deployed contract\\n uint256 private constant MAX_SUPPLY = type(uint128).max;\\n /// @dev The amount of tokens in existence\\n uint256 public totalSupply;\\n mapping(address => mapping(address => uint256)) private allowances;\\n /// @dev The vault with privileges to execute {mint}, {burn}\\n /// and {changeSupply}\\n address public vaultAddress;\\n mapping(address => uint256) internal creditBalances;\\n // the 2 storage variables below need trailing underscores to not name collide with public functions\\n uint256 private rebasingCredits_; // Sum of all rebasing credits (creditBalances for rebasing accounts)\\n uint256 private rebasingCreditsPerToken_;\\n /// @dev The amount of tokens that are not rebasing - receiving yield\\n uint256 public nonRebasingSupply;\\n mapping(address => uint256) internal alternativeCreditsPerToken;\\n /// @dev A map of all addresses and their respective RebaseOptions\\n mapping(address => RebaseOptions) public rebaseState;\\n mapping(address => uint256) private __deprecated_isUpgraded;\\n /// @dev A map of addresses that have yields forwarded to. This is an\\n /// inverse mapping of {yieldFrom}\\n /// Key Account forwarding yield\\n /// Value Account receiving yield\\n mapping(address => address) public yieldTo;\\n /// @dev A map of addresses that are receiving the yield. This is an\\n /// inverse mapping of {yieldTo}\\n /// Key Account receiving yield\\n /// Value Account forwarding yield\\n mapping(address => address) public yieldFrom;\\n\\n uint256 private constant RESOLUTION_INCREASE = 1e9;\\n uint256[34] private __gap; // including below gap totals up to 200\\n\\n /// @dev Verifies that the caller is the Governor or Strategist.\\n modifier onlyGovernorOrStrategist() {\\n require(\\n isGovernor() || msg.sender == IVault(vaultAddress).strategistAddr(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n /// @dev Initializes the contract and sets necessary variables.\\n /// @param _vaultAddress Address of the vault contract\\n /// @param _initialCreditsPerToken The starting rebasing credits per token.\\n function initialize(address _vaultAddress, uint256 _initialCreditsPerToken)\\n external\\n onlyGovernor\\n {\\n require(_vaultAddress != address(0), \\\"Zero vault address\\\");\\n require(vaultAddress == address(0), \\\"Already initialized\\\");\\n\\n rebasingCreditsPerToken_ = _initialCreditsPerToken;\\n vaultAddress = _vaultAddress;\\n }\\n\\n /// @dev Returns the symbol of the token, a shorter version\\n /// of the name.\\n function symbol() external pure virtual returns (string memory) {\\n return \\\"OUSD\\\";\\n }\\n\\n /// @dev Returns the name of the token.\\n function name() external pure virtual returns (string memory) {\\n return \\\"Origin Dollar\\\";\\n }\\n\\n /// @dev Returns the number of decimals used to get its user representation.\\n function decimals() external pure virtual returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev Verifies that the caller is the Vault contract\\n */\\n modifier onlyVault() {\\n require(vaultAddress == msg.sender, \\\"Caller is not the Vault\\\");\\n _;\\n }\\n\\n /**\\n * @return High resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerTokenHighres() external view returns (uint256) {\\n return rebasingCreditsPerToken_;\\n }\\n\\n /**\\n * @return Low resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerToken() external view returns (uint256) {\\n return rebasingCreditsPerToken_ / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return High resolution total number of rebasing credits\\n */\\n function rebasingCreditsHighres() external view returns (uint256) {\\n return rebasingCredits_;\\n }\\n\\n /**\\n * @return Low resolution total number of rebasing credits\\n */\\n function rebasingCredits() external view returns (uint256) {\\n return rebasingCredits_ / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @notice Gets the balance of the specified address.\\n * @param _account Address to query the balance of.\\n * @return A uint256 representing the amount of base units owned by the\\n * specified address.\\n */\\n function balanceOf(address _account) public view returns (uint256) {\\n RebaseOptions state = rebaseState[_account];\\n if (state == RebaseOptions.YieldDelegationSource) {\\n // Saves a slot read when transferring to or from a yield delegating source\\n // since we know creditBalances equals the balance.\\n return creditBalances[_account];\\n }\\n uint256 baseBalance = (creditBalances[_account] * 1e18) /\\n _creditsPerToken(_account);\\n if (state == RebaseOptions.YieldDelegationTarget) {\\n // creditBalances of yieldFrom accounts equals token balances\\n return baseBalance - creditBalances[yieldFrom[_account]];\\n }\\n return baseBalance;\\n }\\n\\n /**\\n * @notice Gets the credits balance of the specified address.\\n * @dev Backwards compatible with old low res credits per token.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256) Credit balance and credits per token of the\\n * address\\n */\\n function creditsBalanceOf(address _account)\\n external\\n view\\n returns (uint256, uint256)\\n {\\n uint256 cpt = _creditsPerToken(_account);\\n if (cpt == 1e27) {\\n // For a period before the resolution upgrade, we created all new\\n // contract accounts at high resolution. Since they are not changing\\n // as a result of this upgrade, we will return their true values\\n return (creditBalances[_account], cpt);\\n } else {\\n return (\\n creditBalances[_account] / RESOLUTION_INCREASE,\\n cpt / RESOLUTION_INCREASE\\n );\\n }\\n }\\n\\n /**\\n * @notice Gets the credits balance of the specified address.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\\n * address, and isUpgraded\\n */\\n function creditsBalanceOfHighres(address _account)\\n external\\n view\\n returns (\\n uint256,\\n uint256,\\n bool\\n )\\n {\\n return (\\n creditBalances[_account],\\n _creditsPerToken(_account),\\n true // all accounts have their resolution \\\"upgraded\\\"\\n );\\n }\\n\\n // Backwards compatible view\\n function nonRebasingCreditsPerToken(address _account)\\n external\\n view\\n returns (uint256)\\n {\\n return alternativeCreditsPerToken[_account];\\n }\\n\\n /**\\n * @notice Transfer tokens to a specified address.\\n * @param _to the address to transfer to.\\n * @param _value the amount to be transferred.\\n * @return true on success.\\n */\\n function transfer(address _to, uint256 _value) external returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n\\n _executeTransfer(msg.sender, _to, _value);\\n\\n emit Transfer(msg.sender, _to, _value);\\n return true;\\n }\\n\\n /**\\n * @notice Transfer tokens from one address to another.\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value The amount of tokens to be transferred.\\n * @return true on success.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n uint256 userAllowance = allowances[_from][msg.sender];\\n require(_value <= userAllowance, \\\"Allowance exceeded\\\");\\n\\n unchecked {\\n allowances[_from][msg.sender] = userAllowance - _value;\\n }\\n\\n _executeTransfer(_from, _to, _value);\\n\\n emit Transfer(_from, _to, _value);\\n return true;\\n }\\n\\n function _executeTransfer(\\n address _from,\\n address _to,\\n uint256 _value\\n ) internal {\\n (\\n int256 fromRebasingCreditsDiff,\\n int256 fromNonRebasingSupplyDiff\\n ) = _adjustAccount(_from, -_value.toInt256());\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_to, _value.toInt256());\\n\\n _adjustGlobals(\\n fromRebasingCreditsDiff + toRebasingCreditsDiff,\\n fromNonRebasingSupplyDiff + toNonRebasingSupplyDiff\\n );\\n }\\n\\n function _adjustAccount(address _account, int256 _balanceChange)\\n internal\\n returns (int256 rebasingCreditsDiff, int256 nonRebasingSupplyDiff)\\n {\\n RebaseOptions state = rebaseState[_account];\\n int256 currentBalance = balanceOf(_account).toInt256();\\n if (currentBalance + _balanceChange < 0) {\\n revert(\\\"Transfer amount exceeds balance\\\");\\n }\\n uint256 newBalance = (currentBalance + _balanceChange).toUint256();\\n\\n if (state == RebaseOptions.YieldDelegationSource) {\\n address target = yieldTo[_account];\\n uint256 targetOldBalance = balanceOf(target);\\n uint256 targetNewCredits = _balanceToRebasingCredits(\\n targetOldBalance + newBalance\\n );\\n rebasingCreditsDiff =\\n targetNewCredits.toInt256() -\\n creditBalances[target].toInt256();\\n\\n creditBalances[_account] = newBalance;\\n creditBalances[target] = targetNewCredits;\\n } else if (state == RebaseOptions.YieldDelegationTarget) {\\n uint256 newCredits = _balanceToRebasingCredits(\\n newBalance + creditBalances[yieldFrom[_account]]\\n );\\n rebasingCreditsDiff =\\n newCredits.toInt256() -\\n creditBalances[_account].toInt256();\\n creditBalances[_account] = newCredits;\\n } else {\\n _autoMigrate(_account);\\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\\n _account\\n ];\\n if (alternativeCreditsPerTokenMem > 0) {\\n nonRebasingSupplyDiff = _balanceChange;\\n if (alternativeCreditsPerTokenMem != 1e18) {\\n alternativeCreditsPerToken[_account] = 1e18;\\n }\\n creditBalances[_account] = newBalance;\\n } else {\\n uint256 newCredits = _balanceToRebasingCredits(newBalance);\\n rebasingCreditsDiff =\\n newCredits.toInt256() -\\n creditBalances[_account].toInt256();\\n creditBalances[_account] = newCredits;\\n }\\n }\\n }\\n\\n function _adjustGlobals(\\n int256 _rebasingCreditsDiff,\\n int256 _nonRebasingSupplyDiff\\n ) internal {\\n if (_rebasingCreditsDiff != 0) {\\n rebasingCredits_ = (rebasingCredits_.toInt256() +\\n _rebasingCreditsDiff).toUint256();\\n }\\n if (_nonRebasingSupplyDiff != 0) {\\n nonRebasingSupply = (nonRebasingSupply.toInt256() +\\n _nonRebasingSupplyDiff).toUint256();\\n }\\n }\\n\\n /**\\n * @notice Function to check the amount of tokens that _owner has allowed\\n * to `_spender`.\\n * @param _owner The address which owns the funds.\\n * @param _spender The address which will spend the funds.\\n * @return The number of tokens still available for the _spender.\\n */\\n function allowance(address _owner, address _spender)\\n external\\n view\\n returns (uint256)\\n {\\n return allowances[_owner][_spender];\\n }\\n\\n /**\\n * @notice Approve the passed address to spend the specified amount of\\n * tokens on behalf of msg.sender.\\n * @param _spender The address which will spend the funds.\\n * @param _value The amount of tokens to be spent.\\n * @return true on success.\\n */\\n function approve(address _spender, uint256 _value) external returns (bool) {\\n allowances[msg.sender][_spender] = _value;\\n emit Approval(msg.sender, _spender, _value);\\n return true;\\n }\\n\\n /**\\n * @notice Creates `_amount` tokens and assigns them to `_account`,\\n * increasing the total supply.\\n */\\n function mint(address _account, uint256 _amount) external onlyVault {\\n require(_account != address(0), \\\"Mint to the zero address\\\");\\n\\n // Account\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_account, _amount.toInt256());\\n // Globals\\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\\n totalSupply = totalSupply + _amount;\\n\\n require(totalSupply < MAX_SUPPLY, \\\"Max supply\\\");\\n emit Transfer(address(0), _account, _amount);\\n }\\n\\n /**\\n * @notice Destroys `_amount` tokens from `_account`,\\n * reducing the total supply.\\n */\\n function burn(address _account, uint256 _amount) external onlyVault {\\n require(_account != address(0), \\\"Burn from the zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n\\n // Account\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_account, -_amount.toInt256());\\n // Globals\\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\\n totalSupply = totalSupply - _amount;\\n\\n emit Transfer(_account, address(0), _amount);\\n }\\n\\n /**\\n * @dev Get the credits per token for an account. Returns a fixed amount\\n * if the account is non-rebasing.\\n * @param _account Address of the account.\\n */\\n function _creditsPerToken(address _account)\\n internal\\n view\\n returns (uint256)\\n {\\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\\n _account\\n ];\\n if (alternativeCreditsPerTokenMem != 0) {\\n return alternativeCreditsPerTokenMem;\\n } else {\\n return rebasingCreditsPerToken_;\\n }\\n }\\n\\n /**\\n * @dev Auto migrate contracts to be non rebasing,\\n * unless they have opted into yield.\\n * @param _account Address of the account.\\n */\\n function _autoMigrate(address _account) internal {\\n uint256 codeLen = _account.code.length;\\n bool isEOA = (codeLen == 0) ||\\n (codeLen == 23 && bytes3(_account.code) == 0xef0100);\\n // In previous code versions, contracts would not have had their\\n // rebaseState[_account] set to RebaseOptions.NonRebasing when migrated\\n // therefore we check the actual accounting used on the account as well.\\n if (\\n (!isEOA) &&\\n rebaseState[_account] == RebaseOptions.NotSet &&\\n alternativeCreditsPerToken[_account] == 0\\n ) {\\n _rebaseOptOut(_account);\\n }\\n }\\n\\n /**\\n * @dev Calculates credits from contract's global rebasingCreditsPerToken_, and\\n * also balance that corresponds to those credits. The latter is important\\n * when adjusting the contract's global nonRebasingSupply to circumvent any\\n * possible rounding errors.\\n *\\n * @param _balance Balance of the account.\\n */\\n function _balanceToRebasingCredits(uint256 _balance)\\n internal\\n view\\n returns (uint256 rebasingCredits)\\n {\\n // Rounds up, because we need to ensure that accounts always have\\n // at least the balance that they should have.\\n // Note this should always be used on an absolute account value,\\n // not on a possibly negative diff, because then the rounding would be wrong.\\n return ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18;\\n }\\n\\n /**\\n * @notice The calling account will start receiving yield after a successful call.\\n * @param _account Address of the account.\\n */\\n function governanceRebaseOptIn(address _account) external onlyGovernor {\\n require(_account != address(0), \\\"Zero address not allowed\\\");\\n _rebaseOptIn(_account);\\n }\\n\\n /**\\n * @notice The calling account will start receiving yield after a successful call.\\n */\\n function rebaseOptIn() external {\\n _rebaseOptIn(msg.sender);\\n }\\n\\n function _rebaseOptIn(address _account) internal {\\n uint256 balance = balanceOf(_account);\\n\\n // prettier-ignore\\n require(\\n alternativeCreditsPerToken[_account] > 0 ||\\n // Accounts may explicitly `rebaseOptIn` regardless of\\n // accounting if they have a 0 balance.\\n creditBalances[_account] == 0\\n ,\\n \\\"Account must be non-rebasing\\\"\\n );\\n RebaseOptions state = rebaseState[_account];\\n // prettier-ignore\\n require(\\n state == RebaseOptions.StdNonRebasing ||\\n state == RebaseOptions.NotSet,\\n \\\"Only standard non-rebasing accounts can opt in\\\"\\n );\\n\\n uint256 newCredits = _balanceToRebasingCredits(balance);\\n\\n // Account\\n rebaseState[_account] = RebaseOptions.StdRebasing;\\n alternativeCreditsPerToken[_account] = 0;\\n creditBalances[_account] = newCredits;\\n // Globals\\n _adjustGlobals(newCredits.toInt256(), -balance.toInt256());\\n\\n emit AccountRebasingEnabled(_account);\\n }\\n\\n /**\\n * @notice The calling account will no longer receive yield\\n */\\n function rebaseOptOut() external {\\n _rebaseOptOut(msg.sender);\\n }\\n\\n function _rebaseOptOut(address _account) internal {\\n require(\\n alternativeCreditsPerToken[_account] == 0,\\n \\\"Account must be rebasing\\\"\\n );\\n RebaseOptions state = rebaseState[_account];\\n require(\\n state == RebaseOptions.StdRebasing || state == RebaseOptions.NotSet,\\n \\\"Only standard rebasing accounts can opt out\\\"\\n );\\n\\n uint256 oldCredits = creditBalances[_account];\\n uint256 balance = balanceOf(_account);\\n\\n // Account\\n rebaseState[_account] = RebaseOptions.StdNonRebasing;\\n alternativeCreditsPerToken[_account] = 1e18;\\n creditBalances[_account] = balance;\\n // Globals\\n _adjustGlobals(-oldCredits.toInt256(), balance.toInt256());\\n\\n emit AccountRebasingDisabled(_account);\\n }\\n\\n /**\\n * @notice Distribute yield to users. This changes the exchange rate\\n * between \\\"credits\\\" and OUSD tokens to change rebasing user's balances.\\n * @param _newTotalSupply New total supply of OUSD.\\n */\\n function changeSupply(uint256 _newTotalSupply) external onlyVault {\\n require(totalSupply > 0, \\\"Cannot increase 0 supply\\\");\\n\\n if (totalSupply == _newTotalSupply) {\\n emit TotalSupplyUpdatedHighres(\\n totalSupply,\\n rebasingCredits_,\\n rebasingCreditsPerToken_\\n );\\n return;\\n }\\n\\n totalSupply = _newTotalSupply > MAX_SUPPLY\\n ? MAX_SUPPLY\\n : _newTotalSupply;\\n\\n uint256 rebasingSupply = totalSupply - nonRebasingSupply;\\n // round up in the favour of the protocol\\n rebasingCreditsPerToken_ =\\n (rebasingCredits_ * 1e18 + rebasingSupply - 1) /\\n rebasingSupply;\\n\\n require(rebasingCreditsPerToken_ > 0, \\\"Invalid change in supply\\\");\\n\\n emit TotalSupplyUpdatedHighres(\\n totalSupply,\\n rebasingCredits_,\\n rebasingCreditsPerToken_\\n );\\n }\\n\\n /*\\n * @notice Send the yield from one account to another account.\\n * Each account keeps its own balances.\\n */\\n function delegateYield(address _from, address _to)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_from != address(0), \\\"Zero from address not allowed\\\");\\n require(_to != address(0), \\\"Zero to address not allowed\\\");\\n\\n require(_from != _to, \\\"Cannot delegate to self\\\");\\n require(\\n yieldFrom[_to] == address(0) &&\\n yieldTo[_to] == address(0) &&\\n yieldFrom[_from] == address(0) &&\\n yieldTo[_from] == address(0),\\n \\\"Blocked by existing yield delegation\\\"\\n );\\n RebaseOptions stateFrom = rebaseState[_from];\\n RebaseOptions stateTo = rebaseState[_to];\\n\\n require(\\n stateFrom == RebaseOptions.NotSet ||\\n stateFrom == RebaseOptions.StdNonRebasing ||\\n stateFrom == RebaseOptions.StdRebasing,\\n \\\"Invalid rebaseState from\\\"\\n );\\n\\n require(\\n stateTo == RebaseOptions.NotSet ||\\n stateTo == RebaseOptions.StdNonRebasing ||\\n stateTo == RebaseOptions.StdRebasing,\\n \\\"Invalid rebaseState to\\\"\\n );\\n\\n if (alternativeCreditsPerToken[_from] == 0) {\\n _rebaseOptOut(_from);\\n }\\n if (alternativeCreditsPerToken[_to] > 0) {\\n _rebaseOptIn(_to);\\n }\\n\\n uint256 fromBalance = balanceOf(_from);\\n uint256 toBalance = balanceOf(_to);\\n uint256 oldToCredits = creditBalances[_to];\\n uint256 newToCredits = _balanceToRebasingCredits(\\n fromBalance + toBalance\\n );\\n\\n // Set up the bidirectional links\\n yieldTo[_from] = _to;\\n yieldFrom[_to] = _from;\\n\\n // Local\\n rebaseState[_from] = RebaseOptions.YieldDelegationSource;\\n alternativeCreditsPerToken[_from] = 1e18;\\n creditBalances[_from] = fromBalance;\\n rebaseState[_to] = RebaseOptions.YieldDelegationTarget;\\n creditBalances[_to] = newToCredits;\\n\\n // Global\\n int256 creditsChange = newToCredits.toInt256() -\\n oldToCredits.toInt256();\\n _adjustGlobals(creditsChange, -(fromBalance).toInt256());\\n emit YieldDelegated(_from, _to);\\n }\\n\\n /*\\n * @notice Stop sending the yield from one account to another account.\\n */\\n function undelegateYield(address _from) external onlyGovernorOrStrategist {\\n // Require a delegation, which will also ensure a valid delegation\\n require(yieldTo[_from] != address(0), \\\"Zero address not allowed\\\");\\n\\n address to = yieldTo[_from];\\n uint256 fromBalance = balanceOf(_from);\\n uint256 toBalance = balanceOf(to);\\n uint256 oldToCredits = creditBalances[to];\\n uint256 newToCredits = _balanceToRebasingCredits(toBalance);\\n\\n // Remove the bidirectional links\\n yieldFrom[to] = address(0);\\n yieldTo[_from] = address(0);\\n\\n // Local\\n rebaseState[_from] = RebaseOptions.StdNonRebasing;\\n // alternativeCreditsPerToken[from] already 1e18 from `delegateYield()`\\n creditBalances[_from] = fromBalance;\\n rebaseState[to] = RebaseOptions.StdRebasing;\\n // alternativeCreditsPerToken[to] already 0 from `delegateYield()`\\n creditBalances[to] = newToCredits;\\n\\n // Global\\n int256 creditsChange = newToCredits.toInt256() -\\n oldToCredits.toInt256();\\n _adjustGlobals(creditsChange, fromBalance.toInt256());\\n emit YieldUndelegated(_from, to);\\n }\\n}\\n\",\"keccak256\":\"0x73439bef6569f5adf6f5ce2cb54a5f0d3109d4819457532236e172a7091980a9\",\"license\":\"BUSL-1.1\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { IBasicToken } from \\\"../interfaces/IBasicToken.sol\\\";\\n\\nlibrary Helpers {\\n /**\\n * @notice Fetch the `symbol()` from an ERC20 token\\n * @dev Grabs the `symbol()` from a contract\\n * @param _token Address of the ERC20 token\\n * @return string Symbol of the ERC20 token\\n */\\n function getSymbol(address _token) internal view returns (string memory) {\\n string memory symbol = IBasicToken(_token).symbol();\\n return symbol;\\n }\\n\\n /**\\n * @notice Fetch the `decimals()` from an ERC20 token\\n * @dev Grabs the `decimals()` from a contract and fails if\\n * the decimal value does not live within a certain range\\n * @param _token Address of the ERC20 token\\n * @return uint256 Decimals of the ERC20 token\\n */\\n function getDecimals(address _token) internal view returns (uint256) {\\n uint256 decimals = IBasicToken(_token).decimals();\\n require(\\n decimals >= 4 && decimals <= 18,\\n \\\"Token must have sufficient decimal places\\\"\\n );\\n\\n return decimals;\\n }\\n}\\n\",\"keccak256\":\"0x4366f8d90b34c1eef8bbaaf369b1e5cd59f04027bb3c111f208eaee65bbc0346\",\"license\":\"BUSL-1.1\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base contract any contracts that need to initialize state after deployment.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0x50d39ebf38a3d3111f2b77a6c75ece1d4ae731552fec4697ab16fcf6c0d4d5e8\",\"license\":\"BUSL-1.1\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n // slither-disable-next-line divide-before-multiply\\n x = x.div(10**(from - to));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e36 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0x71d6ed0053a1e5ef018d27c3b6d024f336d8157ab6f6859e400b3243a50a71b7\",\"license\":\"BUSL-1.1\"},\"contracts/vault/OUSDVault.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { VaultAdmin } from \\\"./VaultAdmin.sol\\\";\\n\\n/**\\n * @title OUSD VaultAdmin Contract\\n * @author Origin Protocol Inc\\n */\\ncontract OUSDVault is VaultAdmin {\\n constructor(address _usdc) VaultAdmin(_usdc) {}\\n}\\n\",\"keccak256\":\"0xb9112bcf70fc7adffe9051e62d3f71ee69f7e06bd7ec7dcce2a149ab8d58693c\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultAdmin contract\\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\nimport \\\"./VaultCore.sol\\\";\\n\\nabstract contract VaultAdmin is VaultCore {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n using SafeCast for uint256;\\n\\n /**\\n * @dev Verifies that the caller is the Governor or Strategist.\\n */\\n modifier onlyGovernorOrStrategist() {\\n require(\\n msg.sender == strategistAddr || isGovernor(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n constructor(address _asset) VaultCore(_asset) {}\\n\\n /***************************************\\n Configuration\\n ****************************************/\\n /**\\n * @notice Set a buffer of asset to keep in the Vault to handle most\\n * redemptions without needing to spend gas unwinding asset from a Strategy.\\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\\n */\\n function setVaultBuffer(uint256 _vaultBuffer)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_vaultBuffer <= 1e18, \\\"Invalid value\\\");\\n vaultBuffer = _vaultBuffer;\\n emit VaultBufferUpdated(_vaultBuffer);\\n }\\n\\n /**\\n * @notice Sets the minimum amount of OTokens in a mint to trigger an\\n * automatic allocation of funds afterwords.\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setAutoAllocateThreshold(uint256 _threshold)\\n external\\n onlyGovernor\\n {\\n autoAllocateThreshold = _threshold;\\n emit AllocateThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set a minimum amount of OTokens in a mint or redeem that triggers a\\n * rebase\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setRebaseThreshold(uint256 _threshold) external onlyGovernor {\\n rebaseThreshold = _threshold;\\n emit RebaseThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set address of Strategist\\n * @param _address Address of Strategist\\n */\\n function setStrategistAddr(address _address) external onlyGovernor {\\n strategistAddr = _address;\\n emit StrategistUpdated(_address);\\n }\\n\\n /**\\n * @notice Set the default Strategy for asset, i.e. the one which\\n * the asset will be automatically allocated to and withdrawn from\\n * @param _strategy Address of the Strategy\\n */\\n function setDefaultStrategy(address _strategy)\\n external\\n onlyGovernorOrStrategist\\n {\\n emit DefaultStrategyUpdated(_strategy);\\n // If its a zero address being passed for the strategy we are removing\\n // the default strategy\\n if (_strategy != address(0)) {\\n // Make sure the strategy meets some criteria\\n require(strategies[_strategy].isSupported, \\\"Strategy not approved\\\");\\n require(\\n IStrategy(_strategy).supportsAsset(asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n }\\n defaultStrategy = _strategy;\\n }\\n\\n /**\\n * @notice Changes the async withdrawal claim period for OETH & superOETHb\\n * @param _delay Delay period (should be between 10 mins to 7 days).\\n * Set to 0 to disable async withdrawals\\n */\\n function setWithdrawalClaimDelay(uint256 _delay) external onlyGovernor {\\n require(\\n _delay == 0 || (_delay >= 10 minutes && _delay <= 15 days),\\n \\\"Invalid claim delay period\\\"\\n );\\n withdrawalClaimDelay = _delay;\\n emit WithdrawalClaimDelayUpdated(_delay);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Set a yield streaming max rate. This spreads yield over\\n * time if it is above the max rate. This is a per rebase APR which\\n * due to compounding differs from the yearly APR. Governance should\\n * consider this fact when picking a desired APR\\n * @param apr in 1e18 notation. 3 * 1e18 = 3% APR\\n */\\n function setRebaseRateMax(uint256 apr) external onlyGovernorOrStrategist {\\n // The old yield will be at the old rate\\n _rebase();\\n // Change the rate\\n uint256 newPerSecond = apr / 100 / 365 days;\\n require(newPerSecond <= MAX_REBASE_PER_SECOND, \\\"Rate too high\\\");\\n rebasePerSecondMax = newPerSecond.toUint64();\\n emit RebasePerSecondMaxChanged(newPerSecond);\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Set the drip duration period\\n * @param _dripDuration Time in seconds to target a constant yield rate\\n */\\n function setDripDuration(uint256 _dripDuration)\\n external\\n onlyGovernorOrStrategist\\n {\\n // The old yield will be at the old rate\\n _rebase();\\n dripDuration = _dripDuration.toUint64();\\n emit DripDurationChanged(_dripDuration);\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /***************************************\\n Strategy Config\\n ****************************************/\\n\\n /**\\n * @notice Add a strategy to the Vault.\\n * @param _addr Address of the strategy to add\\n */\\n function approveStrategy(address _addr) external onlyGovernor {\\n require(!strategies[_addr].isSupported, \\\"Strategy already approved\\\");\\n require(\\n IStrategy(_addr).supportsAsset(asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\\n allStrategies.push(_addr);\\n emit StrategyApproved(_addr);\\n }\\n\\n /**\\n * @notice Remove a strategy from the Vault.\\n * @param _addr Address of the strategy to remove\\n */\\n\\n function removeStrategy(address _addr) external onlyGovernor {\\n require(strategies[_addr].isSupported, \\\"Strategy not approved\\\");\\n require(defaultStrategy != _addr, \\\"Strategy is default for asset\\\");\\n\\n // Initialize strategyIndex with out of bounds result so function will\\n // revert if no valid index found\\n uint256 stratCount = allStrategies.length;\\n uint256 strategyIndex = stratCount;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n if (allStrategies[i] == _addr) {\\n strategyIndex = i;\\n break;\\n }\\n }\\n\\n if (strategyIndex < stratCount) {\\n allStrategies[strategyIndex] = allStrategies[stratCount - 1];\\n allStrategies.pop();\\n\\n // Mark the strategy as not supported\\n strategies[_addr].isSupported = false;\\n isMintWhitelistedStrategy[_addr] = false;\\n\\n // Withdraw all asset\\n IStrategy strategy = IStrategy(_addr);\\n strategy.withdrawAll();\\n\\n // 1e13 for 18 decimals. And 1e1(10) for 6 decimals\\n uint256 maxDustBalance = uint256(1e13).scaleBy(assetDecimals, 18);\\n\\n /*\\n * Some strategies are not able to withdraw all of their funds in a synchronous call.\\n * Prevent the possible accidental removal of such strategies before their funds are withdrawn.\\n */\\n require(\\n strategy.checkBalance(asset) < maxDustBalance,\\n \\\"Strategy has funds\\\"\\n );\\n emit StrategyRemoved(_addr);\\n }\\n }\\n\\n /**\\n * @notice Adds a strategy to the mint whitelist.\\n * Reverts if strategy isn't approved on Vault.\\n * @param strategyAddr Strategy address\\n */\\n function addStrategyToMintWhitelist(address strategyAddr)\\n external\\n onlyGovernor\\n {\\n require(strategies[strategyAddr].isSupported, \\\"Strategy not approved\\\");\\n\\n require(\\n !isMintWhitelistedStrategy[strategyAddr],\\n \\\"Already whitelisted\\\"\\n );\\n\\n isMintWhitelistedStrategy[strategyAddr] = true;\\n\\n emit StrategyAddedToMintWhitelist(strategyAddr);\\n }\\n\\n /**\\n * @notice Removes a strategy from the mint whitelist.\\n * @param strategyAddr Strategy address\\n */\\n function removeStrategyFromMintWhitelist(address strategyAddr)\\n external\\n onlyGovernor\\n {\\n // Intentionally skipping `strategies.isSupported` check since\\n // we may wanna remove an address even after removing the strategy\\n\\n require(isMintWhitelistedStrategy[strategyAddr], \\\"Not whitelisted\\\");\\n\\n isMintWhitelistedStrategy[strategyAddr] = false;\\n\\n emit StrategyRemovedFromMintWhitelist(strategyAddr);\\n }\\n\\n /***************************************\\n Strategies\\n ****************************************/\\n\\n /**\\n * @notice Deposit multiple asset from the vault into the strategy.\\n * @param _strategyToAddress Address of the Strategy to deposit asset into.\\n * @param _assets Array of asset address that will be deposited into the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to deposit.\\n */\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _depositToStrategy(_strategyToAddress, _assets, _amounts);\\n }\\n\\n function _depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyToAddress].isSupported,\\n \\\"Invalid to Strategy\\\"\\n );\\n require(\\n _assets.length == 1 && _amounts.length == 1 && _assets[0] == asset,\\n \\\"Only asset is supported\\\"\\n );\\n\\n // Check the there is enough asset to transfer once the backing\\n // asset reserved for the withdrawal queue is accounted for\\n require(\\n _amounts[0] <= _assetAvailable(),\\n \\\"Not enough assets available\\\"\\n );\\n\\n // Send required amount of funds to the strategy\\n IERC20(asset).safeTransfer(_strategyToAddress, _amounts[0]);\\n\\n // Deposit all the funds that have been sent to the strategy\\n IStrategy(_strategyToAddress).depositAll();\\n }\\n\\n /**\\n * @notice Withdraw multiple asset from the strategy to the vault.\\n * @param _strategyFromAddress Address of the Strategy to withdraw asset from.\\n * @param _assets Array of asset address that will be withdrawn from the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to withdraw.\\n */\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _withdrawFromStrategy(\\n address(this),\\n _strategyFromAddress,\\n _assets,\\n _amounts\\n );\\n }\\n\\n /**\\n * @param _recipient can either be a strategy or the Vault\\n */\\n function _withdrawFromStrategy(\\n address _recipient,\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyFromAddress].isSupported,\\n \\\"Invalid from Strategy\\\"\\n );\\n require(_assets.length == _amounts.length, \\\"Parameter length mismatch\\\");\\n\\n uint256 assetCount = _assets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n // Withdraw from Strategy to the recipient\\n IStrategy(_strategyFromAddress).withdraw(\\n _recipient,\\n _assets[i],\\n _amounts[i]\\n );\\n }\\n\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @notice Sets the maximum allowable difference between\\n * total supply and asset' value.\\n */\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\\n maxSupplyDiff = _maxSupplyDiff;\\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\\n }\\n\\n /**\\n * @notice Sets the trusteeAddress that can receive a portion of yield.\\n * Setting to the zero address disables this feature.\\n */\\n function setTrusteeAddress(address _address) external onlyGovernor {\\n trusteeAddress = _address;\\n emit TrusteeAddressChanged(_address);\\n }\\n\\n /**\\n * @notice Sets the TrusteeFeeBps to the percentage of yield that should be\\n * received in basis points.\\n */\\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\\n require(_basis <= 5000, \\\"basis cannot exceed 50%\\\");\\n trusteeFeeBps = _basis;\\n emit TrusteeFeeBpsChanged(_basis);\\n }\\n\\n /***************************************\\n Pause\\n ****************************************/\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent rebasing.\\n */\\n function pauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = true;\\n emit RebasePaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to allow rebasing.\\n */\\n function unpauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = false;\\n emit RebaseUnpaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent capital movement.\\n */\\n function pauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = true;\\n emit CapitalPaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to false to enable capital movement.\\n */\\n function unpauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = false;\\n emit CapitalUnpaused();\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\\n * contract, i.e. mistaken sends.\\n * @param _asset Address for the asset\\n * @param _amount Amount of the asset to transfer\\n */\\n function transferToken(address _asset, uint256 _amount)\\n external\\n onlyGovernor\\n {\\n require(asset != _asset, \\\"Only unsupported asset\\\");\\n IERC20(_asset).safeTransfer(governor(), _amount);\\n }\\n\\n /***************************************\\n Strategies Admin\\n ****************************************/\\n\\n /**\\n * @notice Withdraws all asset from the strategy and sends asset to the Vault.\\n * @param _strategyAddr Strategy address.\\n */\\n function withdrawAllFromStrategy(address _strategyAddr)\\n external\\n onlyGovernorOrStrategist\\n {\\n _withdrawAllFromStrategy(_strategyAddr);\\n }\\n\\n function _withdrawAllFromStrategy(address _strategyAddr) internal virtual {\\n require(\\n strategies[_strategyAddr].isSupported,\\n \\\"Strategy is not supported\\\"\\n );\\n IStrategy strategy = IStrategy(_strategyAddr);\\n strategy.withdrawAll();\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @notice Withdraws all asset from all the strategies and sends asset to the Vault.\\n */\\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\\n _withdrawAllFromStrategies();\\n }\\n\\n function _withdrawAllFromStrategies() internal virtual {\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy(allStrategies[i]).withdrawAll();\\n }\\n _addWithdrawalQueueLiquidity();\\n }\\n}\\n\",\"keccak256\":\"0x3ba59fd88e9e3dae7197f04bc76213143f36b2e0922958c6f69d406a4a25f9c2\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultCore.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultCore contract\\n * @notice The Vault contract stores asset. On a deposit, OTokens will be minted\\n and sent to the depositor. On a withdrawal, OTokens will be burned and\\n asset will be sent to the withdrawer. The Vault accepts deposits of\\n interest from yield bearing strategies which will modify the supply\\n of OTokens.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\n\\nimport \\\"./VaultInitializer.sol\\\";\\n\\nabstract contract VaultCore is VaultInitializer {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n\\n /**\\n * @dev Verifies that the rebasing is not paused.\\n */\\n modifier whenNotRebasePaused() {\\n require(!rebasePaused, \\\"Rebasing paused\\\");\\n _;\\n }\\n\\n /**\\n * @dev Verifies that the deposits are not paused.\\n */\\n modifier whenNotCapitalPaused() {\\n require(!capitalPaused, \\\"Capital paused\\\");\\n _;\\n }\\n\\n constructor(address _asset) VaultInitializer(_asset) {}\\n\\n ////////////////////////////////////////////////////\\n /// MINT / BURN ///\\n ////////////////////////////////////////////////////\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @dev Deprecated: use `mint(uint256 _amount)` instead.\\n * @dev Deprecated: param _asset Address of the asset being deposited\\n * @param _amount Amount of the asset being deposited\\n * @dev Deprecated: param _minimumOusdAmount Minimum OTokens to mint\\n */\\n function mint(\\n address,\\n uint256 _amount,\\n uint256\\n ) external whenNotCapitalPaused nonReentrant {\\n _mint(_amount);\\n }\\n\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @param _amount Amount of the asset being deposited\\n */\\n function mint(uint256 _amount) external whenNotCapitalPaused nonReentrant {\\n _mint(_amount);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @dev Deposit a supported asset and mint OTokens.\\n * @param _amount Amount of the asset being deposited\\n */\\n function _mint(uint256 _amount) internal virtual {\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n\\n // Scale amount to 18 decimals\\n uint256 scaledAmount = _amount.scaleBy(18, assetDecimals);\\n\\n emit Mint(msg.sender, scaledAmount);\\n\\n // Rebase must happen before any transfers occur.\\n if (!rebasePaused && scaledAmount >= rebaseThreshold) {\\n _rebase();\\n }\\n\\n // Mint oTokens\\n oToken.mint(msg.sender, scaledAmount);\\n\\n IERC20(asset).safeTransferFrom(msg.sender, address(this), _amount);\\n\\n // Give priority to the withdrawal queue for the new asset liquidity\\n _addWithdrawalQueueLiquidity();\\n\\n // Auto-allocate if necessary\\n if (scaledAmount >= autoAllocateThreshold) {\\n _allocate();\\n }\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /**\\n * @notice Mint OTokens for an allowed Strategy\\n * @param _amount Amount of OToken to mint\\n *\\n * Notice: can't use `nonReentrant` modifier since the `mint` function can\\n * call `allocate`, and that can trigger an AMO strategy to call this function\\n * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function mintForStrategy(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n {\\n require(\\n strategies[msg.sender].isSupported == true,\\n \\\"Unsupported strategy\\\"\\n );\\n require(\\n isMintWhitelistedStrategy[msg.sender] == true,\\n \\\"Not whitelisted strategy\\\"\\n );\\n\\n emit Mint(msg.sender, _amount);\\n // Mint matching amount of OTokens\\n oToken.mint(msg.sender, _amount);\\n }\\n\\n /**\\n * @notice Burn OTokens for an allowed Strategy\\n * @param _amount Amount of OToken to burn\\n *\\n * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could\\n * require withdrawal on an AMO strategy and that one can call `burnForStrategy`\\n * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function burnForStrategy(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n {\\n require(\\n strategies[msg.sender].isSupported == true,\\n \\\"Unsupported strategy\\\"\\n );\\n require(\\n isMintWhitelistedStrategy[msg.sender] == true,\\n \\\"Not whitelisted strategy\\\"\\n );\\n\\n emit Redeem(msg.sender, _amount);\\n\\n // Burn OTokens\\n oToken.burn(msg.sender, _amount);\\n }\\n\\n ////////////////////////////////////////////////////\\n /// ASYNC WITHDRAWALS ///\\n ////////////////////////////////////////////////////\\n /**\\n * @notice Request an asynchronous withdrawal of asset in exchange for OToken.\\n * The OToken is burned on request and the asset is transferred to the withdrawer on claim.\\n * This request can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal this request's `queued` amount.\\n * There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs\\n * enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue.\\n * OToken is converted to asset at 1:1.\\n * @param _amount Amount of OToken to burn.\\n * @return requestId Unique ID for the withdrawal request\\n * @return queued Cumulative total of all asset queued including already claimed requests.\\n */\\n function requestWithdrawal(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 requestId, uint256 queued)\\n {\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n require(withdrawalClaimDelay > 0, \\\"Async withdrawals not enabled\\\");\\n\\n // The check that the requester has enough OToken is done in to later burn call\\n\\n requestId = withdrawalQueueMetadata.nextWithdrawalIndex;\\n queued =\\n withdrawalQueueMetadata.queued +\\n _amount.scaleBy(assetDecimals, 18);\\n\\n // Store the next withdrawal request\\n withdrawalQueueMetadata.nextWithdrawalIndex = SafeCast.toUint128(\\n requestId + 1\\n );\\n // Store the updated queued amount which reserves asset in the withdrawal queue\\n // and reduces the vault's total asset\\n withdrawalQueueMetadata.queued = SafeCast.toUint128(queued);\\n // Store the user's withdrawal request\\n // `queued` is in asset decimals, while `amount` is in OToken decimals (18)\\n withdrawalRequests[requestId] = WithdrawalRequest({\\n withdrawer: msg.sender,\\n claimed: false,\\n timestamp: uint40(block.timestamp),\\n amount: SafeCast.toUint128(_amount),\\n queued: SafeCast.toUint128(queued)\\n });\\n\\n // Burn the user's OToken\\n oToken.burn(msg.sender, _amount);\\n\\n // Prevent withdrawal if the vault is solvent by more than the allowed percentage\\n _postRedeem(_amount);\\n\\n emit WithdrawalRequested(msg.sender, requestId, _amount, queued);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Claim a previously requested withdrawal once it is claimable.\\n * This request can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal this request's `queued` amount and 10 minutes has passed.\\n * If the requests is not claimable, the transaction will revert with `Queue pending liquidity`.\\n * If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`.\\n * OToken is converted to asset at 1:1.\\n * @param _requestId Unique ID for the withdrawal request\\n * @return amount Amount of asset transferred to the withdrawer\\n */\\n function claimWithdrawal(uint256 _requestId)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 amount)\\n {\\n // Try and get more liquidity if there is not enough available\\n if (\\n withdrawalRequests[_requestId].queued >\\n withdrawalQueueMetadata.claimable\\n ) {\\n // Add any asset to the withdrawal queue\\n // this needs to remain here as:\\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\\n // - funds can be withdrawn from a strategy\\n //\\n // Those funds need to be added to withdrawal queue liquidity\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n // Scale amount to asset decimals\\n amount = _claimWithdrawal(_requestId);\\n\\n // transfer asset from the vault to the withdrawer\\n IERC20(asset).safeTransfer(msg.sender, amount);\\n\\n // Prevent insolvency\\n _postRedeem(amount.scaleBy(18, assetDecimals));\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n /**\\n * @notice Claim a previously requested withdrawals once they are claimable.\\n * This requests can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal each request's `queued` amount and 10 minutes has passed.\\n * If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`.\\n * If one of the requests is not older than 10 minutes,\\n * the whole transaction will revert with `Claim delay not met`.\\n * @param _requestIds Unique ID of each withdrawal request\\n * @return amounts Amount of asset received for each request\\n * @return totalAmount Total amount of asset transferred to the withdrawer\\n */\\n function claimWithdrawals(uint256[] calldata _requestIds)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256[] memory amounts, uint256 totalAmount)\\n {\\n // Add any asset to the withdrawal queue\\n // this needs to remain here as:\\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\\n // - funds can be withdrawn from a strategy\\n //\\n // Those funds need to be added to withdrawal queue liquidity\\n _addWithdrawalQueueLiquidity();\\n\\n amounts = new uint256[](_requestIds.length);\\n for (uint256 i; i < _requestIds.length; ++i) {\\n // Scale all amounts to asset decimals, thus totalAmount is also in asset decimals\\n amounts[i] = _claimWithdrawal(_requestIds[i]);\\n totalAmount += amounts[i];\\n }\\n\\n // transfer all the claimed asset from the vault to the withdrawer\\n IERC20(asset).safeTransfer(msg.sender, totalAmount);\\n\\n // Prevent insolvency\\n _postRedeem(totalAmount.scaleBy(18, assetDecimals));\\n\\n return (amounts, totalAmount);\\n }\\n\\n function _claimWithdrawal(uint256 requestId)\\n internal\\n returns (uint256 amount)\\n {\\n require(withdrawalClaimDelay > 0, \\\"Async withdrawals not enabled\\\");\\n\\n // Load the structs from storage into memory\\n WithdrawalRequest memory request = withdrawalRequests[requestId];\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n require(\\n request.timestamp + withdrawalClaimDelay <= block.timestamp,\\n \\\"Claim delay not met\\\"\\n );\\n // If there isn't enough reserved liquidity in the queue to claim\\n require(request.queued <= queue.claimable, \\\"Queue pending liquidity\\\");\\n require(request.withdrawer == msg.sender, \\\"Not requester\\\");\\n require(request.claimed == false, \\\"Already claimed\\\");\\n\\n // Store the request as claimed\\n withdrawalRequests[requestId].claimed = true;\\n // Store the updated claimed amount\\n withdrawalQueueMetadata.claimed =\\n queue.claimed +\\n SafeCast.toUint128(\\n StableMath.scaleBy(request.amount, assetDecimals, 18)\\n );\\n\\n emit WithdrawalClaimed(msg.sender, requestId, request.amount);\\n\\n return StableMath.scaleBy(request.amount, assetDecimals, 18);\\n }\\n\\n function _postRedeem(uint256 _amount) internal {\\n // Until we can prove that we won't affect the prices of our asset\\n // by withdrawing them, this should be here.\\n // It's possible that a strategy was off on its asset total, perhaps\\n // a reward token sold for more or for less than anticipated.\\n uint256 totalUnits = 0;\\n if (_amount >= rebaseThreshold && !rebasePaused) {\\n totalUnits = _rebase();\\n } else {\\n totalUnits = _totalValue();\\n }\\n\\n // Check that the OTokens are backed by enough asset\\n if (maxSupplyDiff > 0) {\\n // If there are more outstanding withdrawal requests than asset in the vault and strategies\\n // then the available asset will be negative and totalUnits will be rounded up to zero.\\n // As we don't know the exact shortfall amount, we will reject all redeem and withdrawals\\n require(totalUnits > 0, \\\"Too many outstanding requests\\\");\\n\\n // Allow a max difference of maxSupplyDiff% between\\n // asset value and OUSD total supply\\n uint256 diff = oToken.totalSupply().divPrecisely(totalUnits);\\n require(\\n (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,\\n \\\"Backing supply liquidity error\\\"\\n );\\n }\\n }\\n\\n /**\\n * @notice Allocate unallocated funds on Vault to strategies.\\n */\\n function allocate() external virtual whenNotCapitalPaused nonReentrant {\\n // Add any unallocated asset to the withdrawal queue first\\n _addWithdrawalQueueLiquidity();\\n\\n _allocate();\\n }\\n\\n /**\\n * @dev Allocate asset (eg. WETH or USDC) to the default asset strategy\\n * if there is excess to the Vault buffer.\\n * This is called from either `mint` or `allocate` and assumes `_addWithdrawalQueueLiquidity`\\n * has been called before this function.\\n */\\n function _allocate() internal virtual {\\n // No need to do anything if no default strategy for asset\\n address depositStrategyAddr = defaultStrategy;\\n if (depositStrategyAddr == address(0)) return;\\n\\n uint256 assetAvailableInVault = _assetAvailable();\\n // No need to do anything if there isn't any asset in the vault to allocate\\n if (assetAvailableInVault == 0) return;\\n\\n // Calculate the target buffer for the vault using the total supply\\n uint256 totalSupply = oToken.totalSupply();\\n // Scaled to asset decimals\\n uint256 targetBuffer = totalSupply.mulTruncate(vaultBuffer).scaleBy(\\n assetDecimals,\\n 18\\n );\\n\\n // If available asset in the Vault is below or equal the target buffer then there's nothing to allocate\\n if (assetAvailableInVault <= targetBuffer) return;\\n\\n // The amount of asset to allocate to the default strategy\\n uint256 allocateAmount = assetAvailableInVault - targetBuffer;\\n\\n IStrategy strategy = IStrategy(depositStrategyAddr);\\n // Transfer asset to the strategy and call the strategy's deposit function\\n IERC20(asset).safeTransfer(address(strategy), allocateAmount);\\n strategy.deposit(asset, allocateAmount);\\n\\n emit AssetAllocated(asset, depositStrategyAddr, allocateAmount);\\n }\\n\\n /**\\n * @notice Calculate the total value of asset held by the Vault and all\\n * strategies and update the supply of OTokens.\\n */\\n function rebase() external virtual nonReentrant {\\n _rebase();\\n }\\n\\n /**\\n * @dev Calculate the total value of asset held by the Vault and all\\n * strategies and update the supply of OTokens, optionally sending a\\n * portion of the yield to the trustee.\\n * @return totalUnits Total balance of Vault in units\\n */\\n function _rebase() internal whenNotRebasePaused returns (uint256) {\\n uint256 supply = oToken.totalSupply();\\n uint256 vaultValue = _totalValue();\\n // If no supply yet, do not rebase\\n if (supply == 0) {\\n return vaultValue;\\n }\\n\\n // Calculate yield and new supply\\n (uint256 yield, uint256 targetRate) = _nextYield(supply, vaultValue);\\n uint256 newSupply = supply + yield;\\n // Only rebase upwards and if we have enough backing funds\\n if (newSupply <= supply || newSupply > vaultValue) {\\n return vaultValue;\\n }\\n\\n rebasePerSecondTarget = uint64(_min(targetRate, type(uint64).max));\\n lastRebase = uint64(block.timestamp); // Intentional cast\\n\\n // Fee collection on yield\\n address _trusteeAddress = trusteeAddress; // gas savings\\n uint256 fee = 0;\\n if (_trusteeAddress != address(0)) {\\n fee = (yield * trusteeFeeBps) / 1e4;\\n if (fee > 0) {\\n require(fee < yield, \\\"Fee must not be greater than yield\\\");\\n oToken.mint(_trusteeAddress, fee);\\n }\\n }\\n emit YieldDistribution(_trusteeAddress, yield, fee);\\n\\n // Only ratchet OToken supply upwards\\n // Final check uses latest totalSupply\\n if (newSupply > oToken.totalSupply()) {\\n oToken.changeSupply(newSupply);\\n }\\n return vaultValue;\\n }\\n\\n /**\\n * @notice Calculates the amount that would rebase at next rebase.\\n * This is before any fees.\\n * @return yield amount of expected yield\\n */\\n function previewYield() external view returns (uint256 yield) {\\n (yield, ) = _nextYield(oToken.totalSupply(), _totalValue());\\n return yield;\\n }\\n\\n /**\\n * @dev Calculates the amount that would rebase at next rebase.\\n * See this Readme for detailed explanation:\\n * contracts/contracts/vault/README - Yield Limits.md\\n */\\n function _nextYield(uint256 supply, uint256 vaultValue)\\n internal\\n view\\n virtual\\n returns (uint256 yield, uint256 targetRate)\\n {\\n uint256 nonRebasing = oToken.nonRebasingSupply();\\n uint256 rebasing = supply - nonRebasing;\\n uint256 elapsed = block.timestamp - lastRebase;\\n targetRate = rebasePerSecondTarget;\\n\\n if (\\n elapsed == 0 || // Yield only once per block.\\n rebasing == 0 || // No yield if there are no rebasing tokens to give it to.\\n supply > vaultValue || // No yield if we do not have yield to give.\\n block.timestamp >= type(uint64).max // No yield if we are too far in the future to calculate it correctly.\\n ) {\\n return (0, targetRate);\\n }\\n\\n // Start with the full difference available\\n yield = vaultValue - supply;\\n\\n // Cap via optional automatic duration smoothing\\n uint256 _dripDuration = dripDuration;\\n if (_dripDuration > 1) {\\n // If we are able to sustain an increased drip rate for\\n // double the duration, then increase the target drip rate\\n targetRate = _max(targetRate, yield / (_dripDuration * 2));\\n // If we cannot sustain the target rate any more,\\n // then rebase what we can, and reduce the target\\n targetRate = _min(targetRate, yield / _dripDuration);\\n // drip at the new target rate\\n yield = _min(yield, targetRate * elapsed);\\n }\\n\\n // Cap per second. elapsed is not 1e18 denominated\\n yield = _min(yield, (rebasing * elapsed * rebasePerSecondMax) / 1e18);\\n\\n // Cap at a hard max per rebase, to avoid long durations resulting in huge rebases\\n yield = _min(yield, (rebasing * MAX_REBASE) / 1e18);\\n\\n return (yield, targetRate);\\n }\\n\\n /**\\n * @notice Determine the total value of asset held by the vault and its\\n * strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function totalValue() external view virtual returns (uint256 value) {\\n value = _totalValue();\\n }\\n\\n /**\\n * @dev Internal Calculate the total value of the asset held by the\\n * vault and its strategies.\\n * @dev The total value of all WETH held by the vault and all its strategies\\n * less any WETH that is reserved for the withdrawal queue.\\n * If there is not enough WETH in the vault and all strategies to cover\\n * all outstanding withdrawal requests then return a total value of 0.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValue() internal view virtual returns (uint256 value) {\\n // As asset is the only asset, just return the asset balance\\n value = _checkBalance(asset).scaleBy(18, assetDecimals);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @param _asset Address of asset\\n * @return uint256 Balance of asset in decimals of asset\\n */\\n function checkBalance(address _asset) external view returns (uint256) {\\n return _checkBalance(_asset);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @dev Get the balance of an asset held in Vault and all strategies\\n * less any asset that is reserved for the withdrawal queue.\\n * BaseAsset is the only asset that can return a non-zero balance.\\n * All other asset will return 0 even if there is some dust amounts left in the Vault.\\n * For example, there is 1 wei left of stETH (or USDC) in the OETH (or OUSD) Vault but\\n * will return 0 in this function.\\n *\\n * If there is not enough asset in the vault and all strategies to cover all outstanding\\n * withdrawal requests then return a asset balance of 0\\n * @param _asset Address of asset\\n * @return balance Balance of asset in decimals of asset\\n */\\n function _checkBalance(address _asset)\\n internal\\n view\\n virtual\\n returns (uint256 balance)\\n {\\n if (_asset != asset) return 0;\\n\\n // Get the asset in the vault and the strategies\\n IERC20 asset = IERC20(_asset);\\n balance = asset.balanceOf(address(this));\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy strategy = IStrategy(allStrategies[i]);\\n if (strategy.supportsAsset(_asset)) {\\n balance = balance + strategy.checkBalance(_asset);\\n }\\n }\\n\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // If the vault becomes insolvent enough that the total value in the vault and all strategies\\n // is less than the outstanding withdrawals.\\n // For example, there was a mass slashing event and most users request a withdrawal.\\n if (balance + queue.claimed < queue.queued) {\\n return 0;\\n }\\n\\n // Need to remove asset that is reserved for the withdrawal queue\\n return balance + queue.claimed - queue.queued;\\n }\\n\\n /**\\n * @notice Adds WETH to the withdrawal queue if there is a funding shortfall.\\n * @dev is called from the Native Staking strategy when validator withdrawals are processed.\\n * It also called before any WETH is allocated to a strategy.\\n */\\n function addWithdrawalQueueLiquidity() external {\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @dev Adds asset (eg. WETH or USDC) to the withdrawal queue if there is a funding shortfall.\\n * This assumes 1 asset equal 1 corresponding OToken.\\n */\\n function _addWithdrawalQueueLiquidity()\\n internal\\n returns (uint256 addedClaimable)\\n {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // Check if the claimable asset is less than the queued amount\\n uint256 queueShortfall = queue.queued - queue.claimable;\\n\\n // No need to do anything is the withdrawal queue is full funded\\n if (queueShortfall == 0) {\\n return 0;\\n }\\n\\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\\n\\n // Of the claimable withdrawal requests, how much is unclaimed?\\n // That is, the amount of asset that is currently allocated for the withdrawal queue\\n uint256 allocatedBaseAsset = queue.claimable - queue.claimed;\\n\\n // If there is no unallocated asset then there is nothing to add to the queue\\n if (assetBalance <= allocatedBaseAsset) {\\n return 0;\\n }\\n\\n uint256 unallocatedBaseAsset = assetBalance - allocatedBaseAsset;\\n // the new claimable amount is the smaller of the queue shortfall or unallocated asset\\n addedClaimable = queueShortfall < unallocatedBaseAsset\\n ? queueShortfall\\n : unallocatedBaseAsset;\\n uint256 newClaimable = queue.claimable + addedClaimable;\\n\\n // Store the new claimable amount back to storage\\n withdrawalQueueMetadata.claimable = SafeCast.toUint128(newClaimable);\\n\\n // emit a WithdrawalClaimable event\\n emit WithdrawalClaimable(newClaimable, addedClaimable);\\n }\\n\\n /**\\n * @dev Calculate how much asset (eg. WETH or USDC) in the vault is not reserved for the withdrawal queue.\\n * That is, it is available to be redeemed or deposited into a strategy.\\n */\\n function _assetAvailable() internal view returns (uint256 assetAvailable) {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // The amount of asset that is still to be claimed in the withdrawal queue\\n uint256 outstandingWithdrawals = queue.queued - queue.claimed;\\n\\n // The amount of sitting in asset in the vault\\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\\n // If there is not enough asset in the vault to cover the outstanding withdrawals\\n if (assetBalance <= outstandingWithdrawals) return 0;\\n\\n return assetBalance - outstandingWithdrawals;\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Return the number of asset supported by the Vault.\\n */\\n function getAssetCount() public view returns (uint256) {\\n return 1;\\n }\\n\\n /**\\n * @notice Return all vault asset addresses in order\\n */\\n function getAllAssets() external view returns (address[] memory) {\\n address[] memory a = new address[](1);\\n a[0] = asset;\\n return a;\\n }\\n\\n /**\\n * @notice Return the number of strategies active on the Vault.\\n */\\n function getStrategyCount() external view returns (uint256) {\\n return allStrategies.length;\\n }\\n\\n /**\\n * @notice Return the array of all strategies\\n */\\n function getAllStrategies() external view returns (address[] memory) {\\n return allStrategies;\\n }\\n\\n /**\\n * @notice Returns whether the vault supports the asset\\n * @param _asset address of the asset\\n * @return true if supported\\n */\\n function isSupportedAsset(address _asset) external view returns (bool) {\\n return asset == _asset;\\n }\\n\\n function _min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n function _max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a > b ? a : b;\\n }\\n}\\n\",\"keccak256\":\"0xf5c7295587db70ea009853009724ded12486dfabf420d589ee1eec37e9a681eb\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultInitializer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultInitializer contract\\n * @notice The Vault contract initializes the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport \\\"./VaultStorage.sol\\\";\\n\\nabstract contract VaultInitializer is VaultStorage {\\n constructor(address _asset) VaultStorage(_asset) {}\\n\\n function initialize(address _oToken) external onlyGovernor initializer {\\n require(_oToken != address(0), \\\"oToken address is zero\\\");\\n\\n oToken = OUSD(_oToken);\\n\\n rebasePaused = false;\\n capitalPaused = true;\\n\\n // Initial Vault buffer of 0%\\n vaultBuffer = 0;\\n // Initial allocate threshold of 25,000 OUSD\\n autoAllocateThreshold = 25000e18;\\n // Threshold for rebasing\\n rebaseThreshold = 1000e18;\\n // Initialize all strategies\\n allStrategies = new address[](0);\\n // Start with drip duration: 7 days\\n dripDuration = 604800;\\n }\\n}\\n\",\"keccak256\":\"0xb0b99b4b9279ab87b6008fb9675b581cc009a51cc5f9c0fb838eda86b1bca02b\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultStorage.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultStorage contract\\n * @notice The VaultStorage contract defines the storage for the Vault contracts\\n * @author Origin Protocol Inc\\n */\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { IERC20Metadata } from \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { OUSD } from \\\"../token/OUSD.sol\\\";\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport \\\"../utils/Helpers.sol\\\";\\n\\nabstract contract VaultStorage is Initializable, Governable {\\n using SafeERC20 for IERC20;\\n\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event DefaultStrategyUpdated(address _strategy);\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\\n event DripDurationChanged(uint256 dripDuration);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\\n\\n // Since we are proxy, all state should be uninitalized.\\n // Since this storage contract does not have logic directly on it\\n // we should not be checking for to see if these variables can be constant.\\n // slither-disable-start uninitialized-state\\n // slither-disable-start constable-states\\n\\n /// @dev mapping of supported vault assets to their configuration\\n uint256 private _deprecated_assets;\\n /// @dev list of all assets supported by the vault.\\n address[] private _deprecated_allAssets;\\n\\n // Strategies approved for use by the Vault\\n struct Strategy {\\n bool isSupported;\\n uint256 _deprecated; // Deprecated storage slot\\n }\\n /// @dev mapping of strategy contracts to their configuration\\n mapping(address => Strategy) public strategies;\\n /// @dev list of all vault strategies\\n address[] internal allStrategies;\\n\\n /// @notice Address of the Oracle price provider contract\\n address private _deprecated_priceProvider;\\n /// @notice pause rebasing if true\\n bool public rebasePaused;\\n /// @notice pause operations that change the OToken supply.\\n /// eg mint, redeem, allocate, mint/burn for strategy\\n bool public capitalPaused;\\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\\n uint256 private _deprecated_redeemFeeBps;\\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\\n uint256 public vaultBuffer;\\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\\n uint256 public autoAllocateThreshold;\\n /// @notice OToken mints over this amount automatically rebase. 18 decimals.\\n uint256 public rebaseThreshold;\\n\\n /// @dev Address of the OToken token. eg OUSD or OETH.\\n OUSD public oToken;\\n\\n /// @dev Address of the contract responsible for post rebase syncs with AMMs\\n address private _deprecated_rebaseHooksAddr = address(0);\\n\\n /// @dev Deprecated: Address of Uniswap\\n address private _deprecated_uniswapAddr = address(0);\\n\\n /// @notice Address of the Strategist\\n address public strategistAddr = address(0);\\n\\n /// @notice Mapping of asset address to the Strategy that they should automatically\\n // be allocated to\\n uint256 private _deprecated_assetDefaultStrategies;\\n\\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\\n uint256 public maxSupplyDiff;\\n\\n /// @notice Trustee contract that can collect a percentage of yield\\n address public trusteeAddress;\\n\\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\\n uint256 public trusteeFeeBps;\\n\\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\\n address[] private _deprecated_swapTokens;\\n\\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\\n\\n address private _deprecated_ousdMetaStrategy;\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n int256 private _deprecated_netOusdMintedForStrategy;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n uint256 private _deprecated_netOusdMintForStrategyThreshold;\\n\\n uint256 private _deprecated_swapConfig;\\n\\n // List of strategies that can mint oTokens directly\\n // Used in OETHBaseVaultCore\\n mapping(address => bool) public isMintWhitelistedStrategy;\\n\\n /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\\n /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\\n address private _deprecated_dripper;\\n\\n /// Withdrawal Queue Storage /////\\n\\n struct WithdrawalQueueMetadata {\\n // cumulative total of all withdrawal requests included the ones that have already been claimed\\n uint128 queued;\\n // cumulative total of all the requests that can be claimed including the ones that have already been claimed\\n uint128 claimable;\\n // total of all the requests that have been claimed\\n uint128 claimed;\\n // index of the next withdrawal request starting at 0\\n uint128 nextWithdrawalIndex;\\n }\\n\\n /// @notice Global metadata for the withdrawal queue including:\\n /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed\\n /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed\\n /// claimed - total of all the requests that have been claimed\\n /// nextWithdrawalIndex - index of the next withdrawal request starting at 0\\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\\n\\n struct WithdrawalRequest {\\n address withdrawer;\\n bool claimed;\\n uint40 timestamp; // timestamp of the withdrawal request\\n // Amount of oTokens to redeem. eg OETH\\n uint128 amount;\\n // cumulative total of all withdrawal requests including this one.\\n // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\\n uint128 queued;\\n }\\n\\n /// @notice Mapping of withdrawal request indices to the user withdrawal request data\\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\\n\\n /// @notice Sets a minimum delay that is required to elapse between\\n /// requesting async withdrawals and claiming the request.\\n /// When set to 0 async withdrawals are disabled.\\n uint256 public withdrawalClaimDelay;\\n\\n /// @notice Time in seconds that the vault last rebased yield.\\n uint64 public lastRebase;\\n\\n /// @notice Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\\n uint64 public dripDuration;\\n\\n /// @notice max rebase percentage per second\\n /// Can be used to set maximum yield of the protocol,\\n /// spreading out yield over time\\n uint64 public rebasePerSecondMax;\\n\\n /// @notice target rebase rate limit, based on past rates and funds available.\\n uint64 public rebasePerSecondTarget;\\n\\n uint256 internal constant MAX_REBASE = 0.02 ether;\\n uint256 internal constant MAX_REBASE_PER_SECOND =\\n uint256(0.05 ether) / 1 days;\\n\\n /// @notice Default strategy for asset\\n address public defaultStrategy;\\n\\n // For future use\\n uint256[42] private __gap;\\n\\n /// @notice Index of WETH asset in allAssets array\\n /// Legacy OETHVaultCore code, relocated here for vault consistency.\\n uint256 private _deprecated_wethAssetIndex;\\n\\n /// @dev Address of the asset (eg. WETH or USDC)\\n address public immutable asset;\\n uint8 internal immutable assetDecimals;\\n\\n // slither-disable-end constable-states\\n // slither-disable-end uninitialized-state\\n\\n constructor(address _asset) {\\n uint8 _decimals = IERC20Metadata(_asset).decimals();\\n require(_decimals <= 18, \\\"invalid asset decimals\\\");\\n asset = _asset;\\n assetDecimals = _decimals;\\n }\\n\\n /// @notice Deprecated: use `oToken()` instead.\\n function oUSD() external view returns (OUSD) {\\n return oToken;\\n }\\n}\\n\",\"keccak256\":\"0xcca0e0ebbbbda50b23fba7aea96a1e34f6a9d58c8f2e86e84b0911d4a9e5d418\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x60c0604052603d80546001600160a01b0319908116909155603e805482169055603f8054909116905534801561003457600080fd5b5060405161544638038061544683398101604081905261005391610133565b808080806000816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100bb9190610163565b905060128160ff1611156101155760405162461bcd60e51b815260206004820152601660248201527f696e76616c696420617373657420646563696d616c7300000000000000000000604482015260640160405180910390fd5b6001600160a01b0390911660805260ff1660a0525061018692505050565b60006020828403121561014557600080fd5b81516001600160a01b038116811461015c57600080fd5b9392505050565b60006020828403121561017557600080fd5b815160ff8116811461015c57600080fd5b60805160a0516151e561026160003960008181610fa60152818161178b0152818161205401528181612c6f015281816131560152818161376201528181613806015281816140ae01526144630152600081816105870152818161089401528181610c4e01528181610fe4015281816112d301528181611438015281816117570152818161189401528181612c3b015281816132520152818161338001528181613b0501528181613dda01528181613f110152818161411901528181614164015281816141cc0152818161448a01526148c501526151e56000f3fe608060405234801561001057600080fd5b50600436106104075760003560e01c80636217f3ea11610220578063ae69f3cb11610130578063c5f00841116100b8578063d4c3eea011610087578063d4c3eea0146109e6578063e6cc5432146109ee578063ea33b8e414610a02578063f844443614610a0a578063fac5bb9b14610a1d57600080fd5b8063c5f00841146109bb578063c7af3352146109c3578063c9919112146109cb578063d38bfff4146109d357600080fd5b8063b890ebf6116100ff578063b890ebf61461096b578063b9b17f9f1461097e578063bb7a632e14610986578063c3b28864146109a0578063c4d66de8146109a857600080fd5b8063ae69f3cb1461092a578063af14052c1461093d578063b2c9336d14610945578063b4925a201461095857600080fd5b806394828ffd116101b35780639fa1826e116101825780639fa1826e146108ec578063a0712d68146108f5578063a0aead4d14610908578063ab80dafb1461090f578063abaa99161461092257600080fd5b806394828ffd1461086957806395b166bc146108715780639be918e6146108845780639ee679e8146108c457600080fd5b8063840c4c7a116101ef578063840c4c7a146107925780638e510b52146107a55780638ec489a2146107ae578063937b2581146107c157600080fd5b80636217f3ea14610746578063663e64ce14610759578063773540b31461076c57806378f353a11461077f57600080fd5b806339ebf8231161031b578063527e83a8116102ae57806357bee9441161027d57806357bee944146106f45780635802a17214610707578063597c8910146107185780635d36b1901461072b5780635f5152261461073357600080fd5b8063527e83a8146106aa57806352d38e5d146106c457806353ca9f24146106cd578063570d8e1d146106e157600080fd5b806345e4213b116102ea57806345e4213b1461063b57806348e30f541461064457806349c1d54d146106655780634d5f46291461067857600080fd5b806339ebf823146105a95780633b8ae397146105ed5780633dbc911f146106005780634530820a1461060857600080fd5b80631a32aad61161039e5780632acada4d1161036d5780632acada4d146104f35780632da845a81461050857806331e19cfa1461051b578063362bd1a31461052357806338d52e0f1461058257600080fd5b80631a32aad6146104ad5780631cfbe7bc146104c05780631edfe3da146104d3578063207134b0146104ea57600080fd5b80631072cbea116103da5780631072cbea14610461578063156e29f614610474578063175188e8146104875780631816dd4a1461049a57600080fd5b80630493a0fa1461040c57806309f49bf5146104215780630acbda75146104295780630c340a241461043c575b600080fd5b61041f61041a366004614b73565b610a30565b005b61041f610ae6565b61041f610437366004614b73565b610b56565b610444610c01565b6040516001600160a01b0390911681526020015b60405180910390f35b61041f61046f366004614ba8565b610c1e565b61041f610482366004614bd2565b610cdc565b61041f610495366004614c05565b610d4f565b61041f6104a8366004614c05565b6110e2565b603c54610444906001600160a01b031681565b61041f6104ce366004614b73565b6111e9565b6104dc60395481565b604051908152602001610458565b6104dc60435481565b6104fb6112ab565b6040516104589190614c20565b61041f610516366004614c05565b611322565b6036546104dc565b604b54604c5461054f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610458565b6104447f000000000000000000000000000000000000000000000000000000000000000081565b6105d66105b7366004614c05565b6035602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610458565b61041f6105fb366004614c05565b611394565b61041f6115a7565b61062b610616366004614c05565b60496020526000908152604090205460ff1681565b6040519015158152602001610458565b6104dc604e5481565b610657610652366004614cb0565b61161d565b604051610458929190614cf1565b604254610444906001600160a01b031681565b604f5461069290600160c01b90046001600160401b031681565b6040516001600160401b039091168152602001610458565b604f5461069290600160801b90046001600160401b031681565b6104dc603b5481565b60375461062b90600160a01b900460ff1681565b603f54610444906001600160a01b031681565b61041f610702366004614c05565b6117c2565b603c546001600160a01b0316610444565b61041f610726366004614c05565b611975565b61041f6119b9565b6104dc610741366004614c05565b611a5f565b61041f610754366004614b73565b611a70565b61041f610767366004614b73565b611bf4565b61041f61077a366004614c05565b611c4d565b604f54610692906001600160401b031681565b61041f6107a0366004614d3e565b611cbf565b6104dc60415481565b61041f6107bc366004614b73565b611d46565b6108226107cf366004614b73565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a001610458565b61041f611dfb565b61041f61087f366004614c05565b611e6b565b61062b610892366004614c05565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b6108d76108d2366004614b73565b611f32565b60408051928352602083019190915201610458565b6104dc603a5481565b61041f610903366004614b73565b612273565b60016104dc565b61041f61091d366004614b73565b6122e4565b61041f612433565b61041f610938366004614d3e565b6124ab565b61041f612527565b61041f610953366004614b73565b61256d565b61041f610966366004614b73565b6125c6565b61041f610979366004614b73565b6126e4565b61041f61273d565b604f5461069290600160401b90046001600160401b031681565b6104fb612745565b61041f6109b6366004614c05565b6127a7565b61041f61295f565b61062b6129d5565b61041f612a06565b61041f6109e1366004614c05565b612a46565b6104dc612aea565b60375461062b90600160a81b900460ff1681565b6104dc612af4565b6104dc610a18366004614b73565b612b83565b605054610444906001600160a01b031681565b603f546001600160a01b0316331480610a4c5750610a4c6129d5565b610a715760405162461bcd60e51b8152600401610a6890614dc2565b60405180910390fd5b610a79612c9e565b50610a8381613038565b604f80546001600160401b0392909216600160401b0267ffffffffffffffff60401b199092169190911790556040518181527f406e15fbca1d8ded2dbb06765fea3a54f18395c54125a4c9916dd00ea14ee15e906020015b60405180910390a150565b603f546001600160a01b0316331480610b025750610b026129d5565b610b1e5760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b610b5e6129d5565b610b7a5760405162461bcd60e51b8152600401610a6890614e0a565b611388811115610bcc5760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f7420657863656564203530250000000000000000006044820152606401610a68565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c790602001610adb565b6000610c196000805160206151908339815191525490565b905090565b610c266129d5565b610c425760405162461bcd60e51b8152600401610a6890614e0a565b816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610cbc5760405162461bcd60e51b815260206004820152601660248201527513db9b1e481d5b9cdd5c1c1bdc9d195908185cdcd95d60521b6044820152606401610a68565b610cd8610cc7610c01565b6001600160a01b03841690836130a4565b5050565b603754600160a81b900460ff1615610d065760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101610d385760405162461bcd60e51b8152600401610a6890614e69565b60028255610d45846130fa565b5060019055505050565b610d576129d5565b610d735760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff16610dab5760405162461bcd60e51b8152600401610a6890614e91565b6050546001600160a01b03808316911603610e085760405162461bcd60e51b815260206004820152601d60248201527f53747261746567792069732064656661756c7420666f722061737365740000006044820152606401610a68565b6036548060005b82811015610e5e57836001600160a01b031660368281548110610e3457610e34614ec0565b6000918252602090912001546001600160a01b031603610e5657809150610e5e565b600101610e0f565b50818110156110dd576036610e74600184614eec565b81548110610e8457610e84614ec0565b600091825260209091200154603680546001600160a01b039092169183908110610eb057610eb0614ec0565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610eef57610eef614eff565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038516808352603582526040808420805460ff1990811690915560499093528084208054909316909255815163429c145b60e11b815291518693919263853828b692600480830193919282900301818387803b158015610f7b57600080fd5b505af1158015610f8f573d6000803e3d6000fd5b5060009250610fcd91506509184e72a000905060ff7f0000000000000000000000000000000000000000000000000000000000000000166012613296565b604051632fa8a91360e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192508291841690635f51522690602401602060405180830381865afa158015611038573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105c9190614f15565b1061109e5760405162461bcd60e51b81526020600482015260126024820152715374726174656779206861732066756e647360701b6044820152606401610a68565b6040516001600160a01b03861681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49060200160405180910390a150505b505050565b6110ea6129d5565b6111065760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff1661113e5760405162461bcd60e51b8152600401610a6890614e91565b6001600160a01b03811660009081526049602052604090205460ff161561119d5760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481dda1a5d195b1a5cdd1959606a1b6044820152606401610a68565b6001600160a01b038116600081815260496020526040808220805460ff19166001179055517f47c8c96a5942f094264111c5fe7f6a4fe86efe63254a6fa7afa5fc84f07d58e89190a250565b6111f16129d5565b61120d5760405162461bcd60e51b8152600401610a6890614e0a565b80158061122a5750610258811015801561122a57506213c6808111155b6112765760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636c61696d2064656c617920706572696f640000000000006044820152606401610a68565b604e8190556040518181527fc59f5e32049abab44ddea11021f5abb89422a2f550837afcf25df9fc8d0db6b090602001610adb565b60408051600180825281830190925260609160009190602080830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061130557611305614ec0565b6001600160a01b0390921660209283029190910190910152919050565b61132a6129d5565b6113465760405162461bcd60e51b8152600401610a6890614e0a565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610adb565b61139c6129d5565b6113b85760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff16156114215760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f766564000000000000006044820152606401610a68565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa158015611487573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ab9190614f44565b6114f75760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a68565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610adb565b603f546001600160a01b03163314806115c357506115c36129d5565b6115df5760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b603754606090600090600160a81b900460ff161561164d5760405162461bcd60e51b8152600401610a6890614e41565b6000805160206151708339815191528054600119810161167f5760405162461bcd60e51b8152600401610a6890614e69565b6002825561168b6132fa565b50846001600160401b038111156116a4576116a4614f2e565b6040519080825280602002602001820160405280156116cd578160200160208202803683370190505b50935060005b85811015611749576116fc8787838181106116f0576116f0614ec0565b905060200201356134d6565b85828151811061170e5761170e614ec0565b60200260200101818152505084818151811061172c5761172c614ec0565b60200260200101518461173f9190614f66565b93506001016116d3565b5061177e6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130a4565b6117b56117b084601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b613837565b6001825550509250929050565b603f546001600160a01b03163314806117de57506117de6129d5565b6117fa5760405162461bcd60e51b8152600401610a6890614dc2565b6040516001600160a01b03821681527f45a9e715f8779ebeab88d3e8d081fb8b484b7730857e7c4478a95a5b1d8f79489060200160405180910390a16001600160a01b03811615611953576001600160a01b03811660009081526035602052604090205460ff1661187d5760405162461bcd60e51b8152600401610a6890614e91565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa1580156118e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119079190614f44565b6119535760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a68565b605080546001600160a01b0319166001600160a01b0392909216919091179055565b603f546001600160a01b031633148061199157506119916129d5565b6119ad5760405162461bcd60e51b8152600401610a6890614dc2565b6119b6816139da565b50565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614611a545760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610a68565b611a5d33613aa2565b565b6000611a6a82613b01565b92915050565b603754600160a81b900460ff1615611a9a5760405162461bcd60e51b8152600401610a6890614e41565b3360009081526035602052604090205460ff161515600114611af55760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a68565b3360009081526049602052604090205460ff161515600114611b545760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a68565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051611b85929190614f79565b60405180910390a1603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90611bbf9033908590600401614f79565b600060405180830381600087803b158015611bd957600080fd5b505af1158015611bed573d6000803e3d6000fd5b5050505050565b611bfc6129d5565b611c185760405162461bcd60e51b8152600401610a6890614e0a565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610adb565b611c556129d5565b611c715760405162461bcd60e51b8152600401610a6890614e0a565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610adb565b603f546001600160a01b0316331480611cdb5750611cdb6129d5565b611cf75760405162461bcd60e51b8152600401610a6890614dc2565b60008051602061517083398151915280546001198101611d295760405162461bcd60e51b8152600401610a6890614e69565b60028255611d3a8787878787613d63565b50600190555050505050565b603f546001600160a01b0316331480611d625750611d626129d5565b611d7e5760405162461bcd60e51b8152600401610a6890614dc2565b670de0b6b3a7640000811115611dc65760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b6044820152606401610a68565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610adb565b603f546001600160a01b0316331480611e175750611e176129d5565b611e335760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e736129d5565b611e8f5760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526049602052604090205460ff16611ee95760405162461bcd60e51b815260206004820152600f60248201526e139bdd081dda1a5d195b1a5cdd1959608a1b6044820152606401610a68565b6001600160a01b038116600081815260496020526040808220805460ff19169055517f0ec40967a61509853550658e51d0e4297f7cba244fe4adc8ba18b5631ac20e2f9190a250565b6037546000908190600160a81b900460ff1615611f615760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101611f935760405162461bcd60e51b8152600401610a6890614e69565b6002825560008511611fe75760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a68565b6000604e54116120395760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a68565b604c54600160801b90046001600160801b0316935061207d857f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b604b5461209391906001600160801b0316614f66565b92506120a86120a3856001614f66565b613fa2565b604c80546001600160801b03928316600160801b0292169190911790556120ce83613fa2565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff16918101919091526060810161211e87613fa2565b6001600160801b0316815260200161213585613fa2565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906121f09033908990600401614f79565b600060405180830381600087803b15801561220a57600080fd5b505af115801561221e573d6000803e3d6000fd5b5050505061222b85613837565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff161561229d5760405162461bcd60e51b8152600401610a6890614e41565b600080516020615170833981519152805460011981016122cf5760405162461bcd60e51b8152600401610a6890614e69565b600282556122dc836130fa565b506001905550565b603754600160a81b900460ff161561230e5760405162461bcd60e51b8152600401610a6890614e41565b3360009081526035602052604090205460ff1615156001146123695760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a68565b3360009081526049602052604090205460ff1615156001146123c85760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a68565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516123f9929190614f79565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611bbf9033908590600401614f79565b603754600160a81b900460ff161561245d5760405162461bcd60e51b8152600401610a6890614e41565b6000805160206151708339815191528054600119810161248f5760405162461bcd60e51b8152600401610a6890614e69565b6002825561249b6132fa565b506124a461400b565b5060019055565b603f546001600160a01b03163314806124c757506124c76129d5565b6124e35760405162461bcd60e51b8152600401610a6890614dc2565b600080516020615170833981519152805460011981016125155760405162461bcd60e51b8152600401610a6890614e69565b60028255611d3a308888888888614234565b600080516020615170833981519152805460011981016125595760405162461bcd60e51b8152600401610a6890614e69565b60028255612565612c9e565b505060019055565b6125756129d5565b6125915760405162461bcd60e51b8152600401610a6890614e0a565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610adb565b603f546001600160a01b03163314806125e257506125e26129d5565b6125fe5760405162461bcd60e51b8152600401610a6890614dc2565b612606612c9e565b5060006301e13380612619606484614f92565b6126239190614f92565b90506126396201518066b1a2bc2ec50000614f92565b8111156126785760405162461bcd60e51b815260206004820152600d60248201526c0a4c2e8ca40e8dede40d0d2ced609b1b6044820152606401610a68565b61268181613038565b604f80546001600160401b0392909216600160801b0267ffffffffffffffff60801b199092169190911790556040518181527fef46f143af5fead0010484fe7d6ec2e2972420faa76157f5a6075aa72e614cb59060200160405180910390a15050565b6126ec6129d5565b6127085760405162461bcd60e51b8152600401610a6890614e0a565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d90602001610adb565b6119b66132fa565b6060603680548060200260200160405190810160405280929190818152602001828054801561279d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161277f575b5050505050905090565b6127af6129d5565b6127cb5760405162461bcd60e51b8152600401610a6890614e0a565b600054610100900460ff16806127e4575060005460ff16155b6128475760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a68565b600054610100900460ff16158015612869576000805461ffff19166101011790555b6001600160a01b0382166128b85760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b6044820152606401610a68565b603c80546001600160a01b0384166001600160a01b03199091161790556037805461ffff60a01b1916600160a81b1790556000603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b55604080519182526020820190819052905161292891603691614b02565b50604f805467ffffffffffffffff60401b19166a093a8000000000000000001790558015610cd8576000805461ff00191690555050565b603f546001600160a01b031633148061297b575061297b6129d5565b6129975760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b60006129ed6000805160206151908339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612a225750612a226129d5565b612a3e5760405162461bcd60e51b8152600401610a6890614dc2565b611a5d6143c5565b612a4e6129d5565b612a6a5760405162461bcd60e51b8152600401610a6890614e0a565b612a92817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612ab26000805160206151908339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000610c1961445a565b6000612b7d603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b709190614f15565b612b7861445a565b6144ae565b50919050565b603754600090600160a81b900460ff1615612bb05760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101612be25760405162461bcd60e51b8152600401610a6890614e69565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115612c2357612c216132fa565b505b612c2c846134d6565b9250612c626001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130a4565b612c946117b084601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b5060019055919050565b603754600090600160a01b900460ff1615612ced5760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b6044820152606401610a68565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612d37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d5b9190614f15565b90506000612d6761445a565b905081600003612d7a5791506130359050565b600080612d8784846144ae565b90925090506000612d988386614f66565b90508481111580612da857508381115b15612db7575091949350505050565b612dc8826001600160401b03614681565b604f805477ffffffffffffffffffffffffffffffff000000000000000016600160c01b6001600160401b039384160267ffffffffffffffff19161742929092169190911790556042546001600160a01b031660008115612f045761271060435486612e339190614fb4565b612e3d9190614f92565b90508015612f0457848110612e9f5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b6064820152608401610a68565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612ed19085908590600401614f79565b600060405180830381600087803b158015612eeb57600080fd5b505af1158015612eff573d6000803e3d6000fd5b505050505b604080516001600160a01b0384168152602081018790529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a1603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc59190614f15565b83111561302b57603c546040516339a7919f60e01b8152600481018590526001600160a01b03909116906339a7919f90602401600060405180830381600087803b15801561301257600080fd5b505af1158015613026573d6000803e3d6000fd5b505050505b5093955050505050505b90565b60006001600160401b038211156130a05760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610a68565b5090565b6110dd8363a9059cbb60e01b84846040516024016130c3929190614f79565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614697565b6000811161314a5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a68565b600061317b82601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b90507f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516131ae929190614f79565b60405180910390a1603754600160a01b900460ff161580156131d25750603b548110155b156131e1576131df612c9e565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132139033908590600401614f79565b600060405180830381600087803b15801561322d57600080fd5b505af1158015613241573d6000803e3d6000fd5b5061327c9250506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169050333085614769565b6132846132fa565b50603a548110610cd857610cd861400b565b6000818311156132c6576132bf6132ad8385614eec565b6132b890600a6150b2565b85906147a7565b93506132f0565b818310156132f0576132ed6132db8484614eec565b6132e690600a6150b2565b85906147b3565b93505b50825b9392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c548084169686019690965292909404166060830152600092839161334c916150be565b6001600160801b03169050806000036133685760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156133cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133f39190614f15565b905060008360400151846020015161340b91906150be565b6001600160801b0316905080821161342857600094505050505090565b60006134348284614eec565b90508084106134435780613445565b835b955060008686602001516001600160801b03166134629190614f66565b905061346d81613fa2565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f463333906134c59083908a90918252602082015260400190565b60405180910390a150505050505090565b600080604e54116135295760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a68565b6000828152604d6020908152604091829020825160a08101845281546001600160a01b038116825260ff600160a01b82041615158285015264ffffffffff600160a81b90910481168286019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915288519081018952604b548084168252849004831697810197909752604c54808316988801989098529190960490951694840194909452604e549151909342926135f092909116614f66565b11156136345760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b6044820152606401610a68565b80602001516001600160801b031682608001516001600160801b0316111561369e5760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c69717569646974790000000000000000006044820152606401610a68565b81516001600160a01b031633146136e75760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b6044820152606401610a68565b60208201511561372b5760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b6044820152606401610a68565b6000848152604d60205260409020805460ff60a01b1916600160a01b179055606082015161378b906120a3906001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b816040015161379a91906150dd565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a361382f82606001516001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b949350505050565b6000603b5482101580156138555750603754600160a01b900460ff16155b1561386957613862612c9e565b9050613874565b61387161445a565b90505b60415415610cd857600081116138cc5760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e672072657175657374730000006044820152606401610a68565b600061394f82603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613925573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139499190614f15565b906147bf565b9050604154670de0b6b3a7640000821161397a5761397582670de0b6b3a7640000614eec565b61398c565b61398c670de0b6b3a764000083614eec565b11156110dd5760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f7200006044820152606401610a68565b6001600160a01b03811660009081526035602052604090205460ff16613a425760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f72746564000000000000006044820152606401610a68565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a8257600080fd5b505af1158015613a96573d6000803e3d6000fd5b505050506110dd6132fa565b6001600160a01b038116613af85760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610a68565b6119b6816147e0565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614613b4457506000919050565b6040516370a0823160e01b815230600482015282906001600160a01b038216906370a0823190602401602060405180830381865afa158015613b8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bae9190614f15565b60365490925060005b81811015613cd357600060368281548110613bd457613bd4614ec0565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af690602401602060405180830381865afa158015613c2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4e9190614f44565b15613cca57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f51522690602401602060405180830381865afa158015613c99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cbd9190614f15565b613cc79086614f66565b94505b50600101613bb7565b5060408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529091613d219086614f66565b1015613d3257506000949350505050565b805160408201516001600160801b0391821691613d50911686614f66565b613d5a9190614eec565b95945050505050565b6001600160a01b03851660009081526035602052604090205460ff16613dc15760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b6044820152606401610a68565b600183148015613dd15750600181145b8015613e3557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684846000818110613e1557613e15614ec0565b9050602002016020810190613e2a9190614c05565b6001600160a01b0316145b613e815760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920617373657420697320737570706f727465640000000000000000006044820152606401610a68565b613e89614847565b82826000818110613e9c57613e9c614ec0565b905060200201351115613ef15760405162461bcd60e51b815260206004820152601b60248201527f4e6f7420656e6f7567682061737365747320617661696c61626c6500000000006044820152606401610a68565b613f488583836000818110613f0857613f08614ec0565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166130a49092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613f8357600080fd5b505af1158015613f97573d6000803e3d6000fd5b505050505050505050565b60006001600160801b038211156130a05760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610a68565b6050546001600160a01b03168061401f5750565b6000614029614847565b905080600003614037575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015614081573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140a59190614f15565b905060006140ee7f000000000000000000000000000000000000000000000000000000000000000060ff1660126140e76039548661495590919063ffffffff16565b9190613296565b90508083116140fd5750505050565b60006141098285614eec565b9050846141406001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682846130a4565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061418e907f0000000000000000000000000000000000000000000000000000000000000000908690600401614f79565b600060405180830381600087803b1580156141a857600080fd5b505af11580156141bc573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b6001600160a01b03851660009081526035602052604090205460ff166142945760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b6044820152606401610a68565b8281146142e35760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d61746368000000000000006044820152606401610a68565b8260005b818110156143b257866001600160a01b031663d9caed128988888581811061431157614311614ec0565b90506020020160208101906143269190614c05565b87878681811061433857614338614ec0565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561438f57600080fd5b505af11580156143a3573d6000803e3d6000fd5b505050508060010190506142e7565b506143bb6132fa565b5050505050505050565b60365460005b8181101561445157603681815481106143e6576143e6614ec0565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b15801561442e57600080fd5b505af1158015614442573d6000803e3d6000fd5b505050508060010190506143cb565b50610cd86132fa565b6000610c1960127f000000000000000000000000000000000000000000000000000000000000000060ff166140e77f0000000000000000000000000000000000000000000000000000000000000000613b01565b6000806000603c60009054906101000a90046001600160a01b03166001600160a01b031663e696393a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614506573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061452a9190614f15565b905060006145388287614eec565b604f54909150600090614554906001600160401b031642614eec565b604f54600160c01b90046001600160401b031694509050801580614576575081155b8061458057508587115b8061459257506001600160401b034210155b156145a3576000945050505061467a565b6145ad8787614eec565b604f54909550600160401b90046001600160401b03166001811115614612576145ea856145db836002614fb4565b6145e59089614f92565b61496a565b94506145ff856145fa8389614f92565b614681565b945061460f866145fa8488614fb4565b95505b604f54614653908790670de0b6b3a764000090600160801b90046001600160401b031661463f8688614fb4565b6146499190614fb4565b6145fa9190614f92565b955061467386670de0b6b3a764000061464966470de4df82000087614fb4565b9550505050505b9250929050565b600081831061469057816132f3565b5090919050565b60006146ec826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166149799092919063ffffffff16565b8051909150156110dd578080602001905181019061470a9190614f44565b6110dd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a68565b6040516001600160a01b03808516602483015283166044820152606481018290526147a19085906323b872dd60e01b906084016130c3565b50505050565b60006132f38284614fb4565b60006132f38284614f92565b6000806147d484670de0b6b3a76400006147a7565b905061382f81846147b3565b806001600160a01b03166148006000805160206151908339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a360008051602061519083398151915255565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c5480831695850186905292909204166060830152600092839161489791906150be565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561490c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149309190614f15565b9050818111614943576000935050505090565b61494d8282614eec565b935050505090565b60006132f38383670de0b6b3a7640000614988565b600081831161469057816132f3565b606061382f84846000856149a1565b60008061499585856147a7565b9050613d5a81846147b3565b606082471015614a025760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a68565b843b614a505760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a68565b600080866001600160a01b03168587604051614a6c9190615120565b60006040518083038185875af1925050503d8060008114614aa9576040519150601f19603f3d011682016040523d82523d6000602084013e614aae565b606091505b5091509150614abe828286614ac9565b979650505050505050565b60608315614ad85750816132f3565b825115614ae85782518084602001fd5b8160405162461bcd60e51b8152600401610a68919061513c565b828054828255906000526020600020908101928215614b57579160200282015b82811115614b5757825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614b22565b506130a09291505b808211156130a05760008155600101614b5f565b600060208284031215614b8557600080fd5b5035919050565b80356001600160a01b0381168114614ba357600080fd5b919050565b60008060408385031215614bbb57600080fd5b614bc483614b8c565b946020939093013593505050565b600080600060608486031215614be757600080fd5b614bf084614b8c565b95602085013595506040909401359392505050565b600060208284031215614c1757600080fd5b6132f382614b8c565b602080825282518282018190526000918401906040840190835b81811015614c615783516001600160a01b0316835260209384019390920191600101614c3a565b509095945050505050565b60008083601f840112614c7e57600080fd5b5081356001600160401b03811115614c9557600080fd5b6020830191508360208260051b850101111561467a57600080fd5b60008060208385031215614cc357600080fd5b82356001600160401b03811115614cd957600080fd5b614ce585828601614c6c565b90969095509350505050565b6040808252835190820181905260009060208501906060840190835b81811015614d2b578351835260209384019390920191600101614d0d565b5050602093909301939093525092915050565b600080600080600060608688031215614d5657600080fd5b614d5f86614b8c565b945060208601356001600160401b03811115614d7a57600080fd5b614d8688828901614c6c565b90955093505060408601356001600160401b03811115614da557600080fd5b614db188828901614c6c565b969995985093965092949392505050565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60208082526015908201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115611a6a57611a6a614ed6565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614f2757600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215614f5657600080fd5b815180151581146132f357600080fd5b80820180821115611a6a57611a6a614ed6565b6001600160a01b03929092168252602082015260400190565b600082614faf57634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417611a6a57611a6a614ed6565b6001815b600184111561500657808504811115614fea57614fea614ed6565b6001841615614ff857908102905b60019390931c928002614fcf565b935093915050565b60008261501d57506001611a6a565b8161502a57506000611a6a565b8160018114615040576002811461504a57615066565b6001915050611a6a565b60ff84111561505b5761505b614ed6565b50506001821b611a6a565b5060208310610133831016604e8410600b8410161715615089575081810a611a6a565b6150966000198484614fcb565b80600019048211156150aa576150aa614ed6565b029392505050565b60006132f3838361500e565b6001600160801b038281168282160390811115611a6a57611a6a614ed6565b6001600160801b038181168382160190811115611a6a57611a6a614ed6565b60005b838110156151175781810151838201526020016150ff565b50506000910152565b600082516151328184602087016150fc565b9190910192915050565b602081526000825180602084015261515b8160408501602087016150fc565b601f01601f1916919091016040019291505056fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220cdd4681ab24eb83949cc552c3025347ea514edc98002eccc2e188ec66b9f87e864736f6c634300081c0033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106104075760003560e01c80636217f3ea11610220578063ae69f3cb11610130578063c5f00841116100b8578063d4c3eea011610087578063d4c3eea0146109e6578063e6cc5432146109ee578063ea33b8e414610a02578063f844443614610a0a578063fac5bb9b14610a1d57600080fd5b8063c5f00841146109bb578063c7af3352146109c3578063c9919112146109cb578063d38bfff4146109d357600080fd5b8063b890ebf6116100ff578063b890ebf61461096b578063b9b17f9f1461097e578063bb7a632e14610986578063c3b28864146109a0578063c4d66de8146109a857600080fd5b8063ae69f3cb1461092a578063af14052c1461093d578063b2c9336d14610945578063b4925a201461095857600080fd5b806394828ffd116101b35780639fa1826e116101825780639fa1826e146108ec578063a0712d68146108f5578063a0aead4d14610908578063ab80dafb1461090f578063abaa99161461092257600080fd5b806394828ffd1461086957806395b166bc146108715780639be918e6146108845780639ee679e8146108c457600080fd5b8063840c4c7a116101ef578063840c4c7a146107925780638e510b52146107a55780638ec489a2146107ae578063937b2581146107c157600080fd5b80636217f3ea14610746578063663e64ce14610759578063773540b31461076c57806378f353a11461077f57600080fd5b806339ebf8231161031b578063527e83a8116102ae57806357bee9441161027d57806357bee944146106f45780635802a17214610707578063597c8910146107185780635d36b1901461072b5780635f5152261461073357600080fd5b8063527e83a8146106aa57806352d38e5d146106c457806353ca9f24146106cd578063570d8e1d146106e157600080fd5b806345e4213b116102ea57806345e4213b1461063b57806348e30f541461064457806349c1d54d146106655780634d5f46291461067857600080fd5b806339ebf823146105a95780633b8ae397146105ed5780633dbc911f146106005780634530820a1461060857600080fd5b80631a32aad61161039e5780632acada4d1161036d5780632acada4d146104f35780632da845a81461050857806331e19cfa1461051b578063362bd1a31461052357806338d52e0f1461058257600080fd5b80631a32aad6146104ad5780631cfbe7bc146104c05780631edfe3da146104d3578063207134b0146104ea57600080fd5b80631072cbea116103da5780631072cbea14610461578063156e29f614610474578063175188e8146104875780631816dd4a1461049a57600080fd5b80630493a0fa1461040c57806309f49bf5146104215780630acbda75146104295780630c340a241461043c575b600080fd5b61041f61041a366004614b73565b610a30565b005b61041f610ae6565b61041f610437366004614b73565b610b56565b610444610c01565b6040516001600160a01b0390911681526020015b60405180910390f35b61041f61046f366004614ba8565b610c1e565b61041f610482366004614bd2565b610cdc565b61041f610495366004614c05565b610d4f565b61041f6104a8366004614c05565b6110e2565b603c54610444906001600160a01b031681565b61041f6104ce366004614b73565b6111e9565b6104dc60395481565b604051908152602001610458565b6104dc60435481565b6104fb6112ab565b6040516104589190614c20565b61041f610516366004614c05565b611322565b6036546104dc565b604b54604c5461054f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610458565b6104447f000000000000000000000000000000000000000000000000000000000000000081565b6105d66105b7366004614c05565b6035602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610458565b61041f6105fb366004614c05565b611394565b61041f6115a7565b61062b610616366004614c05565b60496020526000908152604090205460ff1681565b6040519015158152602001610458565b6104dc604e5481565b610657610652366004614cb0565b61161d565b604051610458929190614cf1565b604254610444906001600160a01b031681565b604f5461069290600160c01b90046001600160401b031681565b6040516001600160401b039091168152602001610458565b604f5461069290600160801b90046001600160401b031681565b6104dc603b5481565b60375461062b90600160a01b900460ff1681565b603f54610444906001600160a01b031681565b61041f610702366004614c05565b6117c2565b603c546001600160a01b0316610444565b61041f610726366004614c05565b611975565b61041f6119b9565b6104dc610741366004614c05565b611a5f565b61041f610754366004614b73565b611a70565b61041f610767366004614b73565b611bf4565b61041f61077a366004614c05565b611c4d565b604f54610692906001600160401b031681565b61041f6107a0366004614d3e565b611cbf565b6104dc60415481565b61041f6107bc366004614b73565b611d46565b6108226107cf366004614b73565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a001610458565b61041f611dfb565b61041f61087f366004614c05565b611e6b565b61062b610892366004614c05565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b6108d76108d2366004614b73565b611f32565b60408051928352602083019190915201610458565b6104dc603a5481565b61041f610903366004614b73565b612273565b60016104dc565b61041f61091d366004614b73565b6122e4565b61041f612433565b61041f610938366004614d3e565b6124ab565b61041f612527565b61041f610953366004614b73565b61256d565b61041f610966366004614b73565b6125c6565b61041f610979366004614b73565b6126e4565b61041f61273d565b604f5461069290600160401b90046001600160401b031681565b6104fb612745565b61041f6109b6366004614c05565b6127a7565b61041f61295f565b61062b6129d5565b61041f612a06565b61041f6109e1366004614c05565b612a46565b6104dc612aea565b60375461062b90600160a81b900460ff1681565b6104dc612af4565b6104dc610a18366004614b73565b612b83565b605054610444906001600160a01b031681565b603f546001600160a01b0316331480610a4c5750610a4c6129d5565b610a715760405162461bcd60e51b8152600401610a6890614dc2565b60405180910390fd5b610a79612c9e565b50610a8381613038565b604f80546001600160401b0392909216600160401b0267ffffffffffffffff60401b199092169190911790556040518181527f406e15fbca1d8ded2dbb06765fea3a54f18395c54125a4c9916dd00ea14ee15e906020015b60405180910390a150565b603f546001600160a01b0316331480610b025750610b026129d5565b610b1e5760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b610b5e6129d5565b610b7a5760405162461bcd60e51b8152600401610a6890614e0a565b611388811115610bcc5760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f7420657863656564203530250000000000000000006044820152606401610a68565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c790602001610adb565b6000610c196000805160206151908339815191525490565b905090565b610c266129d5565b610c425760405162461bcd60e51b8152600401610a6890614e0a565b816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610cbc5760405162461bcd60e51b815260206004820152601660248201527513db9b1e481d5b9cdd5c1c1bdc9d195908185cdcd95d60521b6044820152606401610a68565b610cd8610cc7610c01565b6001600160a01b03841690836130a4565b5050565b603754600160a81b900460ff1615610d065760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101610d385760405162461bcd60e51b8152600401610a6890614e69565b60028255610d45846130fa565b5060019055505050565b610d576129d5565b610d735760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff16610dab5760405162461bcd60e51b8152600401610a6890614e91565b6050546001600160a01b03808316911603610e085760405162461bcd60e51b815260206004820152601d60248201527f53747261746567792069732064656661756c7420666f722061737365740000006044820152606401610a68565b6036548060005b82811015610e5e57836001600160a01b031660368281548110610e3457610e34614ec0565b6000918252602090912001546001600160a01b031603610e5657809150610e5e565b600101610e0f565b50818110156110dd576036610e74600184614eec565b81548110610e8457610e84614ec0565b600091825260209091200154603680546001600160a01b039092169183908110610eb057610eb0614ec0565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610eef57610eef614eff565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038516808352603582526040808420805460ff1990811690915560499093528084208054909316909255815163429c145b60e11b815291518693919263853828b692600480830193919282900301818387803b158015610f7b57600080fd5b505af1158015610f8f573d6000803e3d6000fd5b5060009250610fcd91506509184e72a000905060ff7f0000000000000000000000000000000000000000000000000000000000000000166012613296565b604051632fa8a91360e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192508291841690635f51522690602401602060405180830381865afa158015611038573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105c9190614f15565b1061109e5760405162461bcd60e51b81526020600482015260126024820152715374726174656779206861732066756e647360701b6044820152606401610a68565b6040516001600160a01b03861681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49060200160405180910390a150505b505050565b6110ea6129d5565b6111065760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff1661113e5760405162461bcd60e51b8152600401610a6890614e91565b6001600160a01b03811660009081526049602052604090205460ff161561119d5760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481dda1a5d195b1a5cdd1959606a1b6044820152606401610a68565b6001600160a01b038116600081815260496020526040808220805460ff19166001179055517f47c8c96a5942f094264111c5fe7f6a4fe86efe63254a6fa7afa5fc84f07d58e89190a250565b6111f16129d5565b61120d5760405162461bcd60e51b8152600401610a6890614e0a565b80158061122a5750610258811015801561122a57506213c6808111155b6112765760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636c61696d2064656c617920706572696f640000000000006044820152606401610a68565b604e8190556040518181527fc59f5e32049abab44ddea11021f5abb89422a2f550837afcf25df9fc8d0db6b090602001610adb565b60408051600180825281830190925260609160009190602080830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061130557611305614ec0565b6001600160a01b0390921660209283029190910190910152919050565b61132a6129d5565b6113465760405162461bcd60e51b8152600401610a6890614e0a565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610adb565b61139c6129d5565b6113b85760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526035602052604090205460ff16156114215760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f766564000000000000006044820152606401610a68565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa158015611487573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ab9190614f44565b6114f75760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a68565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610adb565b603f546001600160a01b03163314806115c357506115c36129d5565b6115df5760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b603754606090600090600160a81b900460ff161561164d5760405162461bcd60e51b8152600401610a6890614e41565b6000805160206151708339815191528054600119810161167f5760405162461bcd60e51b8152600401610a6890614e69565b6002825561168b6132fa565b50846001600160401b038111156116a4576116a4614f2e565b6040519080825280602002602001820160405280156116cd578160200160208202803683370190505b50935060005b85811015611749576116fc8787838181106116f0576116f0614ec0565b905060200201356134d6565b85828151811061170e5761170e614ec0565b60200260200101818152505084818151811061172c5761172c614ec0565b60200260200101518461173f9190614f66565b93506001016116d3565b5061177e6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130a4565b6117b56117b084601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b613837565b6001825550509250929050565b603f546001600160a01b03163314806117de57506117de6129d5565b6117fa5760405162461bcd60e51b8152600401610a6890614dc2565b6040516001600160a01b03821681527f45a9e715f8779ebeab88d3e8d081fb8b484b7730857e7c4478a95a5b1d8f79489060200160405180910390a16001600160a01b03811615611953576001600160a01b03811660009081526035602052604090205460ff1661187d5760405162461bcd60e51b8152600401610a6890614e91565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa1580156118e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119079190614f44565b6119535760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a68565b605080546001600160a01b0319166001600160a01b0392909216919091179055565b603f546001600160a01b031633148061199157506119916129d5565b6119ad5760405162461bcd60e51b8152600401610a6890614dc2565b6119b6816139da565b50565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614611a545760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610a68565b611a5d33613aa2565b565b6000611a6a82613b01565b92915050565b603754600160a81b900460ff1615611a9a5760405162461bcd60e51b8152600401610a6890614e41565b3360009081526035602052604090205460ff161515600114611af55760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a68565b3360009081526049602052604090205460ff161515600114611b545760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a68565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051611b85929190614f79565b60405180910390a1603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90611bbf9033908590600401614f79565b600060405180830381600087803b158015611bd957600080fd5b505af1158015611bed573d6000803e3d6000fd5b5050505050565b611bfc6129d5565b611c185760405162461bcd60e51b8152600401610a6890614e0a565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610adb565b611c556129d5565b611c715760405162461bcd60e51b8152600401610a6890614e0a565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610adb565b603f546001600160a01b0316331480611cdb5750611cdb6129d5565b611cf75760405162461bcd60e51b8152600401610a6890614dc2565b60008051602061517083398151915280546001198101611d295760405162461bcd60e51b8152600401610a6890614e69565b60028255611d3a8787878787613d63565b50600190555050505050565b603f546001600160a01b0316331480611d625750611d626129d5565b611d7e5760405162461bcd60e51b8152600401610a6890614dc2565b670de0b6b3a7640000811115611dc65760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b6044820152606401610a68565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610adb565b603f546001600160a01b0316331480611e175750611e176129d5565b611e335760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e736129d5565b611e8f5760405162461bcd60e51b8152600401610a6890614e0a565b6001600160a01b03811660009081526049602052604090205460ff16611ee95760405162461bcd60e51b815260206004820152600f60248201526e139bdd081dda1a5d195b1a5cdd1959608a1b6044820152606401610a68565b6001600160a01b038116600081815260496020526040808220805460ff19169055517f0ec40967a61509853550658e51d0e4297f7cba244fe4adc8ba18b5631ac20e2f9190a250565b6037546000908190600160a81b900460ff1615611f615760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101611f935760405162461bcd60e51b8152600401610a6890614e69565b6002825560008511611fe75760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a68565b6000604e54116120395760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a68565b604c54600160801b90046001600160801b0316935061207d857f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b604b5461209391906001600160801b0316614f66565b92506120a86120a3856001614f66565b613fa2565b604c80546001600160801b03928316600160801b0292169190911790556120ce83613fa2565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff16918101919091526060810161211e87613fa2565b6001600160801b0316815260200161213585613fa2565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906121f09033908990600401614f79565b600060405180830381600087803b15801561220a57600080fd5b505af115801561221e573d6000803e3d6000fd5b5050505061222b85613837565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff161561229d5760405162461bcd60e51b8152600401610a6890614e41565b600080516020615170833981519152805460011981016122cf5760405162461bcd60e51b8152600401610a6890614e69565b600282556122dc836130fa565b506001905550565b603754600160a81b900460ff161561230e5760405162461bcd60e51b8152600401610a6890614e41565b3360009081526035602052604090205460ff1615156001146123695760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a68565b3360009081526049602052604090205460ff1615156001146123c85760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a68565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516123f9929190614f79565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611bbf9033908590600401614f79565b603754600160a81b900460ff161561245d5760405162461bcd60e51b8152600401610a6890614e41565b6000805160206151708339815191528054600119810161248f5760405162461bcd60e51b8152600401610a6890614e69565b6002825561249b6132fa565b506124a461400b565b5060019055565b603f546001600160a01b03163314806124c757506124c76129d5565b6124e35760405162461bcd60e51b8152600401610a6890614dc2565b600080516020615170833981519152805460011981016125155760405162461bcd60e51b8152600401610a6890614e69565b60028255611d3a308888888888614234565b600080516020615170833981519152805460011981016125595760405162461bcd60e51b8152600401610a6890614e69565b60028255612565612c9e565b505060019055565b6125756129d5565b6125915760405162461bcd60e51b8152600401610a6890614e0a565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610adb565b603f546001600160a01b03163314806125e257506125e26129d5565b6125fe5760405162461bcd60e51b8152600401610a6890614dc2565b612606612c9e565b5060006301e13380612619606484614f92565b6126239190614f92565b90506126396201518066b1a2bc2ec50000614f92565b8111156126785760405162461bcd60e51b815260206004820152600d60248201526c0a4c2e8ca40e8dede40d0d2ced609b1b6044820152606401610a68565b61268181613038565b604f80546001600160401b0392909216600160801b0267ffffffffffffffff60801b199092169190911790556040518181527fef46f143af5fead0010484fe7d6ec2e2972420faa76157f5a6075aa72e614cb59060200160405180910390a15050565b6126ec6129d5565b6127085760405162461bcd60e51b8152600401610a6890614e0a565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d90602001610adb565b6119b66132fa565b6060603680548060200260200160405190810160405280929190818152602001828054801561279d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161277f575b5050505050905090565b6127af6129d5565b6127cb5760405162461bcd60e51b8152600401610a6890614e0a565b600054610100900460ff16806127e4575060005460ff16155b6128475760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a68565b600054610100900460ff16158015612869576000805461ffff19166101011790555b6001600160a01b0382166128b85760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b6044820152606401610a68565b603c80546001600160a01b0384166001600160a01b03199091161790556037805461ffff60a01b1916600160a81b1790556000603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b55604080519182526020820190819052905161292891603691614b02565b50604f805467ffffffffffffffff60401b19166a093a8000000000000000001790558015610cd8576000805461ff00191690555050565b603f546001600160a01b031633148061297b575061297b6129d5565b6129975760405162461bcd60e51b8152600401610a6890614dc2565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b60006129ed6000805160206151908339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612a225750612a226129d5565b612a3e5760405162461bcd60e51b8152600401610a6890614dc2565b611a5d6143c5565b612a4e6129d5565b612a6a5760405162461bcd60e51b8152600401610a6890614e0a565b612a92817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612ab26000805160206151908339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000610c1961445a565b6000612b7d603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b709190614f15565b612b7861445a565b6144ae565b50919050565b603754600090600160a81b900460ff1615612bb05760405162461bcd60e51b8152600401610a6890614e41565b60008051602061517083398151915280546001198101612be25760405162461bcd60e51b8152600401610a6890614e69565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115612c2357612c216132fa565b505b612c2c846134d6565b9250612c626001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130a4565b612c946117b084601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b5060019055919050565b603754600090600160a01b900460ff1615612ced5760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b6044820152606401610a68565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612d37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d5b9190614f15565b90506000612d6761445a565b905081600003612d7a5791506130359050565b600080612d8784846144ae565b90925090506000612d988386614f66565b90508481111580612da857508381115b15612db7575091949350505050565b612dc8826001600160401b03614681565b604f805477ffffffffffffffffffffffffffffffff000000000000000016600160c01b6001600160401b039384160267ffffffffffffffff19161742929092169190911790556042546001600160a01b031660008115612f045761271060435486612e339190614fb4565b612e3d9190614f92565b90508015612f0457848110612e9f5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b6064820152608401610a68565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612ed19085908590600401614f79565b600060405180830381600087803b158015612eeb57600080fd5b505af1158015612eff573d6000803e3d6000fd5b505050505b604080516001600160a01b0384168152602081018790529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a1603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc59190614f15565b83111561302b57603c546040516339a7919f60e01b8152600481018590526001600160a01b03909116906339a7919f90602401600060405180830381600087803b15801561301257600080fd5b505af1158015613026573d6000803e3d6000fd5b505050505b5093955050505050505b90565b60006001600160401b038211156130a05760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610a68565b5090565b6110dd8363a9059cbb60e01b84846040516024016130c3929190614f79565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614697565b6000811161314a5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a68565b600061317b82601260ff7f000000000000000000000000000000000000000000000000000000000000000016613296565b90507f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516131ae929190614f79565b60405180910390a1603754600160a01b900460ff161580156131d25750603b548110155b156131e1576131df612c9e565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132139033908590600401614f79565b600060405180830381600087803b15801561322d57600080fd5b505af1158015613241573d6000803e3d6000fd5b5061327c9250506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169050333085614769565b6132846132fa565b50603a548110610cd857610cd861400b565b6000818311156132c6576132bf6132ad8385614eec565b6132b890600a6150b2565b85906147a7565b93506132f0565b818310156132f0576132ed6132db8484614eec565b6132e690600a6150b2565b85906147b3565b93505b50825b9392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c548084169686019690965292909404166060830152600092839161334c916150be565b6001600160801b03169050806000036133685760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156133cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133f39190614f15565b905060008360400151846020015161340b91906150be565b6001600160801b0316905080821161342857600094505050505090565b60006134348284614eec565b90508084106134435780613445565b835b955060008686602001516001600160801b03166134629190614f66565b905061346d81613fa2565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f463333906134c59083908a90918252602082015260400190565b60405180910390a150505050505090565b600080604e54116135295760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a68565b6000828152604d6020908152604091829020825160a08101845281546001600160a01b038116825260ff600160a01b82041615158285015264ffffffffff600160a81b90910481168286019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915288519081018952604b548084168252849004831697810197909752604c54808316988801989098529190960490951694840194909452604e549151909342926135f092909116614f66565b11156136345760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b6044820152606401610a68565b80602001516001600160801b031682608001516001600160801b0316111561369e5760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c69717569646974790000000000000000006044820152606401610a68565b81516001600160a01b031633146136e75760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b6044820152606401610a68565b60208201511561372b5760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b6044820152606401610a68565b6000848152604d60205260409020805460ff60a01b1916600160a01b179055606082015161378b906120a3906001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b816040015161379a91906150dd565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a361382f82606001516001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff166012613296565b949350505050565b6000603b5482101580156138555750603754600160a01b900460ff16155b1561386957613862612c9e565b9050613874565b61387161445a565b90505b60415415610cd857600081116138cc5760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e672072657175657374730000006044820152606401610a68565b600061394f82603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613925573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139499190614f15565b906147bf565b9050604154670de0b6b3a7640000821161397a5761397582670de0b6b3a7640000614eec565b61398c565b61398c670de0b6b3a764000083614eec565b11156110dd5760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f7200006044820152606401610a68565b6001600160a01b03811660009081526035602052604090205460ff16613a425760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f72746564000000000000006044820152606401610a68565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a8257600080fd5b505af1158015613a96573d6000803e3d6000fd5b505050506110dd6132fa565b6001600160a01b038116613af85760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610a68565b6119b6816147e0565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614613b4457506000919050565b6040516370a0823160e01b815230600482015282906001600160a01b038216906370a0823190602401602060405180830381865afa158015613b8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bae9190614f15565b60365490925060005b81811015613cd357600060368281548110613bd457613bd4614ec0565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af690602401602060405180830381865afa158015613c2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4e9190614f44565b15613cca57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f51522690602401602060405180830381865afa158015613c99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cbd9190614f15565b613cc79086614f66565b94505b50600101613bb7565b5060408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529091613d219086614f66565b1015613d3257506000949350505050565b805160408201516001600160801b0391821691613d50911686614f66565b613d5a9190614eec565b95945050505050565b6001600160a01b03851660009081526035602052604090205460ff16613dc15760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b6044820152606401610a68565b600183148015613dd15750600181145b8015613e3557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684846000818110613e1557613e15614ec0565b9050602002016020810190613e2a9190614c05565b6001600160a01b0316145b613e815760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920617373657420697320737570706f727465640000000000000000006044820152606401610a68565b613e89614847565b82826000818110613e9c57613e9c614ec0565b905060200201351115613ef15760405162461bcd60e51b815260206004820152601b60248201527f4e6f7420656e6f7567682061737365747320617661696c61626c6500000000006044820152606401610a68565b613f488583836000818110613f0857613f08614ec0565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166130a49092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613f8357600080fd5b505af1158015613f97573d6000803e3d6000fd5b505050505050505050565b60006001600160801b038211156130a05760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610a68565b6050546001600160a01b03168061401f5750565b6000614029614847565b905080600003614037575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015614081573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140a59190614f15565b905060006140ee7f000000000000000000000000000000000000000000000000000000000000000060ff1660126140e76039548661495590919063ffffffff16565b9190613296565b90508083116140fd5750505050565b60006141098285614eec565b9050846141406001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682846130a4565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061418e907f0000000000000000000000000000000000000000000000000000000000000000908690600401614f79565b600060405180830381600087803b1580156141a857600080fd5b505af11580156141bc573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b6001600160a01b03851660009081526035602052604090205460ff166142945760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b6044820152606401610a68565b8281146142e35760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d61746368000000000000006044820152606401610a68565b8260005b818110156143b257866001600160a01b031663d9caed128988888581811061431157614311614ec0565b90506020020160208101906143269190614c05565b87878681811061433857614338614ec0565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561438f57600080fd5b505af11580156143a3573d6000803e3d6000fd5b505050508060010190506142e7565b506143bb6132fa565b5050505050505050565b60365460005b8181101561445157603681815481106143e6576143e6614ec0565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b15801561442e57600080fd5b505af1158015614442573d6000803e3d6000fd5b505050508060010190506143cb565b50610cd86132fa565b6000610c1960127f000000000000000000000000000000000000000000000000000000000000000060ff166140e77f0000000000000000000000000000000000000000000000000000000000000000613b01565b6000806000603c60009054906101000a90046001600160a01b03166001600160a01b031663e696393a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614506573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061452a9190614f15565b905060006145388287614eec565b604f54909150600090614554906001600160401b031642614eec565b604f54600160c01b90046001600160401b031694509050801580614576575081155b8061458057508587115b8061459257506001600160401b034210155b156145a3576000945050505061467a565b6145ad8787614eec565b604f54909550600160401b90046001600160401b03166001811115614612576145ea856145db836002614fb4565b6145e59089614f92565b61496a565b94506145ff856145fa8389614f92565b614681565b945061460f866145fa8488614fb4565b95505b604f54614653908790670de0b6b3a764000090600160801b90046001600160401b031661463f8688614fb4565b6146499190614fb4565b6145fa9190614f92565b955061467386670de0b6b3a764000061464966470de4df82000087614fb4565b9550505050505b9250929050565b600081831061469057816132f3565b5090919050565b60006146ec826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166149799092919063ffffffff16565b8051909150156110dd578080602001905181019061470a9190614f44565b6110dd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a68565b6040516001600160a01b03808516602483015283166044820152606481018290526147a19085906323b872dd60e01b906084016130c3565b50505050565b60006132f38284614fb4565b60006132f38284614f92565b6000806147d484670de0b6b3a76400006147a7565b905061382f81846147b3565b806001600160a01b03166148006000805160206151908339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a360008051602061519083398151915255565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c5480831695850186905292909204166060830152600092839161489791906150be565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561490c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149309190614f15565b9050818111614943576000935050505090565b61494d8282614eec565b935050505090565b60006132f38383670de0b6b3a7640000614988565b600081831161469057816132f3565b606061382f84846000856149a1565b60008061499585856147a7565b9050613d5a81846147b3565b606082471015614a025760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a68565b843b614a505760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a68565b600080866001600160a01b03168587604051614a6c9190615120565b60006040518083038185875af1925050503d8060008114614aa9576040519150601f19603f3d011682016040523d82523d6000602084013e614aae565b606091505b5091509150614abe828286614ac9565b979650505050505050565b60608315614ad85750816132f3565b825115614ae85782518084602001fd5b8160405162461bcd60e51b8152600401610a68919061513c565b828054828255906000526020600020908101928215614b57579160200282015b82811115614b5757825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614b22565b506130a09291505b808211156130a05760008155600101614b5f565b600060208284031215614b8557600080fd5b5035919050565b80356001600160a01b0381168114614ba357600080fd5b919050565b60008060408385031215614bbb57600080fd5b614bc483614b8c565b946020939093013593505050565b600080600060608486031215614be757600080fd5b614bf084614b8c565b95602085013595506040909401359392505050565b600060208284031215614c1757600080fd5b6132f382614b8c565b602080825282518282018190526000918401906040840190835b81811015614c615783516001600160a01b0316835260209384019390920191600101614c3a565b509095945050505050565b60008083601f840112614c7e57600080fd5b5081356001600160401b03811115614c9557600080fd5b6020830191508360208260051b850101111561467a57600080fd5b60008060208385031215614cc357600080fd5b82356001600160401b03811115614cd957600080fd5b614ce585828601614c6c565b90969095509350505050565b6040808252835190820181905260009060208501906060840190835b81811015614d2b578351835260209384019390920191600101614d0d565b5050602093909301939093525092915050565b600080600080600060608688031215614d5657600080fd5b614d5f86614b8c565b945060208601356001600160401b03811115614d7a57600080fd5b614d8688828901614c6c565b90955093505060408601356001600160401b03811115614da557600080fd5b614db188828901614c6c565b969995985093965092949392505050565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60208082526015908201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115611a6a57611a6a614ed6565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614f2757600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215614f5657600080fd5b815180151581146132f357600080fd5b80820180821115611a6a57611a6a614ed6565b6001600160a01b03929092168252602082015260400190565b600082614faf57634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417611a6a57611a6a614ed6565b6001815b600184111561500657808504811115614fea57614fea614ed6565b6001841615614ff857908102905b60019390931c928002614fcf565b935093915050565b60008261501d57506001611a6a565b8161502a57506000611a6a565b8160018114615040576002811461504a57615066565b6001915050611a6a565b60ff84111561505b5761505b614ed6565b50506001821b611a6a565b5060208310610133831016604e8410600b8410161715615089575081810a611a6a565b6150966000198484614fcb565b80600019048211156150aa576150aa614ed6565b029392505050565b60006132f3838361500e565b6001600160801b038281168282160390811115611a6a57611a6a614ed6565b6001600160801b038181168382160190811115611a6a57611a6a614ed6565b60005b838110156151175781810151838201526020016150ff565b50506000910152565b600082516151328184602087016150fc565b9190910192915050565b602081526000825180602084015261515b8160408501602087016150fc565b601f01601f1916919091016040019291505056fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220cdd4681ab24eb83949cc552c3025347ea514edc98002eccc2e188ec66b9f87e864736f6c634300081c0033", + "numDeployments": 2, + "solcInputHash": "f4384e86fd2a870879603d18d53c5b16", + "metadata": "{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_usdc\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"AllocateThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"AssetAllocated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"DefaultStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dripDuration\",\"type\":\"uint256\"}],\"name\":\"DripDurationChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"MaxSupplyDiffChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newOperator\",\"type\":\"address\"}],\"name\":\"OperatorUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebasePaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rebaseRatePerSecond\",\"type\":\"uint256\"}],\"name\":\"RebasePerSecondMaxChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebaseUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"StrategistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyAddedToMintWhitelist\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyRemovedFromMintWhitelist\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"TrusteeAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"TrusteeFeeBpsChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"VaultBufferUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newDelay\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_claimable\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newClaimable\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimable\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_queued\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_yield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"YieldDistribution\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddr\",\"type\":\"address\"}],\"name\":\"addStrategyToMintWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"addWithdrawalQueueLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"allocate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"approveStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"asset\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"autoAllocateThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"burnForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capitalPaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"claimWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_requestIds\",\"type\":\"uint256[]\"}],\"name\":\"claimWithdrawals\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"totalAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultStrategy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyToAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"depositToStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dripDuration\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAssets\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllStrategies\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAssetCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStrategyCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_oToken\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isMintWhitelistedStrategy\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"isSupportedAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRebase\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxSupplyDiff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mintForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oToken\",\"outputs\":[{\"internalType\":\"contract OUSD\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oUSD\",\"outputs\":[{\"internalType\":\"contract OUSD\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatorAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previewYield\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"yield\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePerSecondMax\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePerSecondTarget\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"removeStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddr\",\"type\":\"address\"}],\"name\":\"removeStrategyFromMintWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"requestWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"queued\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setAutoAllocateThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"setDefaultStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dripDuration\",\"type\":\"uint256\"}],\"name\":\"setDripDuration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"setMaxSupplyDiff\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_operator\",\"type\":\"address\"}],\"name\":\"setOperatorAddr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"apr\",\"type\":\"uint256\"}],\"name\":\"setRebaseRateMax\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setStrategistAddr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setTrusteeAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"setTrusteeFeeBps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"setVaultBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_delay\",\"type\":\"uint256\"}],\"name\":\"setWithdrawalClaimDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"strategies\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isSupported\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"_deprecated\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategistAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"transferToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAllFromStrategies\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"}],\"name\":\"withdrawAllFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyFromAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"withdrawFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalClaimDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalQueueMetadata\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimable\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimed\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"nextWithdrawalIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"withdrawalRequests\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"claimed\",\"type\":\"bool\"},{\"internalType\":\"uint40\",\"name\":\"timestamp\",\"type\":\"uint40\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"addStrategyToMintWhitelist(address)\":{\"params\":{\"strategyAddr\":\"Strategy address\"}},\"addWithdrawalQueueLiquidity()\":{\"details\":\"is called from the Native Staking strategy when validator withdrawals are processed. It also called before any WETH is allocated to a strategy.\"},\"approveStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to add\"}},\"burnForStrategy(uint256)\":{\"details\":\"Notice: can't use `nonReentrant` modifier since the `redeem` function could require withdrawal on an AMO strategy and that one can call `burnForStrategy` while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\",\"params\":{\"_amount\":\"Amount of OToken to burn\"}},\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of asset\"},\"returns\":{\"_0\":\"uint256 Balance of asset in decimals of asset\"}},\"claimWithdrawal(uint256)\":{\"params\":{\"_requestId\":\"Unique ID for the withdrawal request\"},\"returns\":{\"amount\":\"Amount of asset transferred to the withdrawer\"}},\"claimWithdrawals(uint256[])\":{\"params\":{\"_requestIds\":\"Unique ID of each withdrawal request\"},\"returns\":{\"amounts\":\"Amount of asset received for each request\",\"totalAmount\":\"Total amount of asset transferred to the withdrawer\"}},\"depositToStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to deposit.\",\"_assets\":\"Array of asset address that will be deposited into the strategy.\",\"_strategyToAddress\":\"Address of the Strategy to deposit asset into.\"}},\"isSupportedAsset(address)\":{\"params\":{\"_asset\":\"address of the asset\"},\"returns\":{\"_0\":\"true if supported\"}},\"mint(address,uint256,uint256)\":{\"details\":\"Deprecated: use `mint(uint256 _amount)` instead.Deprecated: param _asset Address of the asset being depositedDeprecated: param _minimumOusdAmount Minimum OTokens to mint\",\"params\":{\"_amount\":\"Amount of the asset being deposited\"}},\"mint(uint256)\":{\"params\":{\"_amount\":\"Amount of the asset being deposited\"}},\"mintForStrategy(uint256)\":{\"params\":{\"_amount\":\"Amount of OToken to mint Notice: can't use `nonReentrant` modifier since the `mint` function can call `allocate`, and that can trigger an AMO strategy to call this function while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\"}},\"previewYield()\":{\"returns\":{\"yield\":\"amount of expected yield\"}},\"rebase()\":{\"details\":\"Restricted to the Operator, Strategist or Governor.\"},\"removeStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to remove\"}},\"removeStrategyFromMintWhitelist(address)\":{\"params\":{\"strategyAddr\":\"Strategy address\"}},\"requestWithdrawal(uint256)\":{\"params\":{\"_amount\":\"Amount of OToken to burn.\"},\"returns\":{\"queued\":\"Cumulative total of all asset queued including already claimed requests.\",\"requestId\":\"Unique ID for the withdrawal request\"}},\"setAutoAllocateThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setDefaultStrategy(address)\":{\"params\":{\"_strategy\":\"Address of the Strategy\"}},\"setDripDuration(uint256)\":{\"params\":{\"_dripDuration\":\"Time in seconds to target a constant yield rate\"}},\"setOperatorAddr(address)\":{\"params\":{\"_operator\":\"New operator address. May be set to the zero address to disable operator-initiated rebases.\"}},\"setRebaseRateMax(uint256)\":{\"params\":{\"apr\":\"in 1e18 notation. 3 * 1e18 = 3% APR\"}},\"setStrategistAddr(address)\":{\"params\":{\"_address\":\"Address of Strategist\"}},\"setVaultBuffer(uint256)\":{\"params\":{\"_vaultBuffer\":\"Percentage using 18 decimals. 100% = 1e18.\"}},\"setWithdrawalClaimDelay(uint256)\":{\"params\":{\"_delay\":\"Delay period (should be between 10 mins to 7 days). Set to 0 to disable async withdrawals\"}},\"totalValue()\":{\"returns\":{\"value\":\"Total value in USD/ETH (1e18)\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"transferToken(address,uint256)\":{\"params\":{\"_amount\":\"Amount of the asset to transfer\",\"_asset\":\"Address for the asset\"}},\"withdrawAllFromStrategy(address)\":{\"params\":{\"_strategyAddr\":\"Strategy address.\"}},\"withdrawFromStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to withdraw.\",\"_assets\":\"Array of asset address that will be withdrawn from the strategy.\",\"_strategyFromAddress\":\"Address of the Strategy to withdraw asset from.\"}}},\"title\":\"OUSD VaultAdmin Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"addStrategyToMintWhitelist(address)\":{\"notice\":\"Adds a strategy to the mint whitelist. Reverts if strategy isn't approved on Vault.\"},\"addWithdrawalQueueLiquidity()\":{\"notice\":\"Adds WETH to the withdrawal queue if there is a funding shortfall.\"},\"allocate()\":{\"notice\":\"Allocate unallocated funds on Vault to strategies.\"},\"approveStrategy(address)\":{\"notice\":\"Add a strategy to the Vault.\"},\"autoAllocateThreshold()\":{\"notice\":\"OToken mints over this amount automatically allocate funds. 18 decimals.\"},\"burnForStrategy(uint256)\":{\"notice\":\"Burn OTokens for an allowed Strategy\"},\"capitalPaused()\":{\"notice\":\"pause operations that change the OToken supply. eg mint, redeem, allocate, mint/burn for strategy\"},\"checkBalance(address)\":{\"notice\":\"Get the balance of an asset held in Vault and all strategies.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"claimWithdrawal(uint256)\":{\"notice\":\"Claim a previously requested withdrawal once it is claimable. This request can be claimed once the withdrawal queue's `claimable` amount is greater than or equal this request's `queued` amount and 10 minutes has passed. If the requests is not claimable, the transaction will revert with `Queue pending liquidity`. If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`. OToken is converted to asset at 1:1.\"},\"claimWithdrawals(uint256[])\":{\"notice\":\"Claim a previously requested withdrawals once they are claimable. This requests can be claimed once the withdrawal queue's `claimable` amount is greater than or equal each request's `queued` amount and 10 minutes has passed. If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`. If one of the requests is not older than 10 minutes, the whole transaction will revert with `Claim delay not met`.\"},\"defaultStrategy()\":{\"notice\":\"Default strategy for asset\"},\"depositToStrategy(address,address[],uint256[])\":{\"notice\":\"Deposit multiple asset from the vault into the strategy.\"},\"dripDuration()\":{\"notice\":\"Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\"},\"getAllAssets()\":{\"notice\":\"Return all vault asset addresses in order\"},\"getAllStrategies()\":{\"notice\":\"Return the array of all strategies\"},\"getAssetCount()\":{\"notice\":\"Return the number of asset supported by the Vault.\"},\"getStrategyCount()\":{\"notice\":\"Return the number of strategies active on the Vault.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"isSupportedAsset(address)\":{\"notice\":\"Returns whether the vault supports the asset\"},\"lastRebase()\":{\"notice\":\"Time in seconds that the vault last rebased yield.\"},\"maxSupplyDiff()\":{\"notice\":\"Max difference between total supply and total value of assets. 18 decimals.\"},\"mint(address,uint256,uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mint(uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mintForStrategy(uint256)\":{\"notice\":\"Mint OTokens for an allowed Strategy\"},\"oUSD()\":{\"notice\":\"Deprecated: use `oToken()` instead.\"},\"operatorAddr()\":{\"notice\":\"Address authorized to call `rebase()` directly. The Governor and Strategist are always allowed in addition to this address.\"},\"pauseCapital()\":{\"notice\":\"Set the deposit paused flag to true to prevent capital movement.\"},\"pauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to prevent rebasing.\"},\"previewYield()\":{\"notice\":\"Calculates the amount that would rebase at next rebase. This is before any fees.\"},\"rebase()\":{\"notice\":\"Calculate the total value of asset held by the Vault and all strategies and update the supply of OTokens.\"},\"rebasePaused()\":{\"notice\":\"pause rebasing if true\"},\"rebasePerSecondMax()\":{\"notice\":\"max rebase percentage per second Can be used to set maximum yield of the protocol, spreading out yield over time\"},\"rebasePerSecondTarget()\":{\"notice\":\"target rebase rate limit, based on past rates and funds available.\"},\"removeStrategy(address)\":{\"notice\":\"Remove a strategy from the Vault.\"},\"removeStrategyFromMintWhitelist(address)\":{\"notice\":\"Removes a strategy from the mint whitelist.\"},\"requestWithdrawal(uint256)\":{\"notice\":\"Request an asynchronous withdrawal of asset in exchange for OToken. The OToken is burned on request and the asset is transferred to the withdrawer on claim. This request can be claimed once the withdrawal queue's `claimable` amount is greater than or equal this request's `queued` amount. There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue. OToken is converted to asset at 1:1.\"},\"setAutoAllocateThreshold(uint256)\":{\"notice\":\"Sets the minimum amount of OTokens in a mint to trigger an automatic allocation of funds afterwords.\"},\"setDefaultStrategy(address)\":{\"notice\":\"Set the default Strategy for asset, i.e. the one which the asset will be automatically allocated to and withdrawn from\"},\"setDripDuration(uint256)\":{\"notice\":\"Set the drip duration period\"},\"setMaxSupplyDiff(uint256)\":{\"notice\":\"Sets the maximum allowable difference between total supply and asset' value.\"},\"setOperatorAddr(address)\":{\"notice\":\"Set the address authorized to call `rebase()`.\"},\"setRebaseRateMax(uint256)\":{\"notice\":\"Set a yield streaming max rate. This spreads yield over time if it is above the max rate. This is a per rebase APR which due to compounding differs from the yearly APR. Governance should consider this fact when picking a desired APR\"},\"setStrategistAddr(address)\":{\"notice\":\"Set address of Strategist\"},\"setTrusteeAddress(address)\":{\"notice\":\"Sets the trusteeAddress that can receive a portion of yield. Setting to the zero address disables this feature.\"},\"setTrusteeFeeBps(uint256)\":{\"notice\":\"Sets the TrusteeFeeBps to the percentage of yield that should be received in basis points.\"},\"setVaultBuffer(uint256)\":{\"notice\":\"Set a buffer of asset to keep in the Vault to handle most redemptions without needing to spend gas unwinding asset from a Strategy.\"},\"setWithdrawalClaimDelay(uint256)\":{\"notice\":\"Changes the async withdrawal claim period for OETH & superOETHb\"},\"strategistAddr()\":{\"notice\":\"Address of the Strategist\"},\"totalValue()\":{\"notice\":\"Determine the total value of asset held by the vault and its strategies.\"},\"transferGovernance(address)\":{\"notice\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\"},\"transferToken(address,uint256)\":{\"notice\":\"Transfer token to governor. Intended for recovering tokens stuck in contract, i.e. mistaken sends.\"},\"trusteeAddress()\":{\"notice\":\"Trustee contract that can collect a percentage of yield\"},\"trusteeFeeBps()\":{\"notice\":\"Amount of yield collected in basis points. eg 2000 = 20%\"},\"unpauseCapital()\":{\"notice\":\"Set the deposit paused flag to false to enable capital movement.\"},\"unpauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to allow rebasing.\"},\"vaultBuffer()\":{\"notice\":\"Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\"},\"withdrawAllFromStrategies()\":{\"notice\":\"Withdraws all asset from all the strategies and sends asset to the Vault.\"},\"withdrawAllFromStrategy(address)\":{\"notice\":\"Withdraws all asset from the strategy and sends asset to the Vault.\"},\"withdrawFromStrategy(address,address[],uint256[])\":{\"notice\":\"Withdraw multiple asset from the strategy to the vault.\"},\"withdrawalClaimDelay()\":{\"notice\":\"Sets a minimum delay that is required to elapse between requesting async withdrawals and claiming the request. When set to 0 async withdrawals are disabled.\"},\"withdrawalQueueMetadata()\":{\"notice\":\"Global metadata for the withdrawal queue including: queued - cumulative total of all withdrawal requests included the ones that have already been claimed claimable - cumulative total of all the requests that can be claimed including the ones already claimed claimed - total of all the requests that have been claimed nextWithdrawalIndex - index of the next withdrawal request starting at 0\"},\"withdrawalRequests(uint256)\":{\"notice\":\"Mapping of withdrawal request indices to the user withdrawal request data\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/vault/OUSDVault.sol\":\"OUSDVault\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0x61437cb513a887a1bbad006e7b1c8b414478427d33de47c5600af3c748f108da\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeCast.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\\n * checks.\\n *\\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\\n * easily result in undesired exploitation or bugs, since developers usually\\n * assume that overflows raise errors. `SafeCast` restores this intuition by\\n * reverting the transaction when such an operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n *\\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\\n * all math on `uint256` and `int256` and then downcasting.\\n */\\nlibrary SafeCast {\\n /**\\n * @dev Returns the downcasted uint224 from uint256, reverting on\\n * overflow (when the input is greater than largest uint224).\\n *\\n * Counterpart to Solidity's `uint224` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 224 bits\\n */\\n function toUint224(uint256 value) internal pure returns (uint224) {\\n require(value <= type(uint224).max, \\\"SafeCast: value doesn't fit in 224 bits\\\");\\n return uint224(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint128 from uint256, reverting on\\n * overflow (when the input is greater than largest uint128).\\n *\\n * Counterpart to Solidity's `uint128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n */\\n function toUint128(uint256 value) internal pure returns (uint128) {\\n require(value <= type(uint128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return uint128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint96 from uint256, reverting on\\n * overflow (when the input is greater than largest uint96).\\n *\\n * Counterpart to Solidity's `uint96` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 96 bits\\n */\\n function toUint96(uint256 value) internal pure returns (uint96) {\\n require(value <= type(uint96).max, \\\"SafeCast: value doesn't fit in 96 bits\\\");\\n return uint96(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint64 from uint256, reverting on\\n * overflow (when the input is greater than largest uint64).\\n *\\n * Counterpart to Solidity's `uint64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n */\\n function toUint64(uint256 value) internal pure returns (uint64) {\\n require(value <= type(uint64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return uint64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint32 from uint256, reverting on\\n * overflow (when the input is greater than largest uint32).\\n *\\n * Counterpart to Solidity's `uint32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n */\\n function toUint32(uint256 value) internal pure returns (uint32) {\\n require(value <= type(uint32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return uint32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint16 from uint256, reverting on\\n * overflow (when the input is greater than largest uint16).\\n *\\n * Counterpart to Solidity's `uint16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n */\\n function toUint16(uint256 value) internal pure returns (uint16) {\\n require(value <= type(uint16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return uint16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint8 from uint256, reverting on\\n * overflow (when the input is greater than largest uint8).\\n *\\n * Counterpart to Solidity's `uint8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits.\\n */\\n function toUint8(uint256 value) internal pure returns (uint8) {\\n require(value <= type(uint8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return uint8(value);\\n }\\n\\n /**\\n * @dev Converts a signed int256 into an unsigned uint256.\\n *\\n * Requirements:\\n *\\n * - input must be greater than or equal to 0.\\n */\\n function toUint256(int256 value) internal pure returns (uint256) {\\n require(value >= 0, \\\"SafeCast: value must be positive\\\");\\n return uint256(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int128 from int256, reverting on\\n * overflow (when the input is less than smallest int128 or\\n * greater than largest int128).\\n *\\n * Counterpart to Solidity's `int128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt128(int256 value) internal pure returns (int128) {\\n require(value >= type(int128).min && value <= type(int128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return int128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int64 from int256, reverting on\\n * overflow (when the input is less than smallest int64 or\\n * greater than largest int64).\\n *\\n * Counterpart to Solidity's `int64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt64(int256 value) internal pure returns (int64) {\\n require(value >= type(int64).min && value <= type(int64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return int64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int32 from int256, reverting on\\n * overflow (when the input is less than smallest int32 or\\n * greater than largest int32).\\n *\\n * Counterpart to Solidity's `int32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt32(int256 value) internal pure returns (int32) {\\n require(value >= type(int32).min && value <= type(int32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return int32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int16 from int256, reverting on\\n * overflow (when the input is less than smallest int16 or\\n * greater than largest int16).\\n *\\n * Counterpart to Solidity's `int16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt16(int256 value) internal pure returns (int16) {\\n require(value >= type(int16).min && value <= type(int16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return int16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int8 from int256, reverting on\\n * overflow (when the input is less than smallest int8 or\\n * greater than largest int8).\\n *\\n * Counterpart to Solidity's `int8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits.\\n *\\n * _Available since v3.1._\\n */\\n function toInt8(int256 value) internal pure returns (int8) {\\n require(value >= type(int8).min && value <= type(int8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return int8(value);\\n }\\n\\n /**\\n * @dev Converts an unsigned uint256 into a signed int256.\\n *\\n * Requirements:\\n *\\n * - input must be less than or equal to maxInt256.\\n */\\n function toInt256(uint256 value) internal pure returns (int256) {\\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\\n require(value <= uint256(type(int256).max), \\\"SafeCast: value doesn't fit in an int256\\\");\\n return int256(value);\\n }\\n}\\n\",\"keccak256\":\"0x5c6caab697d302ad7eb59c234a4d2dbc965c1bae87709bd2850060b7695b28c7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa2f576be637946f767aa56601c26d717f48a0aff44f82e46f13807eea1009a21\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @notice Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @notice Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n emit GovernorshipTransferred(_governor(), newGovernor);\\n\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0xf32f873c8bfbacf2e5f01d0cf37bc7f54fbd5aa656e95c8a599114229946f107\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xa562062698aa12572123b36dfd2072f1a39e44fed2031cc19c2c9fd522f96ec2\",\"license\":\"MIT\"},\"contracts/interfaces/IStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\\n */\\ninterface IStrategy {\\n /**\\n * @dev Deposit the given asset to platform\\n * @param _asset asset address\\n * @param _amount Amount to deposit\\n */\\n function deposit(address _asset, uint256 _amount) external;\\n\\n /**\\n * @dev Deposit the entire balance of all supported assets in the Strategy\\n * to the platform\\n */\\n function depositAll() external;\\n\\n /**\\n * @dev Withdraw given asset from Lending platform\\n */\\n function withdraw(\\n address _recipient,\\n address _asset,\\n uint256 _amount\\n ) external;\\n\\n /**\\n * @dev Liquidate all assets in strategy and return them to Vault.\\n */\\n function withdrawAll() external;\\n\\n /**\\n * @dev Returns the current balance of the given asset.\\n */\\n function checkBalance(address _asset)\\n external\\n view\\n returns (uint256 balance);\\n\\n /**\\n * @dev Returns bool indicating whether strategy supports asset.\\n */\\n function supportsAsset(address _asset) external view returns (bool);\\n\\n /**\\n * @dev Collect reward tokens from the Strategy.\\n */\\n function collectRewardTokens() external;\\n\\n /**\\n * @dev The address array of the reward tokens for the Strategy.\\n */\\n function getRewardTokenAddresses() external view returns (address[] memory);\\n\\n function harvesterAddress() external view returns (address);\\n\\n function transferToken(address token, uint256 amount) external;\\n\\n function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\\n external;\\n}\\n\",\"keccak256\":\"0x79ca47defb3b5a56bba13f14c440838152fd1c1aa640476154516a16da4da8ba\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/IVault.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { VaultStorage } from \\\"../vault/VaultStorage.sol\\\";\\n\\ninterface IVault {\\n // slither-disable-start constable-states\\n\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event DefaultStrategyUpdated(address _strategy);\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\\n event DripDurationChanged(uint256 dripDuration);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\\n\\n // Governable.sol\\n function transferGovernance(address _newGovernor) external;\\n\\n function claimGovernance() external;\\n\\n function governor() external view returns (address);\\n\\n // VaultAdmin.sol\\n function setVaultBuffer(uint256 _vaultBuffer) external;\\n\\n function vaultBuffer() external view returns (uint256);\\n\\n function setAutoAllocateThreshold(uint256 _threshold) external;\\n\\n function autoAllocateThreshold() external view returns (uint256);\\n\\n function setStrategistAddr(address _address) external;\\n\\n function strategistAddr() external view returns (address);\\n\\n function setOperatorAddr(address _operator) external;\\n\\n function operatorAddr() external view returns (address);\\n\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\\n\\n function maxSupplyDiff() external view returns (uint256);\\n\\n function setTrusteeAddress(address _address) external;\\n\\n function trusteeAddress() external view returns (address);\\n\\n function setTrusteeFeeBps(uint256 _basis) external;\\n\\n function trusteeFeeBps() external view returns (uint256);\\n\\n function approveStrategy(address _addr) external;\\n\\n function removeStrategy(address _addr) external;\\n\\n function setDefaultStrategy(address _strategy) external;\\n\\n function defaultStrategy() external view returns (address);\\n\\n function pauseRebase() external;\\n\\n function unpauseRebase() external;\\n\\n function rebasePaused() external view returns (bool);\\n\\n function pauseCapital() external;\\n\\n function unpauseCapital() external;\\n\\n function capitalPaused() external view returns (bool);\\n\\n function transferToken(address _asset, uint256 _amount) external;\\n\\n function withdrawAllFromStrategy(address _strategyAddr) external;\\n\\n function withdrawAllFromStrategies() external;\\n\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n // VaultCore.sol\\n function mint(uint256 _amount) external;\\n\\n function mintForStrategy(uint256 _amount) external;\\n\\n function burnForStrategy(uint256 _amount) external;\\n\\n function allocate() external;\\n\\n function rebase() external;\\n\\n function totalValue() external view returns (uint256 value);\\n\\n function checkBalance(address _asset) external view returns (uint256);\\n\\n function getAssetCount() external view returns (uint256);\\n\\n function getAllAssets() external view returns (address[] memory);\\n\\n function getStrategyCount() external view returns (uint256);\\n\\n function getAllStrategies() external view returns (address[] memory);\\n\\n function strategies(address _addr)\\n external\\n view\\n returns (VaultStorage.Strategy memory);\\n\\n /// @notice Deprecated: use `asset()` instead.\\n function isSupportedAsset(address _asset) external view returns (bool);\\n\\n function asset() external view returns (address);\\n\\n function oToken() external view returns (address);\\n\\n function initialize(address) external;\\n\\n function addWithdrawalQueueLiquidity() external;\\n\\n function requestWithdrawal(uint256 _amount)\\n external\\n returns (uint256 requestId, uint256 queued);\\n\\n function claimWithdrawal(uint256 requestId)\\n external\\n returns (uint256 amount);\\n\\n function claimWithdrawals(uint256[] memory requestIds)\\n external\\n returns (uint256[] memory amounts, uint256 totalAmount);\\n\\n function withdrawalQueueMetadata()\\n external\\n view\\n returns (VaultStorage.WithdrawalQueueMetadata memory);\\n\\n function withdrawalRequests(uint256 requestId)\\n external\\n view\\n returns (VaultStorage.WithdrawalRequest memory);\\n\\n function addStrategyToMintWhitelist(address strategyAddr) external;\\n\\n function removeStrategyFromMintWhitelist(address strategyAddr) external;\\n\\n function isMintWhitelistedStrategy(address strategyAddr)\\n external\\n view\\n returns (bool);\\n\\n function withdrawalClaimDelay() external view returns (uint256);\\n\\n function setWithdrawalClaimDelay(uint256 newDelay) external;\\n\\n function lastRebase() external view returns (uint64);\\n\\n function dripDuration() external view returns (uint64);\\n\\n function setDripDuration(uint256 _dripDuration) external;\\n\\n function rebasePerSecondMax() external view returns (uint64);\\n\\n function setRebaseRateMax(uint256 yearlyApr) external;\\n\\n function rebasePerSecondTarget() external view returns (uint64);\\n\\n function previewYield() external view returns (uint256 yield);\\n\\n // slither-disable-end constable-states\\n}\\n\",\"keccak256\":\"0x573ee781634813c659362ca2950f439711c2d2b1f79b285d22ecd14c8c32fb9d\",\"license\":\"BUSL-1.1\"},\"contracts/token/OUSD.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OUSD Token Contract\\n * @dev ERC20 compatible contract for OUSD\\n * @dev Implements an elastic supply\\n * @author Origin Protocol Inc\\n */\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\ncontract OUSD is Governable {\\n using SafeCast for int256;\\n using SafeCast for uint256;\\n\\n /// @dev Event triggered when the supply changes\\n /// @param totalSupply Updated token total supply\\n /// @param rebasingCredits Updated token rebasing credits\\n /// @param rebasingCreditsPerToken Updated token rebasing credits per token\\n event TotalSupplyUpdatedHighres(\\n uint256 totalSupply,\\n uint256 rebasingCredits,\\n uint256 rebasingCreditsPerToken\\n );\\n /// @dev Event triggered when an account opts in for rebasing\\n /// @param account Address of the account\\n event AccountRebasingEnabled(address account);\\n /// @dev Event triggered when an account opts out of rebasing\\n /// @param account Address of the account\\n event AccountRebasingDisabled(address account);\\n /// @dev Emitted when `value` tokens are moved from one account `from` to\\n /// another `to`.\\n /// @param from Address of the account tokens are moved from\\n /// @param to Address of the account tokens are moved to\\n /// @param value Amount of tokens transferred\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n /// @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n /// a call to {approve}. `value` is the new allowance.\\n /// @param owner Address of the owner approving allowance\\n /// @param spender Address of the spender allowance is granted to\\n /// @param value Amount of tokens spender can transfer\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 value\\n );\\n /// @dev Yield resulting from {changeSupply} that a `source` account would\\n /// receive is directed to `target` account.\\n /// @param source Address of the source forwarding the yield\\n /// @param target Address of the target receiving the yield\\n event YieldDelegated(address source, address target);\\n /// @dev Yield delegation from `source` account to the `target` account is\\n /// suspended.\\n /// @param source Address of the source suspending yield forwarding\\n /// @param target Address of the target no longer receiving yield from `source`\\n /// account\\n event YieldUndelegated(address source, address target);\\n\\n enum RebaseOptions {\\n NotSet,\\n StdNonRebasing,\\n StdRebasing,\\n YieldDelegationSource,\\n YieldDelegationTarget\\n }\\n\\n uint256[154] private _gap; // Slots to align with deployed contract\\n uint256 private constant MAX_SUPPLY = type(uint128).max;\\n /// @dev The amount of tokens in existence\\n uint256 public totalSupply;\\n mapping(address => mapping(address => uint256)) private allowances;\\n /// @dev The vault with privileges to execute {mint}, {burn}\\n /// and {changeSupply}\\n address public vaultAddress;\\n mapping(address => uint256) internal creditBalances;\\n // the 2 storage variables below need trailing underscores to not name collide with public functions\\n uint256 private rebasingCredits_; // Sum of all rebasing credits (creditBalances for rebasing accounts)\\n uint256 private rebasingCreditsPerToken_;\\n /// @dev The amount of tokens that are not rebasing - receiving yield\\n uint256 public nonRebasingSupply;\\n mapping(address => uint256) internal alternativeCreditsPerToken;\\n /// @dev A map of all addresses and their respective RebaseOptions\\n mapping(address => RebaseOptions) public rebaseState;\\n mapping(address => uint256) private __deprecated_isUpgraded;\\n /// @dev A map of addresses that have yields forwarded to. This is an\\n /// inverse mapping of {yieldFrom}\\n /// Key Account forwarding yield\\n /// Value Account receiving yield\\n mapping(address => address) public yieldTo;\\n /// @dev A map of addresses that are receiving the yield. This is an\\n /// inverse mapping of {yieldTo}\\n /// Key Account receiving yield\\n /// Value Account forwarding yield\\n mapping(address => address) public yieldFrom;\\n\\n uint256 private constant RESOLUTION_INCREASE = 1e9;\\n uint256[34] private __gap; // including below gap totals up to 200\\n\\n /// @dev Verifies that the caller is the Governor or Strategist.\\n modifier onlyGovernorOrStrategist() {\\n require(\\n isGovernor() || msg.sender == IVault(vaultAddress).strategistAddr(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n /// @dev Initializes the contract and sets necessary variables.\\n /// @param _vaultAddress Address of the vault contract\\n /// @param _initialCreditsPerToken The starting rebasing credits per token.\\n function initialize(address _vaultAddress, uint256 _initialCreditsPerToken)\\n external\\n onlyGovernor\\n {\\n require(_vaultAddress != address(0), \\\"Zero vault address\\\");\\n require(vaultAddress == address(0), \\\"Already initialized\\\");\\n\\n rebasingCreditsPerToken_ = _initialCreditsPerToken;\\n vaultAddress = _vaultAddress;\\n }\\n\\n /// @dev Returns the symbol of the token, a shorter version\\n /// of the name.\\n function symbol() external pure virtual returns (string memory) {\\n return \\\"OUSD\\\";\\n }\\n\\n /// @dev Returns the name of the token.\\n function name() external pure virtual returns (string memory) {\\n return \\\"Origin Dollar\\\";\\n }\\n\\n /// @dev Returns the number of decimals used to get its user representation.\\n function decimals() external pure virtual returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev Verifies that the caller is the Vault contract\\n */\\n modifier onlyVault() {\\n require(vaultAddress == msg.sender, \\\"Caller is not the Vault\\\");\\n _;\\n }\\n\\n /**\\n * @return High resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerTokenHighres() external view returns (uint256) {\\n return rebasingCreditsPerToken_;\\n }\\n\\n /**\\n * @return Low resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerToken() external view returns (uint256) {\\n return rebasingCreditsPerToken_ / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return High resolution total number of rebasing credits\\n */\\n function rebasingCreditsHighres() external view returns (uint256) {\\n return rebasingCredits_;\\n }\\n\\n /**\\n * @return Low resolution total number of rebasing credits\\n */\\n function rebasingCredits() external view returns (uint256) {\\n return rebasingCredits_ / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @notice Gets the balance of the specified address.\\n * @param _account Address to query the balance of.\\n * @return A uint256 representing the amount of base units owned by the\\n * specified address.\\n */\\n function balanceOf(address _account) public view returns (uint256) {\\n RebaseOptions state = rebaseState[_account];\\n if (state == RebaseOptions.YieldDelegationSource) {\\n // Saves a slot read when transferring to or from a yield delegating source\\n // since we know creditBalances equals the balance.\\n return creditBalances[_account];\\n }\\n uint256 baseBalance = (creditBalances[_account] * 1e18) /\\n _creditsPerToken(_account);\\n if (state == RebaseOptions.YieldDelegationTarget) {\\n // creditBalances of yieldFrom accounts equals token balances\\n return baseBalance - creditBalances[yieldFrom[_account]];\\n }\\n return baseBalance;\\n }\\n\\n /**\\n * @notice Gets the credits balance of the specified address.\\n * @dev Backwards compatible with old low res credits per token.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256) Credit balance and credits per token of the\\n * address\\n */\\n function creditsBalanceOf(address _account)\\n external\\n view\\n returns (uint256, uint256)\\n {\\n uint256 cpt = _creditsPerToken(_account);\\n if (cpt == 1e27) {\\n // For a period before the resolution upgrade, we created all new\\n // contract accounts at high resolution. Since they are not changing\\n // as a result of this upgrade, we will return their true values\\n return (creditBalances[_account], cpt);\\n } else {\\n return (\\n creditBalances[_account] / RESOLUTION_INCREASE,\\n cpt / RESOLUTION_INCREASE\\n );\\n }\\n }\\n\\n /**\\n * @notice Gets the credits balance of the specified address.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\\n * address, and isUpgraded\\n */\\n function creditsBalanceOfHighres(address _account)\\n external\\n view\\n returns (\\n uint256,\\n uint256,\\n bool\\n )\\n {\\n return (\\n creditBalances[_account],\\n _creditsPerToken(_account),\\n true // all accounts have their resolution \\\"upgraded\\\"\\n );\\n }\\n\\n // Backwards compatible view\\n function nonRebasingCreditsPerToken(address _account)\\n external\\n view\\n returns (uint256)\\n {\\n return alternativeCreditsPerToken[_account];\\n }\\n\\n /**\\n * @notice Transfer tokens to a specified address.\\n * @param _to the address to transfer to.\\n * @param _value the amount to be transferred.\\n * @return true on success.\\n */\\n function transfer(address _to, uint256 _value) external returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n\\n _executeTransfer(msg.sender, _to, _value);\\n\\n emit Transfer(msg.sender, _to, _value);\\n return true;\\n }\\n\\n /**\\n * @notice Transfer tokens from one address to another.\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value The amount of tokens to be transferred.\\n * @return true on success.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n uint256 userAllowance = allowances[_from][msg.sender];\\n require(_value <= userAllowance, \\\"Allowance exceeded\\\");\\n\\n unchecked {\\n allowances[_from][msg.sender] = userAllowance - _value;\\n }\\n\\n _executeTransfer(_from, _to, _value);\\n\\n emit Transfer(_from, _to, _value);\\n return true;\\n }\\n\\n function _executeTransfer(\\n address _from,\\n address _to,\\n uint256 _value\\n ) internal {\\n (\\n int256 fromRebasingCreditsDiff,\\n int256 fromNonRebasingSupplyDiff\\n ) = _adjustAccount(_from, -_value.toInt256());\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_to, _value.toInt256());\\n\\n _adjustGlobals(\\n fromRebasingCreditsDiff + toRebasingCreditsDiff,\\n fromNonRebasingSupplyDiff + toNonRebasingSupplyDiff\\n );\\n }\\n\\n function _adjustAccount(address _account, int256 _balanceChange)\\n internal\\n returns (int256 rebasingCreditsDiff, int256 nonRebasingSupplyDiff)\\n {\\n RebaseOptions state = rebaseState[_account];\\n int256 currentBalance = balanceOf(_account).toInt256();\\n if (currentBalance + _balanceChange < 0) {\\n revert(\\\"Transfer amount exceeds balance\\\");\\n }\\n uint256 newBalance = (currentBalance + _balanceChange).toUint256();\\n\\n if (state == RebaseOptions.YieldDelegationSource) {\\n address target = yieldTo[_account];\\n uint256 targetOldBalance = balanceOf(target);\\n uint256 targetNewCredits = _balanceToRebasingCredits(\\n targetOldBalance + newBalance\\n );\\n rebasingCreditsDiff =\\n targetNewCredits.toInt256() -\\n creditBalances[target].toInt256();\\n\\n creditBalances[_account] = newBalance;\\n creditBalances[target] = targetNewCredits;\\n } else if (state == RebaseOptions.YieldDelegationTarget) {\\n uint256 newCredits = _balanceToRebasingCredits(\\n newBalance + creditBalances[yieldFrom[_account]]\\n );\\n rebasingCreditsDiff =\\n newCredits.toInt256() -\\n creditBalances[_account].toInt256();\\n creditBalances[_account] = newCredits;\\n } else {\\n _autoMigrate(_account);\\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\\n _account\\n ];\\n if (alternativeCreditsPerTokenMem > 0) {\\n nonRebasingSupplyDiff = _balanceChange;\\n if (alternativeCreditsPerTokenMem != 1e18) {\\n alternativeCreditsPerToken[_account] = 1e18;\\n }\\n creditBalances[_account] = newBalance;\\n } else {\\n uint256 newCredits = _balanceToRebasingCredits(newBalance);\\n rebasingCreditsDiff =\\n newCredits.toInt256() -\\n creditBalances[_account].toInt256();\\n creditBalances[_account] = newCredits;\\n }\\n }\\n }\\n\\n function _adjustGlobals(\\n int256 _rebasingCreditsDiff,\\n int256 _nonRebasingSupplyDiff\\n ) internal {\\n if (_rebasingCreditsDiff != 0) {\\n rebasingCredits_ = (rebasingCredits_.toInt256() +\\n _rebasingCreditsDiff).toUint256();\\n }\\n if (_nonRebasingSupplyDiff != 0) {\\n nonRebasingSupply = (nonRebasingSupply.toInt256() +\\n _nonRebasingSupplyDiff).toUint256();\\n }\\n }\\n\\n /**\\n * @notice Function to check the amount of tokens that _owner has allowed\\n * to `_spender`.\\n * @param _owner The address which owns the funds.\\n * @param _spender The address which will spend the funds.\\n * @return The number of tokens still available for the _spender.\\n */\\n function allowance(address _owner, address _spender)\\n external\\n view\\n returns (uint256)\\n {\\n return allowances[_owner][_spender];\\n }\\n\\n /**\\n * @notice Approve the passed address to spend the specified amount of\\n * tokens on behalf of msg.sender.\\n * @param _spender The address which will spend the funds.\\n * @param _value The amount of tokens to be spent.\\n * @return true on success.\\n */\\n function approve(address _spender, uint256 _value) external returns (bool) {\\n allowances[msg.sender][_spender] = _value;\\n emit Approval(msg.sender, _spender, _value);\\n return true;\\n }\\n\\n /**\\n * @notice Creates `_amount` tokens and assigns them to `_account`,\\n * increasing the total supply.\\n */\\n function mint(address _account, uint256 _amount) external onlyVault {\\n require(_account != address(0), \\\"Mint to the zero address\\\");\\n\\n // Account\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_account, _amount.toInt256());\\n // Globals\\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\\n totalSupply = totalSupply + _amount;\\n\\n require(totalSupply < MAX_SUPPLY, \\\"Max supply\\\");\\n emit Transfer(address(0), _account, _amount);\\n }\\n\\n /**\\n * @notice Destroys `_amount` tokens from `_account`,\\n * reducing the total supply.\\n */\\n function burn(address _account, uint256 _amount) external onlyVault {\\n require(_account != address(0), \\\"Burn from the zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n\\n // Account\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_account, -_amount.toInt256());\\n // Globals\\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\\n totalSupply = totalSupply - _amount;\\n\\n emit Transfer(_account, address(0), _amount);\\n }\\n\\n /**\\n * @dev Get the credits per token for an account. Returns a fixed amount\\n * if the account is non-rebasing.\\n * @param _account Address of the account.\\n */\\n function _creditsPerToken(address _account)\\n internal\\n view\\n returns (uint256)\\n {\\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\\n _account\\n ];\\n if (alternativeCreditsPerTokenMem != 0) {\\n return alternativeCreditsPerTokenMem;\\n } else {\\n return rebasingCreditsPerToken_;\\n }\\n }\\n\\n /**\\n * @dev Auto migrate contracts to be non rebasing,\\n * unless they have opted into yield.\\n * @param _account Address of the account.\\n */\\n function _autoMigrate(address _account) internal {\\n uint256 codeLen = _account.code.length;\\n bool isEOA = (codeLen == 0) ||\\n (codeLen == 23 && bytes3(_account.code) == 0xef0100);\\n // In previous code versions, contracts would not have had their\\n // rebaseState[_account] set to RebaseOptions.NonRebasing when migrated\\n // therefore we check the actual accounting used on the account as well.\\n if (\\n (!isEOA) &&\\n rebaseState[_account] == RebaseOptions.NotSet &&\\n alternativeCreditsPerToken[_account] == 0\\n ) {\\n _rebaseOptOut(_account);\\n }\\n }\\n\\n /**\\n * @dev Calculates credits from contract's global rebasingCreditsPerToken_, and\\n * also balance that corresponds to those credits. The latter is important\\n * when adjusting the contract's global nonRebasingSupply to circumvent any\\n * possible rounding errors.\\n *\\n * @param _balance Balance of the account.\\n */\\n function _balanceToRebasingCredits(uint256 _balance)\\n internal\\n view\\n returns (uint256 rebasingCredits)\\n {\\n // Rounds up, because we need to ensure that accounts always have\\n // at least the balance that they should have.\\n // Note this should always be used on an absolute account value,\\n // not on a possibly negative diff, because then the rounding would be wrong.\\n return ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18;\\n }\\n\\n /**\\n * @notice The calling account will start receiving yield after a successful call.\\n * @param _account Address of the account.\\n */\\n function governanceRebaseOptIn(address _account) external onlyGovernor {\\n require(_account != address(0), \\\"Zero address not allowed\\\");\\n _rebaseOptIn(_account);\\n }\\n\\n /**\\n * @notice The calling account will start receiving yield after a successful call.\\n */\\n function rebaseOptIn() external {\\n _rebaseOptIn(msg.sender);\\n }\\n\\n function _rebaseOptIn(address _account) internal {\\n uint256 balance = balanceOf(_account);\\n\\n // prettier-ignore\\n require(\\n alternativeCreditsPerToken[_account] > 0 ||\\n // Accounts may explicitly `rebaseOptIn` regardless of\\n // accounting if they have a 0 balance.\\n creditBalances[_account] == 0\\n ,\\n \\\"Account must be non-rebasing\\\"\\n );\\n RebaseOptions state = rebaseState[_account];\\n // prettier-ignore\\n require(\\n state == RebaseOptions.StdNonRebasing ||\\n state == RebaseOptions.NotSet,\\n \\\"Only standard non-rebasing accounts can opt in\\\"\\n );\\n\\n uint256 newCredits = _balanceToRebasingCredits(balance);\\n\\n // Account\\n rebaseState[_account] = RebaseOptions.StdRebasing;\\n alternativeCreditsPerToken[_account] = 0;\\n creditBalances[_account] = newCredits;\\n // Globals\\n _adjustGlobals(newCredits.toInt256(), -balance.toInt256());\\n\\n emit AccountRebasingEnabled(_account);\\n }\\n\\n /**\\n * @notice The calling account will no longer receive yield\\n */\\n function rebaseOptOut() external {\\n _rebaseOptOut(msg.sender);\\n }\\n\\n function _rebaseOptOut(address _account) internal {\\n require(\\n alternativeCreditsPerToken[_account] == 0,\\n \\\"Account must be rebasing\\\"\\n );\\n RebaseOptions state = rebaseState[_account];\\n require(\\n state == RebaseOptions.StdRebasing || state == RebaseOptions.NotSet,\\n \\\"Only standard rebasing accounts can opt out\\\"\\n );\\n\\n uint256 oldCredits = creditBalances[_account];\\n uint256 balance = balanceOf(_account);\\n\\n // Account\\n rebaseState[_account] = RebaseOptions.StdNonRebasing;\\n alternativeCreditsPerToken[_account] = 1e18;\\n creditBalances[_account] = balance;\\n // Globals\\n _adjustGlobals(-oldCredits.toInt256(), balance.toInt256());\\n\\n emit AccountRebasingDisabled(_account);\\n }\\n\\n /**\\n * @notice Distribute yield to users. This changes the exchange rate\\n * between \\\"credits\\\" and OUSD tokens to change rebasing user's balances.\\n * @param _newTotalSupply New total supply of OUSD.\\n */\\n function changeSupply(uint256 _newTotalSupply) external onlyVault {\\n require(totalSupply > 0, \\\"Cannot increase 0 supply\\\");\\n\\n if (totalSupply == _newTotalSupply) {\\n emit TotalSupplyUpdatedHighres(\\n totalSupply,\\n rebasingCredits_,\\n rebasingCreditsPerToken_\\n );\\n return;\\n }\\n\\n totalSupply = _newTotalSupply > MAX_SUPPLY\\n ? MAX_SUPPLY\\n : _newTotalSupply;\\n\\n uint256 rebasingSupply = totalSupply - nonRebasingSupply;\\n // round up in the favour of the protocol\\n rebasingCreditsPerToken_ =\\n (rebasingCredits_ * 1e18 + rebasingSupply - 1) /\\n rebasingSupply;\\n\\n require(rebasingCreditsPerToken_ > 0, \\\"Invalid change in supply\\\");\\n\\n emit TotalSupplyUpdatedHighres(\\n totalSupply,\\n rebasingCredits_,\\n rebasingCreditsPerToken_\\n );\\n }\\n\\n /*\\n * @notice Send the yield from one account to another account.\\n * Each account keeps its own balances.\\n */\\n function delegateYield(address _from, address _to)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_from != address(0), \\\"Zero from address not allowed\\\");\\n require(_to != address(0), \\\"Zero to address not allowed\\\");\\n\\n require(_from != _to, \\\"Cannot delegate to self\\\");\\n require(\\n yieldFrom[_to] == address(0) &&\\n yieldTo[_to] == address(0) &&\\n yieldFrom[_from] == address(0) &&\\n yieldTo[_from] == address(0),\\n \\\"Blocked by existing yield delegation\\\"\\n );\\n RebaseOptions stateFrom = rebaseState[_from];\\n RebaseOptions stateTo = rebaseState[_to];\\n\\n require(\\n stateFrom == RebaseOptions.NotSet ||\\n stateFrom == RebaseOptions.StdNonRebasing ||\\n stateFrom == RebaseOptions.StdRebasing,\\n \\\"Invalid rebaseState from\\\"\\n );\\n\\n require(\\n stateTo == RebaseOptions.NotSet ||\\n stateTo == RebaseOptions.StdNonRebasing ||\\n stateTo == RebaseOptions.StdRebasing,\\n \\\"Invalid rebaseState to\\\"\\n );\\n\\n if (alternativeCreditsPerToken[_from] == 0) {\\n _rebaseOptOut(_from);\\n }\\n if (alternativeCreditsPerToken[_to] > 0) {\\n _rebaseOptIn(_to);\\n }\\n\\n uint256 fromBalance = balanceOf(_from);\\n uint256 toBalance = balanceOf(_to);\\n uint256 oldToCredits = creditBalances[_to];\\n uint256 newToCredits = _balanceToRebasingCredits(\\n fromBalance + toBalance\\n );\\n\\n // Set up the bidirectional links\\n yieldTo[_from] = _to;\\n yieldFrom[_to] = _from;\\n\\n // Local\\n rebaseState[_from] = RebaseOptions.YieldDelegationSource;\\n alternativeCreditsPerToken[_from] = 1e18;\\n creditBalances[_from] = fromBalance;\\n rebaseState[_to] = RebaseOptions.YieldDelegationTarget;\\n creditBalances[_to] = newToCredits;\\n\\n // Global\\n int256 creditsChange = newToCredits.toInt256() -\\n oldToCredits.toInt256();\\n _adjustGlobals(creditsChange, -(fromBalance).toInt256());\\n emit YieldDelegated(_from, _to);\\n }\\n\\n /*\\n * @notice Stop sending the yield from one account to another account.\\n */\\n function undelegateYield(address _from) external onlyGovernorOrStrategist {\\n // Require a delegation, which will also ensure a valid delegation\\n require(yieldTo[_from] != address(0), \\\"Zero address not allowed\\\");\\n\\n address to = yieldTo[_from];\\n uint256 fromBalance = balanceOf(_from);\\n uint256 toBalance = balanceOf(to);\\n uint256 oldToCredits = creditBalances[to];\\n uint256 newToCredits = _balanceToRebasingCredits(toBalance);\\n\\n // Remove the bidirectional links\\n yieldFrom[to] = address(0);\\n yieldTo[_from] = address(0);\\n\\n // Local\\n rebaseState[_from] = RebaseOptions.StdNonRebasing;\\n // alternativeCreditsPerToken[from] already 1e18 from `delegateYield()`\\n creditBalances[_from] = fromBalance;\\n rebaseState[to] = RebaseOptions.StdRebasing;\\n // alternativeCreditsPerToken[to] already 0 from `delegateYield()`\\n creditBalances[to] = newToCredits;\\n\\n // Global\\n int256 creditsChange = newToCredits.toInt256() -\\n oldToCredits.toInt256();\\n _adjustGlobals(creditsChange, fromBalance.toInt256());\\n emit YieldUndelegated(_from, to);\\n }\\n}\\n\",\"keccak256\":\"0x73439bef6569f5adf6f5ce2cb54a5f0d3109d4819457532236e172a7091980a9\",\"license\":\"BUSL-1.1\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { IBasicToken } from \\\"../interfaces/IBasicToken.sol\\\";\\n\\nlibrary Helpers {\\n /**\\n * @notice Fetch the `symbol()` from an ERC20 token\\n * @dev Grabs the `symbol()` from a contract\\n * @param _token Address of the ERC20 token\\n * @return string Symbol of the ERC20 token\\n */\\n function getSymbol(address _token) internal view returns (string memory) {\\n string memory symbol = IBasicToken(_token).symbol();\\n return symbol;\\n }\\n\\n /**\\n * @notice Fetch the `decimals()` from an ERC20 token\\n * @dev Grabs the `decimals()` from a contract and fails if\\n * the decimal value does not live within a certain range\\n * @param _token Address of the ERC20 token\\n * @return uint256 Decimals of the ERC20 token\\n */\\n function getDecimals(address _token) internal view returns (uint256) {\\n uint256 decimals = IBasicToken(_token).decimals();\\n require(\\n decimals >= 4 && decimals <= 18,\\n \\\"Token must have sufficient decimal places\\\"\\n );\\n\\n return decimals;\\n }\\n}\\n\",\"keccak256\":\"0x4366f8d90b34c1eef8bbaaf369b1e5cd59f04027bb3c111f208eaee65bbc0346\",\"license\":\"BUSL-1.1\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base contract any contracts that need to initialize state after deployment.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0x50d39ebf38a3d3111f2b77a6c75ece1d4ae731552fec4697ab16fcf6c0d4d5e8\",\"license\":\"BUSL-1.1\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n // slither-disable-next-line divide-before-multiply\\n x = x.div(10**(from - to));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e36 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0x71d6ed0053a1e5ef018d27c3b6d024f336d8157ab6f6859e400b3243a50a71b7\",\"license\":\"BUSL-1.1\"},\"contracts/vault/OUSDVault.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { VaultAdmin } from \\\"./VaultAdmin.sol\\\";\\n\\n/**\\n * @title OUSD VaultAdmin Contract\\n * @author Origin Protocol Inc\\n */\\ncontract OUSDVault is VaultAdmin {\\n constructor(address _usdc) VaultAdmin(_usdc) {}\\n}\\n\",\"keccak256\":\"0xb9112bcf70fc7adffe9051e62d3f71ee69f7e06bd7ec7dcce2a149ab8d58693c\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultAdmin contract\\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\nimport \\\"./VaultCore.sol\\\";\\n\\nabstract contract VaultAdmin is VaultCore {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n using SafeCast for uint256;\\n\\n /**\\n * @dev Verifies that the caller is the Governor or Strategist.\\n */\\n modifier onlyGovernorOrStrategist() {\\n require(\\n msg.sender == strategistAddr || isGovernor(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n constructor(address _asset) VaultCore(_asset) {}\\n\\n /***************************************\\n Configuration\\n ****************************************/\\n /**\\n * @notice Set a buffer of asset to keep in the Vault to handle most\\n * redemptions without needing to spend gas unwinding asset from a Strategy.\\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\\n */\\n function setVaultBuffer(uint256 _vaultBuffer)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_vaultBuffer <= 1e18, \\\"Invalid value\\\");\\n vaultBuffer = _vaultBuffer;\\n emit VaultBufferUpdated(_vaultBuffer);\\n }\\n\\n /**\\n * @notice Sets the minimum amount of OTokens in a mint to trigger an\\n * automatic allocation of funds afterwords.\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setAutoAllocateThreshold(uint256 _threshold)\\n external\\n onlyGovernor\\n {\\n autoAllocateThreshold = _threshold;\\n emit AllocateThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set address of Strategist\\n * @param _address Address of Strategist\\n */\\n function setStrategistAddr(address _address) external onlyGovernor {\\n strategistAddr = _address;\\n emit StrategistUpdated(_address);\\n }\\n\\n /**\\n * @notice Set the address authorized to call `rebase()`.\\n * @param _operator New operator address. May be set to the zero address\\n * to disable operator-initiated rebases.\\n */\\n function setOperatorAddr(address _operator) external onlyGovernor {\\n operatorAddr = _operator;\\n emit OperatorUpdated(_operator);\\n }\\n\\n /**\\n * @notice Set the default Strategy for asset, i.e. the one which\\n * the asset will be automatically allocated to and withdrawn from\\n * @param _strategy Address of the Strategy\\n */\\n function setDefaultStrategy(address _strategy)\\n external\\n onlyGovernorOrStrategist\\n {\\n emit DefaultStrategyUpdated(_strategy);\\n // If its a zero address being passed for the strategy we are removing\\n // the default strategy\\n if (_strategy != address(0)) {\\n // Make sure the strategy meets some criteria\\n require(strategies[_strategy].isSupported, \\\"Strategy not approved\\\");\\n require(\\n IStrategy(_strategy).supportsAsset(asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n }\\n defaultStrategy = _strategy;\\n }\\n\\n /**\\n * @notice Changes the async withdrawal claim period for OETH & superOETHb\\n * @param _delay Delay period (should be between 10 mins to 7 days).\\n * Set to 0 to disable async withdrawals\\n */\\n function setWithdrawalClaimDelay(uint256 _delay) external onlyGovernor {\\n require(\\n _delay == 0 || (_delay >= 10 minutes && _delay <= 15 days),\\n \\\"Invalid claim delay period\\\"\\n );\\n withdrawalClaimDelay = _delay;\\n emit WithdrawalClaimDelayUpdated(_delay);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Set a yield streaming max rate. This spreads yield over\\n * time if it is above the max rate. This is a per rebase APR which\\n * due to compounding differs from the yearly APR. Governance should\\n * consider this fact when picking a desired APR\\n * @param apr in 1e18 notation. 3 * 1e18 = 3% APR\\n */\\n function setRebaseRateMax(uint256 apr) external onlyGovernorOrStrategist {\\n // The old yield will be at the old rate\\n _rebase();\\n // Change the rate\\n uint256 newPerSecond = apr / 100 / 365 days;\\n require(newPerSecond <= MAX_REBASE_PER_SECOND, \\\"Rate too high\\\");\\n rebasePerSecondMax = newPerSecond.toUint64();\\n emit RebasePerSecondMaxChanged(newPerSecond);\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Set the drip duration period\\n * @param _dripDuration Time in seconds to target a constant yield rate\\n */\\n function setDripDuration(uint256 _dripDuration)\\n external\\n onlyGovernorOrStrategist\\n {\\n // The old yield will be at the old rate\\n _rebase();\\n dripDuration = _dripDuration.toUint64();\\n emit DripDurationChanged(_dripDuration);\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /***************************************\\n Strategy Config\\n ****************************************/\\n\\n /**\\n * @notice Add a strategy to the Vault.\\n * @param _addr Address of the strategy to add\\n */\\n function approveStrategy(address _addr) external onlyGovernor {\\n require(!strategies[_addr].isSupported, \\\"Strategy already approved\\\");\\n require(\\n IStrategy(_addr).supportsAsset(asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\\n allStrategies.push(_addr);\\n emit StrategyApproved(_addr);\\n }\\n\\n /**\\n * @notice Remove a strategy from the Vault.\\n * @param _addr Address of the strategy to remove\\n */\\n\\n function removeStrategy(address _addr) external onlyGovernor {\\n require(strategies[_addr].isSupported, \\\"Strategy not approved\\\");\\n require(defaultStrategy != _addr, \\\"Strategy is default for asset\\\");\\n\\n // Initialize strategyIndex with out of bounds result so function will\\n // revert if no valid index found\\n uint256 stratCount = allStrategies.length;\\n uint256 strategyIndex = stratCount;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n if (allStrategies[i] == _addr) {\\n strategyIndex = i;\\n break;\\n }\\n }\\n\\n if (strategyIndex < stratCount) {\\n allStrategies[strategyIndex] = allStrategies[stratCount - 1];\\n allStrategies.pop();\\n\\n // Withdraw all assets BEFORE marking as unsupported so that AMO\\n // strategies can call burnForStrategy/mintForStrategy during withdrawAll\\n IStrategy strategy = IStrategy(_addr);\\n // slither-disable-next-line reentrancy-no-eth\\n strategy.withdrawAll();\\n\\n // Mark the strategy as not supported\\n strategies[_addr].isSupported = false;\\n isMintWhitelistedStrategy[_addr] = false;\\n\\n // 1e13 for 18 decimals. And 1e1(10) for 6 decimals\\n uint256 maxDustBalance = uint256(1e13).scaleBy(assetDecimals, 18);\\n\\n /*\\n * Some strategies are not able to withdraw all of their funds in a synchronous call.\\n * Prevent the possible accidental removal of such strategies before their funds are withdrawn.\\n */\\n require(\\n strategy.checkBalance(asset) < maxDustBalance,\\n \\\"Strategy has funds\\\"\\n );\\n emit StrategyRemoved(_addr);\\n }\\n }\\n\\n /**\\n * @notice Adds a strategy to the mint whitelist.\\n * Reverts if strategy isn't approved on Vault.\\n * @param strategyAddr Strategy address\\n */\\n function addStrategyToMintWhitelist(address strategyAddr)\\n external\\n onlyGovernor\\n {\\n require(strategies[strategyAddr].isSupported, \\\"Strategy not approved\\\");\\n\\n require(\\n !isMintWhitelistedStrategy[strategyAddr],\\n \\\"Already whitelisted\\\"\\n );\\n\\n isMintWhitelistedStrategy[strategyAddr] = true;\\n\\n emit StrategyAddedToMintWhitelist(strategyAddr);\\n }\\n\\n /**\\n * @notice Removes a strategy from the mint whitelist.\\n * @param strategyAddr Strategy address\\n */\\n function removeStrategyFromMintWhitelist(address strategyAddr)\\n external\\n onlyGovernor\\n {\\n // Intentionally skipping `strategies.isSupported` check since\\n // we may wanna remove an address even after removing the strategy\\n\\n require(isMintWhitelistedStrategy[strategyAddr], \\\"Not whitelisted\\\");\\n\\n isMintWhitelistedStrategy[strategyAddr] = false;\\n\\n emit StrategyRemovedFromMintWhitelist(strategyAddr);\\n }\\n\\n /***************************************\\n Strategies\\n ****************************************/\\n\\n /**\\n * @notice Deposit multiple asset from the vault into the strategy.\\n * @param _strategyToAddress Address of the Strategy to deposit asset into.\\n * @param _assets Array of asset address that will be deposited into the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to deposit.\\n */\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _depositToStrategy(_strategyToAddress, _assets, _amounts);\\n }\\n\\n function _depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyToAddress].isSupported,\\n \\\"Invalid to Strategy\\\"\\n );\\n require(\\n _assets.length == 1 && _amounts.length == 1 && _assets[0] == asset,\\n \\\"Only asset is supported\\\"\\n );\\n\\n // Check the there is enough asset to transfer once the backing\\n // asset reserved for the withdrawal queue is accounted for\\n require(\\n _amounts[0] <= _assetAvailable(),\\n \\\"Not enough assets available\\\"\\n );\\n\\n // Send required amount of funds to the strategy\\n IERC20(asset).safeTransfer(_strategyToAddress, _amounts[0]);\\n\\n // Deposit all the funds that have been sent to the strategy\\n IStrategy(_strategyToAddress).depositAll();\\n }\\n\\n /**\\n * @notice Withdraw multiple asset from the strategy to the vault.\\n * @param _strategyFromAddress Address of the Strategy to withdraw asset from.\\n * @param _assets Array of asset address that will be withdrawn from the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to withdraw.\\n */\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _withdrawFromStrategy(\\n address(this),\\n _strategyFromAddress,\\n _assets,\\n _amounts\\n );\\n }\\n\\n /**\\n * @param _recipient can either be a strategy or the Vault\\n */\\n function _withdrawFromStrategy(\\n address _recipient,\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyFromAddress].isSupported,\\n \\\"Invalid from Strategy\\\"\\n );\\n require(_assets.length == _amounts.length, \\\"Parameter length mismatch\\\");\\n\\n uint256 assetCount = _assets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n // Withdraw from Strategy to the recipient\\n IStrategy(_strategyFromAddress).withdraw(\\n _recipient,\\n _assets[i],\\n _amounts[i]\\n );\\n }\\n\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @notice Sets the maximum allowable difference between\\n * total supply and asset' value.\\n */\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\\n maxSupplyDiff = _maxSupplyDiff;\\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\\n }\\n\\n /**\\n * @notice Sets the trusteeAddress that can receive a portion of yield.\\n * Setting to the zero address disables this feature.\\n */\\n function setTrusteeAddress(address _address) external onlyGovernor {\\n trusteeAddress = _address;\\n emit TrusteeAddressChanged(_address);\\n }\\n\\n /**\\n * @notice Sets the TrusteeFeeBps to the percentage of yield that should be\\n * received in basis points.\\n */\\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\\n require(_basis <= 5000, \\\"basis cannot exceed 50%\\\");\\n trusteeFeeBps = _basis;\\n emit TrusteeFeeBpsChanged(_basis);\\n }\\n\\n /***************************************\\n Pause\\n ****************************************/\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent rebasing.\\n */\\n function pauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = true;\\n emit RebasePaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to allow rebasing.\\n */\\n function unpauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = false;\\n emit RebaseUnpaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent capital movement.\\n */\\n function pauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = true;\\n emit CapitalPaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to false to enable capital movement.\\n */\\n function unpauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = false;\\n emit CapitalUnpaused();\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\\n * contract, i.e. mistaken sends.\\n * @param _asset Address for the asset\\n * @param _amount Amount of the asset to transfer\\n */\\n function transferToken(address _asset, uint256 _amount)\\n external\\n onlyGovernor\\n {\\n require(asset != _asset, \\\"Only unsupported asset\\\");\\n IERC20(_asset).safeTransfer(governor(), _amount);\\n }\\n\\n /***************************************\\n Strategies Admin\\n ****************************************/\\n\\n /**\\n * @notice Withdraws all asset from the strategy and sends asset to the Vault.\\n * @param _strategyAddr Strategy address.\\n */\\n function withdrawAllFromStrategy(address _strategyAddr)\\n external\\n onlyGovernorOrStrategist\\n {\\n _withdrawAllFromStrategy(_strategyAddr);\\n }\\n\\n function _withdrawAllFromStrategy(address _strategyAddr) internal virtual {\\n require(\\n strategies[_strategyAddr].isSupported,\\n \\\"Strategy is not supported\\\"\\n );\\n IStrategy strategy = IStrategy(_strategyAddr);\\n strategy.withdrawAll();\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @notice Withdraws all asset from all the strategies and sends asset to the Vault.\\n */\\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\\n _withdrawAllFromStrategies();\\n }\\n\\n function _withdrawAllFromStrategies() internal virtual {\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy(allStrategies[i]).withdrawAll();\\n }\\n _addWithdrawalQueueLiquidity();\\n }\\n}\\n\",\"keccak256\":\"0xa9489d6c1c248bbf2d022d50dcc494f97f85b6d0fe40a13ab8516bd1ffda75ef\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultCore.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultCore contract\\n * @notice The Vault contract stores asset. On a deposit, OTokens will be minted\\n and sent to the depositor. On a withdrawal, OTokens will be burned and\\n asset will be sent to the withdrawer. The Vault accepts deposits of\\n interest from yield bearing strategies which will modify the supply\\n of OTokens.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\n\\nimport \\\"./VaultInitializer.sol\\\";\\n\\nabstract contract VaultCore is VaultInitializer {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n\\n /**\\n * @dev Verifies that the rebasing is not paused.\\n */\\n modifier whenNotRebasePaused() {\\n require(!rebasePaused, \\\"Rebasing paused\\\");\\n _;\\n }\\n\\n /**\\n * @dev Verifies that the deposits are not paused.\\n */\\n modifier whenNotCapitalPaused() {\\n require(!capitalPaused, \\\"Capital paused\\\");\\n _;\\n }\\n\\n constructor(address _asset) VaultInitializer(_asset) {}\\n\\n ////////////////////////////////////////////////////\\n /// MINT / BURN ///\\n ////////////////////////////////////////////////////\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @dev Deprecated: use `mint(uint256 _amount)` instead.\\n * @dev Deprecated: param _asset Address of the asset being deposited\\n * @param _amount Amount of the asset being deposited\\n * @dev Deprecated: param _minimumOusdAmount Minimum OTokens to mint\\n */\\n function mint(\\n address,\\n uint256 _amount,\\n uint256\\n ) external whenNotCapitalPaused nonReentrant {\\n _mint(_amount);\\n }\\n\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @param _amount Amount of the asset being deposited\\n */\\n function mint(uint256 _amount) external whenNotCapitalPaused nonReentrant {\\n _mint(_amount);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @dev Deposit a supported asset and mint OTokens.\\n * @param _amount Amount of the asset being deposited\\n */\\n function _mint(uint256 _amount) internal virtual {\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n\\n // Scale amount to 18 decimals\\n uint256 scaledAmount = _amount.scaleBy(18, assetDecimals);\\n\\n emit Mint(msg.sender, scaledAmount);\\n\\n // Mint oTokens\\n oToken.mint(msg.sender, scaledAmount);\\n\\n IERC20(asset).safeTransferFrom(msg.sender, address(this), _amount);\\n\\n // Give priority to the withdrawal queue for the new asset liquidity\\n _addWithdrawalQueueLiquidity();\\n\\n // Auto-allocate if necessary\\n if (scaledAmount >= autoAllocateThreshold) {\\n _allocate();\\n }\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /**\\n * @notice Mint OTokens for an allowed Strategy\\n * @param _amount Amount of OToken to mint\\n *\\n * Notice: can't use `nonReentrant` modifier since the `mint` function can\\n * call `allocate`, and that can trigger an AMO strategy to call this function\\n * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function mintForStrategy(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n {\\n require(\\n strategies[msg.sender].isSupported == true,\\n \\\"Unsupported strategy\\\"\\n );\\n require(\\n isMintWhitelistedStrategy[msg.sender] == true,\\n \\\"Not whitelisted strategy\\\"\\n );\\n\\n emit Mint(msg.sender, _amount);\\n // Mint matching amount of OTokens\\n oToken.mint(msg.sender, _amount);\\n }\\n\\n /**\\n * @notice Burn OTokens for an allowed Strategy\\n * @param _amount Amount of OToken to burn\\n *\\n * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could\\n * require withdrawal on an AMO strategy and that one can call `burnForStrategy`\\n * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function burnForStrategy(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n {\\n require(\\n strategies[msg.sender].isSupported == true,\\n \\\"Unsupported strategy\\\"\\n );\\n require(\\n isMintWhitelistedStrategy[msg.sender] == true,\\n \\\"Not whitelisted strategy\\\"\\n );\\n\\n emit Redeem(msg.sender, _amount);\\n\\n // Burn OTokens\\n oToken.burn(msg.sender, _amount);\\n }\\n\\n ////////////////////////////////////////////////////\\n /// ASYNC WITHDRAWALS ///\\n ////////////////////////////////////////////////////\\n /**\\n * @notice Request an asynchronous withdrawal of asset in exchange for OToken.\\n * The OToken is burned on request and the asset is transferred to the withdrawer on claim.\\n * This request can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal this request's `queued` amount.\\n * There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs\\n * enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue.\\n * OToken is converted to asset at 1:1.\\n * @param _amount Amount of OToken to burn.\\n * @return requestId Unique ID for the withdrawal request\\n * @return queued Cumulative total of all asset queued including already claimed requests.\\n */\\n function requestWithdrawal(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 requestId, uint256 queued)\\n {\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n require(withdrawalClaimDelay > 0, \\\"Async withdrawals not enabled\\\");\\n\\n // The check that the requester has enough OToken is done in to later burn call\\n\\n requestId = withdrawalQueueMetadata.nextWithdrawalIndex;\\n queued =\\n withdrawalQueueMetadata.queued +\\n _amount.scaleBy(assetDecimals, 18);\\n\\n // Store the next withdrawal request\\n withdrawalQueueMetadata.nextWithdrawalIndex = SafeCast.toUint128(\\n requestId + 1\\n );\\n // Store the updated queued amount which reserves asset in the withdrawal queue\\n // and reduces the vault's total asset\\n withdrawalQueueMetadata.queued = SafeCast.toUint128(queued);\\n // Store the user's withdrawal request\\n // `queued` is in asset decimals, while `amount` is in OToken decimals (18)\\n withdrawalRequests[requestId] = WithdrawalRequest({\\n withdrawer: msg.sender,\\n claimed: false,\\n timestamp: uint40(block.timestamp),\\n amount: SafeCast.toUint128(_amount),\\n queued: SafeCast.toUint128(queued)\\n });\\n\\n // Burn the user's OToken\\n oToken.burn(msg.sender, _amount);\\n\\n // Prevent withdrawal if the vault is solvent by more than the allowed percentage\\n _postRedeem();\\n\\n emit WithdrawalRequested(msg.sender, requestId, _amount, queued);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Claim a previously requested withdrawal once it is claimable.\\n * This request can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal this request's `queued` amount and 10 minutes has passed.\\n * If the requests is not claimable, the transaction will revert with `Queue pending liquidity`.\\n * If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`.\\n * OToken is converted to asset at 1:1.\\n * @param _requestId Unique ID for the withdrawal request\\n * @return amount Amount of asset transferred to the withdrawer\\n */\\n function claimWithdrawal(uint256 _requestId)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 amount)\\n {\\n // Try and get more liquidity if there is not enough available\\n if (\\n withdrawalRequests[_requestId].queued >\\n withdrawalQueueMetadata.claimable\\n ) {\\n // Add any asset to the withdrawal queue\\n // this needs to remain here as:\\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\\n // - funds can be withdrawn from a strategy\\n //\\n // Those funds need to be added to withdrawal queue liquidity\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n // Scale amount to asset decimals\\n amount = _claimWithdrawal(_requestId);\\n\\n // transfer asset from the vault to the withdrawer\\n IERC20(asset).safeTransfer(msg.sender, amount);\\n\\n // Prevent insolvency\\n _postRedeem();\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n /**\\n * @notice Claim a previously requested withdrawals once they are claimable.\\n * This requests can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal each request's `queued` amount and 10 minutes has passed.\\n * If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`.\\n * If one of the requests is not older than 10 minutes,\\n * the whole transaction will revert with `Claim delay not met`.\\n * @param _requestIds Unique ID of each withdrawal request\\n * @return amounts Amount of asset received for each request\\n * @return totalAmount Total amount of asset transferred to the withdrawer\\n */\\n function claimWithdrawals(uint256[] calldata _requestIds)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256[] memory amounts, uint256 totalAmount)\\n {\\n // Add any asset to the withdrawal queue\\n // this needs to remain here as:\\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\\n // - funds can be withdrawn from a strategy\\n //\\n // Those funds need to be added to withdrawal queue liquidity\\n _addWithdrawalQueueLiquidity();\\n\\n amounts = new uint256[](_requestIds.length);\\n for (uint256 i; i < _requestIds.length; ++i) {\\n // Scale all amounts to asset decimals, thus totalAmount is also in asset decimals\\n amounts[i] = _claimWithdrawal(_requestIds[i]);\\n totalAmount += amounts[i];\\n }\\n\\n // transfer all the claimed asset from the vault to the withdrawer\\n IERC20(asset).safeTransfer(msg.sender, totalAmount);\\n\\n // Prevent insolvency\\n _postRedeem();\\n\\n return (amounts, totalAmount);\\n }\\n\\n function _claimWithdrawal(uint256 requestId)\\n internal\\n returns (uint256 amount)\\n {\\n require(withdrawalClaimDelay > 0, \\\"Async withdrawals not enabled\\\");\\n\\n // Load the structs from storage into memory\\n WithdrawalRequest memory request = withdrawalRequests[requestId];\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n require(\\n request.timestamp + withdrawalClaimDelay <= block.timestamp,\\n \\\"Claim delay not met\\\"\\n );\\n // If there isn't enough reserved liquidity in the queue to claim\\n require(request.queued <= queue.claimable, \\\"Queue pending liquidity\\\");\\n require(request.withdrawer == msg.sender, \\\"Not requester\\\");\\n require(request.claimed == false, \\\"Already claimed\\\");\\n\\n // Store the request as claimed\\n withdrawalRequests[requestId].claimed = true;\\n // Store the updated claimed amount\\n withdrawalQueueMetadata.claimed =\\n queue.claimed +\\n SafeCast.toUint128(\\n StableMath.scaleBy(request.amount, assetDecimals, 18)\\n );\\n\\n emit WithdrawalClaimed(msg.sender, requestId, request.amount);\\n\\n return StableMath.scaleBy(request.amount, assetDecimals, 18);\\n }\\n\\n function _postRedeem() internal view {\\n // Until we can prove that we won't affect the prices of our asset\\n // by withdrawing them, this should be here.\\n // It's possible that a strategy was off on its asset total, perhaps\\n // a reward token sold for more or for less than anticipated.\\n uint256 totalUnits = _totalValue();\\n\\n // Check that the OTokens are backed by enough asset\\n if (maxSupplyDiff > 0) {\\n // If there are more outstanding withdrawal requests than asset in the vault and strategies\\n // then the available asset will be negative and totalUnits will be rounded up to zero.\\n // As we don't know the exact shortfall amount, we will reject all redeem and withdrawals\\n require(totalUnits > 0, \\\"Too many outstanding requests\\\");\\n\\n // Allow a max difference of maxSupplyDiff% between\\n // asset value and OUSD total supply\\n uint256 diff = oToken.totalSupply().divPrecisely(totalUnits);\\n require(\\n (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,\\n \\\"Backing supply liquidity error\\\"\\n );\\n }\\n }\\n\\n /**\\n * @notice Allocate unallocated funds on Vault to strategies.\\n */\\n function allocate() external virtual whenNotCapitalPaused nonReentrant {\\n // Add any unallocated asset to the withdrawal queue first\\n _addWithdrawalQueueLiquidity();\\n\\n _allocate();\\n }\\n\\n /**\\n * @dev Allocate asset (eg. WETH or USDC) to the default asset strategy\\n * if there is excess to the Vault buffer.\\n * This is called from either `mint` or `allocate` and assumes `_addWithdrawalQueueLiquidity`\\n * has been called before this function.\\n */\\n function _allocate() internal virtual {\\n // No need to do anything if no default strategy for asset\\n address depositStrategyAddr = defaultStrategy;\\n if (depositStrategyAddr == address(0)) return;\\n\\n uint256 assetAvailableInVault = _assetAvailable();\\n // No need to do anything if there isn't any asset in the vault to allocate\\n if (assetAvailableInVault == 0) return;\\n\\n // Calculate the target buffer for the vault using the total supply\\n uint256 totalSupply = oToken.totalSupply();\\n // Scaled to asset decimals\\n uint256 targetBuffer = totalSupply.mulTruncate(vaultBuffer).scaleBy(\\n assetDecimals,\\n 18\\n );\\n\\n // If available asset in the Vault is below or equal the target buffer then there's nothing to allocate\\n if (assetAvailableInVault <= targetBuffer) return;\\n\\n // The amount of asset to allocate to the default strategy\\n uint256 allocateAmount = assetAvailableInVault - targetBuffer;\\n\\n IStrategy strategy = IStrategy(depositStrategyAddr);\\n // Transfer asset to the strategy and call the strategy's deposit function\\n IERC20(asset).safeTransfer(address(strategy), allocateAmount);\\n strategy.deposit(asset, allocateAmount);\\n\\n emit AssetAllocated(asset, depositStrategyAddr, allocateAmount);\\n }\\n\\n /**\\n * @notice Calculate the total value of asset held by the Vault and all\\n * strategies and update the supply of OTokens.\\n * @dev Restricted to the Operator, Strategist or Governor.\\n */\\n function rebase() external virtual nonReentrant {\\n require(\\n msg.sender == operatorAddr ||\\n msg.sender == strategistAddr ||\\n isGovernor(),\\n \\\"Caller not authorized\\\"\\n );\\n _rebase();\\n }\\n\\n /**\\n * @dev Calculate the total value of asset held by the Vault and all\\n * strategies and update the supply of OTokens, optionally sending a\\n * portion of the yield to the trustee.\\n * @return totalUnits Total balance of Vault in units\\n */\\n function _rebase() internal whenNotRebasePaused returns (uint256) {\\n uint256 supply = oToken.totalSupply();\\n uint256 vaultValue = _totalValue();\\n // If no supply yet, do not rebase\\n if (supply == 0) {\\n return vaultValue;\\n }\\n\\n // Calculate yield and new supply\\n (uint256 yield, uint256 targetRate) = _nextYield(supply, vaultValue);\\n uint256 newSupply = supply + yield;\\n // Only rebase upwards and if we have enough backing funds\\n if (newSupply <= supply || newSupply > vaultValue) {\\n return vaultValue;\\n }\\n\\n rebasePerSecondTarget = uint64(_min(targetRate, type(uint64).max));\\n lastRebase = uint64(block.timestamp); // Intentional cast\\n\\n // Fee collection on yield\\n address _trusteeAddress = trusteeAddress; // gas savings\\n uint256 fee = 0;\\n if (_trusteeAddress != address(0)) {\\n fee = (yield * trusteeFeeBps) / 1e4;\\n if (fee > 0) {\\n require(fee < yield, \\\"Fee must not be greater than yield\\\");\\n oToken.mint(_trusteeAddress, fee);\\n }\\n }\\n emit YieldDistribution(_trusteeAddress, yield, fee);\\n\\n // Only ratchet OToken supply upwards\\n // Final check uses latest totalSupply\\n if (newSupply > oToken.totalSupply()) {\\n oToken.changeSupply(newSupply);\\n }\\n return vaultValue;\\n }\\n\\n /**\\n * @notice Calculates the amount that would rebase at next rebase.\\n * This is before any fees.\\n * @return yield amount of expected yield\\n */\\n function previewYield() external view returns (uint256 yield) {\\n (yield, ) = _nextYield(oToken.totalSupply(), _totalValue());\\n return yield;\\n }\\n\\n /**\\n * @dev Calculates the amount that would rebase at next rebase.\\n * See this Readme for detailed explanation:\\n * contracts/contracts/vault/README - Yield Limits.md\\n */\\n function _nextYield(uint256 supply, uint256 vaultValue)\\n internal\\n view\\n virtual\\n returns (uint256 yield, uint256 targetRate)\\n {\\n uint256 nonRebasing = oToken.nonRebasingSupply();\\n uint256 rebasing = supply - nonRebasing;\\n uint256 elapsed = block.timestamp - lastRebase;\\n targetRate = rebasePerSecondTarget;\\n\\n if (\\n elapsed == 0 || // Yield only once per block.\\n rebasing == 0 || // No yield if there are no rebasing tokens to give it to.\\n supply > vaultValue || // No yield if we do not have yield to give.\\n block.timestamp >= type(uint64).max // No yield if we are too far in the future to calculate it correctly.\\n ) {\\n return (0, targetRate);\\n }\\n\\n // Start with the full difference available\\n yield = vaultValue - supply;\\n\\n // Cap via optional automatic duration smoothing\\n uint256 _dripDuration = dripDuration;\\n if (_dripDuration > 1) {\\n // If we are able to sustain an increased drip rate for\\n // double the duration, then increase the target drip rate\\n targetRate = _max(targetRate, yield / (_dripDuration * 2));\\n // If we cannot sustain the target rate any more,\\n // then rebase what we can, and reduce the target\\n targetRate = _min(targetRate, yield / _dripDuration);\\n // drip at the new target rate\\n yield = _min(yield, targetRate * elapsed);\\n }\\n\\n // Cap per second. elapsed is not 1e18 denominated\\n yield = _min(yield, (rebasing * elapsed * rebasePerSecondMax) / 1e18);\\n\\n // Cap at a hard max per rebase, to avoid long durations resulting in huge rebases\\n yield = _min(yield, (rebasing * MAX_REBASE) / 1e18);\\n\\n return (yield, targetRate);\\n }\\n\\n /**\\n * @notice Determine the total value of asset held by the vault and its\\n * strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function totalValue() external view virtual returns (uint256 value) {\\n value = _totalValue();\\n }\\n\\n /**\\n * @dev Internal Calculate the total value of the asset held by the\\n * vault and its strategies.\\n * @dev The total value of all WETH held by the vault and all its strategies\\n * less any WETH that is reserved for the withdrawal queue.\\n * If there is not enough WETH in the vault and all strategies to cover\\n * all outstanding withdrawal requests then return a total value of 0.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValue() internal view virtual returns (uint256 value) {\\n // As asset is the only asset, just return the asset balance\\n value = _checkBalance(asset).scaleBy(18, assetDecimals);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @param _asset Address of asset\\n * @return uint256 Balance of asset in decimals of asset\\n */\\n function checkBalance(address _asset) external view returns (uint256) {\\n return _checkBalance(_asset);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @dev Get the balance of an asset held in Vault and all strategies\\n * less any asset that is reserved for the withdrawal queue.\\n * BaseAsset is the only asset that can return a non-zero balance.\\n * All other asset will return 0 even if there is some dust amounts left in the Vault.\\n * For example, there is 1 wei left of stETH (or USDC) in the OETH (or OUSD) Vault but\\n * will return 0 in this function.\\n *\\n * If there is not enough asset in the vault and all strategies to cover all outstanding\\n * withdrawal requests then return a asset balance of 0\\n * @param _asset Address of asset\\n * @return balance Balance of asset in decimals of asset\\n */\\n function _checkBalance(address _asset)\\n internal\\n view\\n virtual\\n returns (uint256 balance)\\n {\\n if (_asset != asset) return 0;\\n\\n // Get the asset in the vault and the strategies\\n IERC20 asset = IERC20(_asset);\\n balance = asset.balanceOf(address(this));\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy strategy = IStrategy(allStrategies[i]);\\n if (strategy.supportsAsset(_asset)) {\\n balance = balance + strategy.checkBalance(_asset);\\n }\\n }\\n\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // If the vault becomes insolvent enough that the total value in the vault and all strategies\\n // is less than the outstanding withdrawals.\\n // For example, there was a mass slashing event and most users request a withdrawal.\\n if (balance + queue.claimed < queue.queued) {\\n return 0;\\n }\\n\\n // Need to remove asset that is reserved for the withdrawal queue\\n return balance + queue.claimed - queue.queued;\\n }\\n\\n /**\\n * @notice Adds WETH to the withdrawal queue if there is a funding shortfall.\\n * @dev is called from the Native Staking strategy when validator withdrawals are processed.\\n * It also called before any WETH is allocated to a strategy.\\n */\\n function addWithdrawalQueueLiquidity() external {\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @dev Adds asset (eg. WETH or USDC) to the withdrawal queue if there is a funding shortfall.\\n * This assumes 1 asset equal 1 corresponding OToken.\\n */\\n function _addWithdrawalQueueLiquidity()\\n internal\\n returns (uint256 addedClaimable)\\n {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // Check if the claimable asset is less than the queued amount\\n uint256 queueShortfall = queue.queued - queue.claimable;\\n\\n // No need to do anything is the withdrawal queue is full funded\\n if (queueShortfall == 0) {\\n return 0;\\n }\\n\\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\\n\\n // Of the claimable withdrawal requests, how much is unclaimed?\\n // That is, the amount of asset that is currently allocated for the withdrawal queue\\n uint256 allocatedBaseAsset = queue.claimable - queue.claimed;\\n\\n // If there is no unallocated asset then there is nothing to add to the queue\\n if (assetBalance <= allocatedBaseAsset) {\\n return 0;\\n }\\n\\n uint256 unallocatedBaseAsset = assetBalance - allocatedBaseAsset;\\n // the new claimable amount is the smaller of the queue shortfall or unallocated asset\\n addedClaimable = queueShortfall < unallocatedBaseAsset\\n ? queueShortfall\\n : unallocatedBaseAsset;\\n uint256 newClaimable = queue.claimable + addedClaimable;\\n\\n // Store the new claimable amount back to storage\\n withdrawalQueueMetadata.claimable = SafeCast.toUint128(newClaimable);\\n\\n // emit a WithdrawalClaimable event\\n emit WithdrawalClaimable(newClaimable, addedClaimable);\\n }\\n\\n /**\\n * @dev Calculate how much asset (eg. WETH or USDC) in the vault is not reserved for the withdrawal queue.\\n * That is, it is available to be redeemed or deposited into a strategy.\\n */\\n function _assetAvailable() internal view returns (uint256 assetAvailable) {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // The amount of asset that is still to be claimed in the withdrawal queue\\n uint256 outstandingWithdrawals = queue.queued - queue.claimed;\\n\\n // The amount of sitting in asset in the vault\\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\\n // If there is not enough asset in the vault to cover the outstanding withdrawals\\n if (assetBalance <= outstandingWithdrawals) return 0;\\n\\n return assetBalance - outstandingWithdrawals;\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Return the number of asset supported by the Vault.\\n */\\n function getAssetCount() public view returns (uint256) {\\n return 1;\\n }\\n\\n /**\\n * @notice Return all vault asset addresses in order\\n */\\n function getAllAssets() external view returns (address[] memory) {\\n address[] memory a = new address[](1);\\n a[0] = asset;\\n return a;\\n }\\n\\n /**\\n * @notice Return the number of strategies active on the Vault.\\n */\\n function getStrategyCount() external view returns (uint256) {\\n return allStrategies.length;\\n }\\n\\n /**\\n * @notice Return the array of all strategies\\n */\\n function getAllStrategies() external view returns (address[] memory) {\\n return allStrategies;\\n }\\n\\n /**\\n * @notice Returns whether the vault supports the asset\\n * @param _asset address of the asset\\n * @return true if supported\\n */\\n function isSupportedAsset(address _asset) external view returns (bool) {\\n return asset == _asset;\\n }\\n\\n function _min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n function _max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a > b ? a : b;\\n }\\n}\\n\",\"keccak256\":\"0xc2080a50088fc275eddea5784cef6a561280918679c846de48a8983613acf56e\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultInitializer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultInitializer contract\\n * @notice The Vault contract initializes the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport \\\"./VaultStorage.sol\\\";\\n\\nabstract contract VaultInitializer is VaultStorage {\\n constructor(address _asset) VaultStorage(_asset) {}\\n\\n function initialize(address _oToken) external onlyGovernor initializer {\\n require(_oToken != address(0), \\\"oToken address is zero\\\");\\n\\n oToken = OUSD(_oToken);\\n\\n rebasePaused = false;\\n capitalPaused = true;\\n\\n // Initial Vault buffer of 0%\\n vaultBuffer = 0;\\n // Initial allocate threshold of 25,000 OUSD\\n autoAllocateThreshold = 25000e18;\\n // Initialize all strategies\\n allStrategies = new address[](0);\\n // Start with drip duration: 7 days\\n dripDuration = 604800;\\n }\\n}\\n\",\"keccak256\":\"0x5198442b36146a9c1c1f38294866f4b3a12344ccf67dd9dd2e3958243bbd9c98\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultStorage.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultStorage contract\\n * @notice The VaultStorage contract defines the storage for the Vault contracts\\n * @author Origin Protocol Inc\\n */\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { IERC20Metadata } from \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { OUSD } from \\\"../token/OUSD.sol\\\";\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport \\\"../utils/Helpers.sol\\\";\\n\\nabstract contract VaultStorage is Initializable, Governable {\\n using SafeERC20 for IERC20;\\n\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event DefaultStrategyUpdated(address _strategy);\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\\n event DripDurationChanged(uint256 dripDuration);\\n event OperatorUpdated(address newOperator);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\\n\\n // Since we are proxy, all state should be uninitalized.\\n // Since this storage contract does not have logic directly on it\\n // we should not be checking for to see if these variables can be constant.\\n // slither-disable-start uninitialized-state\\n // slither-disable-start constable-states\\n\\n /// @dev mapping of supported vault assets to their configuration\\n uint256 private _deprecated_assets;\\n /// @dev list of all assets supported by the vault.\\n address[] private _deprecated_allAssets;\\n\\n // Strategies approved for use by the Vault\\n struct Strategy {\\n bool isSupported;\\n uint256 _deprecated; // Deprecated storage slot\\n }\\n /// @dev mapping of strategy contracts to their configuration\\n mapping(address => Strategy) public strategies;\\n /// @dev list of all vault strategies\\n address[] internal allStrategies;\\n\\n /// @notice Address of the Oracle price provider contract\\n address private _deprecated_priceProvider;\\n /// @notice pause rebasing if true\\n bool public rebasePaused;\\n /// @notice pause operations that change the OToken supply.\\n /// eg mint, redeem, allocate, mint/burn for strategy\\n bool public capitalPaused;\\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\\n uint256 private _deprecated_redeemFeeBps;\\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\\n uint256 public vaultBuffer;\\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\\n uint256 public autoAllocateThreshold;\\n /// @dev Deprecated. Was the auto-rebase trigger threshold for mint/redeem.\\n /// Storage slot retained for proxy compatibility; no longer read or written.\\n uint256 internal __deprecatedRebaseThreshold;\\n\\n /// @dev Address of the OToken token. eg OUSD or OETH.\\n OUSD public oToken;\\n\\n /// @dev Address of the contract responsible for post rebase syncs with AMMs\\n address private _deprecated_rebaseHooksAddr = address(0);\\n\\n /// @dev Deprecated: Address of Uniswap\\n address private _deprecated_uniswapAddr = address(0);\\n\\n /// @notice Address of the Strategist\\n address public strategistAddr = address(0);\\n\\n /// @notice Mapping of asset address to the Strategy that they should automatically\\n // be allocated to\\n uint256 private _deprecated_assetDefaultStrategies;\\n\\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\\n uint256 public maxSupplyDiff;\\n\\n /// @notice Trustee contract that can collect a percentage of yield\\n address public trusteeAddress;\\n\\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\\n uint256 public trusteeFeeBps;\\n\\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\\n address[] private _deprecated_swapTokens;\\n\\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\\n\\n address private _deprecated_ousdMetaStrategy;\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n int256 private _deprecated_netOusdMintedForStrategy;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n uint256 private _deprecated_netOusdMintForStrategyThreshold;\\n\\n uint256 private _deprecated_swapConfig;\\n\\n // List of strategies that can mint oTokens directly\\n // Used in OETHBaseVaultCore\\n mapping(address => bool) public isMintWhitelistedStrategy;\\n\\n /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\\n /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\\n address private _deprecated_dripper;\\n\\n /// Withdrawal Queue Storage /////\\n\\n struct WithdrawalQueueMetadata {\\n // cumulative total of all withdrawal requests included the ones that have already been claimed\\n uint128 queued;\\n // cumulative total of all the requests that can be claimed including the ones that have already been claimed\\n uint128 claimable;\\n // total of all the requests that have been claimed\\n uint128 claimed;\\n // index of the next withdrawal request starting at 0\\n uint128 nextWithdrawalIndex;\\n }\\n\\n /// @notice Global metadata for the withdrawal queue including:\\n /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed\\n /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed\\n /// claimed - total of all the requests that have been claimed\\n /// nextWithdrawalIndex - index of the next withdrawal request starting at 0\\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\\n\\n struct WithdrawalRequest {\\n address withdrawer;\\n bool claimed;\\n uint40 timestamp; // timestamp of the withdrawal request\\n // Amount of oTokens to redeem. eg OETH\\n uint128 amount;\\n // cumulative total of all withdrawal requests including this one.\\n // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\\n uint128 queued;\\n }\\n\\n /// @notice Mapping of withdrawal request indices to the user withdrawal request data\\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\\n\\n /// @notice Sets a minimum delay that is required to elapse between\\n /// requesting async withdrawals and claiming the request.\\n /// When set to 0 async withdrawals are disabled.\\n uint256 public withdrawalClaimDelay;\\n\\n /// @notice Time in seconds that the vault last rebased yield.\\n uint64 public lastRebase;\\n\\n /// @notice Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\\n uint64 public dripDuration;\\n\\n /// @notice max rebase percentage per second\\n /// Can be used to set maximum yield of the protocol,\\n /// spreading out yield over time\\n uint64 public rebasePerSecondMax;\\n\\n /// @notice target rebase rate limit, based on past rates and funds available.\\n uint64 public rebasePerSecondTarget;\\n\\n uint256 internal constant MAX_REBASE = 0.02 ether;\\n uint256 internal constant MAX_REBASE_PER_SECOND =\\n uint256(0.05 ether) / 1 days;\\n\\n /// @notice Default strategy for asset\\n address public defaultStrategy;\\n\\n /// @notice Address authorized to call `rebase()` directly. The Governor\\n /// and Strategist are always allowed in addition to this address.\\n address public operatorAddr;\\n\\n // For future use\\n uint256[41] private __gap;\\n\\n /// @notice Index of WETH asset in allAssets array\\n /// Legacy OETHVaultCore code, relocated here for vault consistency.\\n uint256 private _deprecated_wethAssetIndex;\\n\\n /// @dev Address of the asset (eg. WETH or USDC)\\n address public immutable asset;\\n uint8 internal immutable assetDecimals;\\n\\n // slither-disable-end constable-states\\n // slither-disable-end uninitialized-state\\n\\n constructor(address _asset) {\\n uint8 _decimals = IERC20Metadata(_asset).decimals();\\n require(_decimals <= 18, \\\"invalid asset decimals\\\");\\n asset = _asset;\\n assetDecimals = _decimals;\\n }\\n\\n /// @notice Deprecated: use `oToken()` instead.\\n function oUSD() external view returns (OUSD) {\\n return oToken;\\n }\\n}\\n\",\"keccak256\":\"0x9245e680c777afc86fc97e0101940bd0d702b206e49b940c42c574be92860e4f\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x60c0604052603d80546001600160a01b0319908116909155603e805482169055603f8054909116905534801561003457600080fd5b5060405161541938038061541983398101604081905261005391610133565b808080806000816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100bb9190610163565b905060128160ff1611156101155760405162461bcd60e51b815260206004820152601660248201527f696e76616c696420617373657420646563696d616c7300000000000000000000604482015260640160405180910390fd5b6001600160a01b0390911660805260ff1660a0525061018692505050565b60006020828403121561014557600080fd5b81516001600160a01b038116811461015c57600080fd5b9392505050565b60006020828403121561017557600080fd5b815160ff8116811461015c57600080fd5b60805160a0516151c661025360003960008181610fbb015281816120ac0152818161319201528181613773015281816138170152818161408f01526144440152600081816105870152818161088b01528181610c5801528181610ff9015281816112e80152818161144d0152818161176c0152818161187a01528181612ca1015281816132630152818161339101528181613ae601528181613dbb01528181613ef2015281816140fa01528181614145015281816141ad0152818161446b01526148a601526151c66000f3fe608060405234801561001057600080fd5b50600436106104075760003560e01c8063663e64ce11610220578063ae69f3cb11610130578063c7af3352116100b8578063e6cc543211610087578063e6cc5432146109e5578063ea33b8e4146109f9578063f3f18c3714610a01578063f844443614610a14578063fac5bb9b14610a2757600080fd5b8063c7af3352146109ba578063c9919112146109c2578063d38bfff4146109ca578063d4c3eea0146109dd57600080fd5b8063b9b17f9f116100ff578063b9b17f9f14610975578063bb7a632e1461097d578063c3b2886414610997578063c4d66de81461099f578063c5f00841146109b257600080fd5b8063ae69f3cb14610934578063af14052c14610947578063b2c9336d1461094f578063b4925a201461096257600080fd5b806395b166bc116101b35780639fa1826e116101825780639fa1826e146108f6578063a0712d68146108ff578063a0aead4d14610912578063ab80dafb14610919578063abaa99161461092c57600080fd5b806395b166bc146108685780639be918e61461087b5780639e428552146108bb5780639ee679e8146108ce57600080fd5b80638e510b52116101ef5780638e510b521461079c5780638ec489a2146107a5578063937b2581146107b857806394828ffd1461086057600080fd5b8063663e64ce14610750578063773540b31461076357806378f353a114610776578063840c4c7a1461078957600080fd5b806339ebf8231161031b578063527e83a8116102ae5780635802a1721161027d5780635802a172146106fe578063597c89101461070f5780635d36b190146107225780635f5152261461072a5780636217f3ea1461073d57600080fd5b8063527e83a8146106aa57806353ca9f24146106c4578063570d8e1d146106d857806357bee944146106eb57600080fd5b806345e4213b116102ea57806345e4213b1461063b57806348e30f541461064457806349c1d54d146106655780634d5f46291461067857600080fd5b806339ebf823146105a95780633b8ae397146105ed5780633dbc911f146106005780634530820a1461060857600080fd5b80631a32aad61161039e5780632acada4d1161036d5780632acada4d146104f35780632da845a81461050857806331e19cfa1461051b578063362bd1a31461052357806338d52e0f1461058257600080fd5b80631a32aad6146104ad5780631cfbe7bc146104c05780631edfe3da146104d3578063207134b0146104ea57600080fd5b80631072cbea116103da5780631072cbea14610461578063156e29f614610474578063175188e8146104875780631816dd4a1461049a57600080fd5b80630493a0fa1461040c57806309f49bf5146104215780630acbda75146104295780630c340a241461043c575b600080fd5b61041f61041a366004614b54565b610a3a565b005b61041f610af0565b61041f610437366004614b54565b610b60565b610444610c0b565b6040516001600160a01b0390911681526020015b60405180910390f35b61041f61046f366004614b89565b610c28565b61041f610482366004614bb3565b610ce6565b61041f610495366004614be6565b610d59565b61041f6104a8366004614be6565b6110f7565b603c54610444906001600160a01b031681565b61041f6104ce366004614b54565b6111fe565b6104dc60395481565b604051908152602001610458565b6104dc60435481565b6104fb6112c0565b6040516104589190614c01565b61041f610516366004614be6565b611337565b6036546104dc565b604b54604c5461054f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610458565b6104447f000000000000000000000000000000000000000000000000000000000000000081565b6105d66105b7366004614be6565b6035602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610458565b61041f6105fb366004614be6565b6113a9565b61041f6115bc565b61062b610616366004614be6565b60496020526000908152604090205460ff1681565b6040519015158152602001610458565b6104dc604e5481565b610657610652366004614c91565b611632565b604051610458929190614cd2565b604254610444906001600160a01b031681565b604f5461069290600160c01b90046001600160401b031681565b6040516001600160401b039091168152602001610458565b604f5461069290600160801b90046001600160401b031681565b60375461062b90600160a01b900460ff1681565b603f54610444906001600160a01b031681565b61041f6106f9366004614be6565b6117a8565b603c546001600160a01b0316610444565b61041f61071d366004614be6565b61195b565b61041f61199f565b6104dc610738366004614be6565b611a45565b61041f61074b366004614b54565b611a56565b61041f61075e366004614b54565b611bda565b61041f610771366004614be6565b611c33565b604f54610692906001600160401b031681565b61041f610797366004614d1f565b611ca5565b6104dc60415481565b61041f6107b3366004614b54565b611d2c565b6108196107c6366004614b54565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a001610458565b61041f611de1565b61041f610876366004614be6565b611e51565b61062b610889366004614be6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b61041f6108c9366004614be6565b611f18565b6108e16108dc366004614b54565b611f8a565b60408051928352602083019190915201610458565b6104dc603a5481565b61041f61090d366004614b54565b6122ca565b60016104dc565b61041f610927366004614b54565b61233b565b61041f61248a565b61041f610942366004614d1f565b612502565b61041f61257e565b61041f61095d366004614b54565b612639565b61041f610970366004614b54565b612692565b61041f6127b0565b604f5461069290600160401b90046001600160401b031681565b6104fb6127b8565b61041f6109ad366004614be6565b61281a565b61041f6129c5565b61062b612a3b565b61041f612a6c565b61041f6109d8366004614be6565b612aac565b6104dc612b50565b60375461062b90600160a81b900460ff1681565b6104dc612b5a565b605154610444906001600160a01b031681565b6104dc610a22366004614b54565b612be9565b605054610444906001600160a01b031681565b603f546001600160a01b0316331480610a565750610a56612a3b565b610a7b5760405162461bcd60e51b8152600401610a7290614da3565b60405180910390fd5b610a83612cda565b50610a8d81613074565b604f80546001600160401b0392909216600160401b0267ffffffffffffffff60401b199092169190911790556040518181527f406e15fbca1d8ded2dbb06765fea3a54f18395c54125a4c9916dd00ea14ee15e906020015b60405180910390a150565b603f546001600160a01b0316331480610b0c5750610b0c612a3b565b610b285760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b610b68612a3b565b610b845760405162461bcd60e51b8152600401610a7290614deb565b611388811115610bd65760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f7420657863656564203530250000000000000000006044820152606401610a72565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c790602001610ae5565b6000610c236000805160206151718339815191525490565b905090565b610c30612a3b565b610c4c5760405162461bcd60e51b8152600401610a7290614deb565b816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610cc65760405162461bcd60e51b815260206004820152601660248201527513db9b1e481d5b9cdd5c1c1bdc9d195908185cdcd95d60521b6044820152606401610a72565b610ce2610cd1610c0b565b6001600160a01b03841690836130e0565b5050565b603754600160a81b900460ff1615610d105760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101610d425760405162461bcd60e51b8152600401610a7290614e4a565b60028255610d4f84613136565b5060019055505050565b610d61612a3b565b610d7d5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff16610db55760405162461bcd60e51b8152600401610a7290614e72565b6050546001600160a01b03808316911603610e125760405162461bcd60e51b815260206004820152601d60248201527f53747261746567792069732064656661756c7420666f722061737365740000006044820152606401610a72565b6036548060005b82811015610e6857836001600160a01b031660368281548110610e3e57610e3e614ea1565b6000918252602090912001546001600160a01b031603610e6057809150610e68565b600101610e19565b50818110156110f2576036610e7e600184614ecd565b81548110610e8e57610e8e614ea1565b600091825260209091200154603680546001600160a01b039092169183908110610eba57610eba614ea1565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610ef957610ef9614ee0565b6001900381819060005260206000200160006101000a8154906001600160a01b03021916905590556000839050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610f6157600080fd5b505af1158015610f75573d6000803e3d6000fd5b505050506001600160a01b0384166000908152603560209081526040808320805460ff199081169091556049909252822080549091169055610fe26509184e72a00060ff7f00000000000000000000000000000000000000000000000000000000000000001660126132a7565b604051632fa8a91360e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192508291841690635f51522690602401602060405180830381865afa15801561104d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110719190614ef6565b106110b35760405162461bcd60e51b81526020600482015260126024820152715374726174656779206861732066756e647360701b6044820152606401610a72565b6040516001600160a01b03861681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49060200160405180910390a150505b505050565b6110ff612a3b565b61111b5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff166111535760405162461bcd60e51b8152600401610a7290614e72565b6001600160a01b03811660009081526049602052604090205460ff16156111b25760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481dda1a5d195b1a5cdd1959606a1b6044820152606401610a72565b6001600160a01b038116600081815260496020526040808220805460ff19166001179055517f47c8c96a5942f094264111c5fe7f6a4fe86efe63254a6fa7afa5fc84f07d58e89190a250565b611206612a3b565b6112225760405162461bcd60e51b8152600401610a7290614deb565b80158061123f5750610258811015801561123f57506213c6808111155b61128b5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636c61696d2064656c617920706572696f640000000000006044820152606401610a72565b604e8190556040518181527fc59f5e32049abab44ddea11021f5abb89422a2f550837afcf25df9fc8d0db6b090602001610ae5565b60408051600180825281830190925260609160009190602080830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061131a5761131a614ea1565b6001600160a01b0390921660209283029190910190910152919050565b61133f612a3b565b61135b5760405162461bcd60e51b8152600401610a7290614deb565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610ae5565b6113b1612a3b565b6113cd5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff16156114365760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f766564000000000000006044820152606401610a72565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa15801561149c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c09190614f25565b61150c5760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a72565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610ae5565b603f546001600160a01b03163314806115d857506115d8612a3b565b6115f45760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b603754606090600090600160a81b900460ff16156116625760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016116945760405162461bcd60e51b8152600401610a7290614e4a565b600282556116a061330b565b50846001600160401b038111156116b9576116b9614f0f565b6040519080825280602002602001820160405280156116e2578160200160208202803683370190505b50935060005b8581101561175e5761171187878381811061170557611705614ea1565b905060200201356134e7565b85828151811061172357611723614ea1565b60200260200101818152505084818151811061174157611741614ea1565b6020026020010151846117549190614f47565b93506001016116e8565b506117936001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130e0565b61179b613848565b6001825550509250929050565b603f546001600160a01b03163314806117c457506117c4612a3b565b6117e05760405162461bcd60e51b8152600401610a7290614da3565b6040516001600160a01b03821681527f45a9e715f8779ebeab88d3e8d081fb8b484b7730857e7c4478a95a5b1d8f79489060200160405180910390a16001600160a01b03811615611939576001600160a01b03811660009081526035602052604090205460ff166118635760405162461bcd60e51b8152600401610a7290614e72565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa1580156118c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ed9190614f25565b6119395760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a72565b605080546001600160a01b0319166001600160a01b0392909216919091179055565b603f546001600160a01b03163314806119775750611977612a3b565b6119935760405162461bcd60e51b8152600401610a7290614da3565b61199c816139bb565b50565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614611a3a5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610a72565b611a4333613a83565b565b6000611a5082613ae2565b92915050565b603754600160a81b900460ff1615611a805760405162461bcd60e51b8152600401610a7290614e22565b3360009081526035602052604090205460ff161515600114611adb5760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a72565b3360009081526049602052604090205460ff161515600114611b3a5760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a72565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051611b6b929190614f5a565b60405180910390a1603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90611ba59033908590600401614f5a565b600060405180830381600087803b158015611bbf57600080fd5b505af1158015611bd3573d6000803e3d6000fd5b5050505050565b611be2612a3b565b611bfe5760405162461bcd60e51b8152600401610a7290614deb565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610ae5565b611c3b612a3b565b611c575760405162461bcd60e51b8152600401610a7290614deb565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610ae5565b603f546001600160a01b0316331480611cc15750611cc1612a3b565b611cdd5760405162461bcd60e51b8152600401610a7290614da3565b60008051602061515183398151915280546001198101611d0f5760405162461bcd60e51b8152600401610a7290614e4a565b60028255611d208787878787613d44565b50600190555050505050565b603f546001600160a01b0316331480611d485750611d48612a3b565b611d645760405162461bcd60e51b8152600401610a7290614da3565b670de0b6b3a7640000811115611dac5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b6044820152606401610a72565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610ae5565b603f546001600160a01b0316331480611dfd5750611dfd612a3b565b611e195760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e59612a3b565b611e755760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526049602052604090205460ff16611ecf5760405162461bcd60e51b815260206004820152600f60248201526e139bdd081dda1a5d195b1a5cdd1959608a1b6044820152606401610a72565b6001600160a01b038116600081815260496020526040808220805460ff19169055517f0ec40967a61509853550658e51d0e4297f7cba244fe4adc8ba18b5631ac20e2f9190a250565b611f20612a3b565b611f3c5760405162461bcd60e51b8152600401610a7290614deb565b605180546001600160a01b0319166001600160a01b0383169081179091556040519081527fb3b3f5f64ab192e4b5fefde1f51ce9733bbdcf831951543b325aebd49cc27ec490602001610ae5565b6037546000908190600160a81b900460ff1615611fb95760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101611feb5760405162461bcd60e51b8152600401610a7290614e4a565b600282556000851161203f5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a72565b6000604e54116120915760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a72565b604c54600160801b90046001600160801b031693506120d5857f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b604b546120eb91906001600160801b0316614f47565b92506121006120fb856001614f47565b613f83565b604c80546001600160801b03928316600160801b02921691909117905561212683613f83565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff16918101919091526060810161217687613f83565b6001600160801b0316815260200161218d85613f83565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906122489033908990600401614f5a565b600060405180830381600087803b15801561226257600080fd5b505af1158015612276573d6000803e3d6000fd5b50505050612282613848565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff16156122f45760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016123265760405162461bcd60e51b8152600401610a7290614e4a565b6002825561233383613136565b506001905550565b603754600160a81b900460ff16156123655760405162461bcd60e51b8152600401610a7290614e22565b3360009081526035602052604090205460ff1615156001146123c05760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a72565b3360009081526049602052604090205460ff16151560011461241f5760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a72565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853382604051612450929190614f5a565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611ba59033908590600401614f5a565b603754600160a81b900460ff16156124b45760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016124e65760405162461bcd60e51b8152600401610a7290614e4a565b600282556124f261330b565b506124fb613fec565b5060019055565b603f546001600160a01b031633148061251e575061251e612a3b565b61253a5760405162461bcd60e51b8152600401610a7290614da3565b6000805160206151518339815191528054600119810161256c5760405162461bcd60e51b8152600401610a7290614e4a565b60028255611d20308888888888614215565b600080516020615151833981519152805460011981016125b05760405162461bcd60e51b8152600401610a7290614e4a565b600282556051546001600160a01b03163314806125d75750603f546001600160a01b031633145b806125e557506125e5612a3b565b6126295760405162461bcd60e51b815260206004820152601560248201527410d85b1b195c881b9bdd08185d5d1a1bdc9a5e9959605a1b6044820152606401610a72565b612631612cda565b505060019055565b612641612a3b565b61265d5760405162461bcd60e51b8152600401610a7290614deb565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610ae5565b603f546001600160a01b03163314806126ae57506126ae612a3b565b6126ca5760405162461bcd60e51b8152600401610a7290614da3565b6126d2612cda565b5060006301e133806126e5606484614f73565b6126ef9190614f73565b90506127056201518066b1a2bc2ec50000614f73565b8111156127445760405162461bcd60e51b815260206004820152600d60248201526c0a4c2e8ca40e8dede40d0d2ced609b1b6044820152606401610a72565b61274d81613074565b604f80546001600160401b0392909216600160801b0267ffffffffffffffff60801b199092169190911790556040518181527fef46f143af5fead0010484fe7d6ec2e2972420faa76157f5a6075aa72e614cb59060200160405180910390a15050565b61199c61330b565b6060603680548060200260200160405190810160405280929190818152602001828054801561281057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116127f2575b5050505050905090565b612822612a3b565b61283e5760405162461bcd60e51b8152600401610a7290614deb565b600054610100900460ff1680612857575060005460ff16155b6128ba5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a72565b600054610100900460ff161580156128dc576000805461ffff19166101011790555b6001600160a01b03821661292b5760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b6044820152606401610a72565b603c80546001600160a01b0384166001600160a01b03199091161790556037805461ffff60a01b1916600160a81b1790556000603981905569054b40b1f852bda00000603a55604080519182526020820190819052905161298e91603691614ae3565b50604f805467ffffffffffffffff60401b19166a093a8000000000000000001790558015610ce2576000805461ff00191690555050565b603f546001600160a01b03163314806129e157506129e1612a3b565b6129fd5760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b6000612a536000805160206151718339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612a885750612a88612a3b565b612aa45760405162461bcd60e51b8152600401610a7290614da3565b611a436143a6565b612ab4612a3b565b612ad05760405162461bcd60e51b8152600401610a7290614deb565b612af8817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612b186000805160206151718339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000610c2361443b565b6000612be3603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd69190614ef6565b612bde61443b565b61448f565b50919050565b603754600090600160a81b900460ff1615612c165760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101612c485760405162461bcd60e51b8152600401610a7290614e4a565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115612c8957612c8761330b565b505b612c92846134e7565b9250612cc86001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130e0565b612cd0613848565b5060019055919050565b603754600090600160a01b900460ff1615612d295760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b6044820152606401610a72565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612d73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d979190614ef6565b90506000612da361443b565b905081600003612db65791506130719050565b600080612dc3848461448f565b90925090506000612dd48386614f47565b90508481111580612de457508381115b15612df3575091949350505050565b612e04826001600160401b03614662565b604f805477ffffffffffffffffffffffffffffffff000000000000000016600160c01b6001600160401b039384160267ffffffffffffffff19161742929092169190911790556042546001600160a01b031660008115612f405761271060435486612e6f9190614f95565b612e799190614f73565b90508015612f4057848110612edb5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b6064820152608401610a72565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612f0d9085908590600401614f5a565b600060405180830381600087803b158015612f2757600080fd5b505af1158015612f3b573d6000803e3d6000fd5b505050505b604080516001600160a01b0384168152602081018790529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a1603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fdd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130019190614ef6565b83111561306757603c546040516339a7919f60e01b8152600481018590526001600160a01b03909116906339a7919f90602401600060405180830381600087803b15801561304e57600080fd5b505af1158015613062573d6000803e3d6000fd5b505050505b5093955050505050505b90565b60006001600160401b038211156130dc5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610a72565b5090565b6110f28363a9059cbb60e01b84846040516024016130ff929190614f5a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614678565b600081116131865760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a72565b60006131b782601260ff7f0000000000000000000000000000000000000000000000000000000000000000166132a7565b90507f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516131ea929190614f5a565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132249033908590600401614f5a565b600060405180830381600087803b15801561323e57600080fd5b505af1158015613252573d6000803e3d6000fd5b5061328d9250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016905033308561474a565b61329561330b565b50603a548110610ce257610ce2613fec565b6000818311156132d7576132d06132be8385614ecd565b6132c990600a615093565b8590614788565b9350613301565b81831015613301576132fe6132ec8484614ecd565b6132f790600a615093565b8590614794565b93505b50825b9392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c548084169686019690965292909404166060830152600092839161335d9161509f565b6001600160801b03169050806000036133795760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156133e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134049190614ef6565b905060008360400151846020015161341c919061509f565b6001600160801b0316905080821161343957600094505050505090565b60006134458284614ecd565b90508084106134545780613456565b835b955060008686602001516001600160801b03166134739190614f47565b905061347e81613f83565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f463333906134d69083908a90918252602082015260400190565b60405180910390a150505050505090565b600080604e541161353a5760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a72565b6000828152604d6020908152604091829020825160a08101845281546001600160a01b038116825260ff600160a01b82041615158285015264ffffffffff600160a81b90910481168286019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915288519081018952604b548084168252849004831697810197909752604c54808316988801989098529190960490951694840194909452604e5491519093429261360192909116614f47565b11156136455760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b6044820152606401610a72565b80602001516001600160801b031682608001516001600160801b031611156136af5760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c69717569646974790000000000000000006044820152606401610a72565b81516001600160a01b031633146136f85760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b6044820152606401610a72565b60208201511561373c5760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b6044820152606401610a72565b6000848152604d60205260409020805460ff60a01b1916600160a01b179055606082015161379c906120fb906001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b81604001516137ab91906150be565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a361384082606001516001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b949350505050565b600061385261443b565b6041549091501561199c57600081116138ad5760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e672072657175657374730000006044820152606401610a72565b600061393082603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613906573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061392a9190614ef6565b906147a0565b9050604154670de0b6b3a7640000821161395b5761395682670de0b6b3a7640000614ecd565b61396d565b61396d670de0b6b3a764000083614ecd565b1115610ce25760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f7200006044820152606401610a72565b6001600160a01b03811660009081526035602052604090205460ff16613a235760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f72746564000000000000006044820152606401610a72565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a6357600080fd5b505af1158015613a77573d6000803e3d6000fd5b505050506110f261330b565b6001600160a01b038116613ad95760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610a72565b61199c816147c1565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614613b2557506000919050565b6040516370a0823160e01b815230600482015282906001600160a01b038216906370a0823190602401602060405180830381865afa158015613b6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b8f9190614ef6565b60365490925060005b81811015613cb457600060368281548110613bb557613bb5614ea1565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af690602401602060405180830381865afa158015613c0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c2f9190614f25565b15613cab57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f51522690602401602060405180830381865afa158015613c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c9e9190614ef6565b613ca89086614f47565b94505b50600101613b98565b5060408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529091613d029086614f47565b1015613d1357506000949350505050565b805160408201516001600160801b0391821691613d31911686614f47565b613d3b9190614ecd565b95945050505050565b6001600160a01b03851660009081526035602052604090205460ff16613da25760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b6044820152606401610a72565b600183148015613db25750600181145b8015613e1657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684846000818110613df657613df6614ea1565b9050602002016020810190613e0b9190614be6565b6001600160a01b0316145b613e625760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920617373657420697320737570706f727465640000000000000000006044820152606401610a72565b613e6a614828565b82826000818110613e7d57613e7d614ea1565b905060200201351115613ed25760405162461bcd60e51b815260206004820152601b60248201527f4e6f7420656e6f7567682061737365747320617661696c61626c6500000000006044820152606401610a72565b613f298583836000818110613ee957613ee9614ea1565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166130e09092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613f6457600080fd5b505af1158015613f78573d6000803e3d6000fd5b505050505050505050565b60006001600160801b038211156130dc5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610a72565b6050546001600160a01b0316806140005750565b600061400a614828565b905080600003614018575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015614062573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140869190614ef6565b905060006140cf7f000000000000000000000000000000000000000000000000000000000000000060ff1660126140c86039548661493690919063ffffffff16565b91906132a7565b90508083116140de5750505050565b60006140ea8285614ecd565b9050846141216001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682846130e0565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061416f907f0000000000000000000000000000000000000000000000000000000000000000908690600401614f5a565b600060405180830381600087803b15801561418957600080fd5b505af115801561419d573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b6001600160a01b03851660009081526035602052604090205460ff166142755760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b6044820152606401610a72565b8281146142c45760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d61746368000000000000006044820152606401610a72565b8260005b8181101561439357866001600160a01b031663d9caed12898888858181106142f2576142f2614ea1565b90506020020160208101906143079190614be6565b87878681811061431957614319614ea1565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561437057600080fd5b505af1158015614384573d6000803e3d6000fd5b505050508060010190506142c8565b5061439c61330b565b5050505050505050565b60365460005b8181101561443257603681815481106143c7576143c7614ea1565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b15801561440f57600080fd5b505af1158015614423573d6000803e3d6000fd5b505050508060010190506143ac565b50610ce261330b565b6000610c2360127f000000000000000000000000000000000000000000000000000000000000000060ff166140c87f0000000000000000000000000000000000000000000000000000000000000000613ae2565b6000806000603c60009054906101000a90046001600160a01b03166001600160a01b031663e696393a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156144e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061450b9190614ef6565b905060006145198287614ecd565b604f54909150600090614535906001600160401b031642614ecd565b604f54600160c01b90046001600160401b031694509050801580614557575081155b8061456157508587115b8061457357506001600160401b034210155b15614584576000945050505061465b565b61458e8787614ecd565b604f54909550600160401b90046001600160401b031660018111156145f3576145cb856145bc836002614f95565b6145c69089614f73565b61494b565b94506145e0856145db8389614f73565b614662565b94506145f0866145db8488614f95565b95505b604f54614634908790670de0b6b3a764000090600160801b90046001600160401b03166146208688614f95565b61462a9190614f95565b6145db9190614f73565b955061465486670de0b6b3a764000061462a66470de4df82000087614f95565b9550505050505b9250929050565b60008183106146715781613304565b5090919050565b60006146cd826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661495a9092919063ffffffff16565b8051909150156110f257808060200190518101906146eb9190614f25565b6110f25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a72565b6040516001600160a01b03808516602483015283166044820152606481018290526147829085906323b872dd60e01b906084016130ff565b50505050565b60006133048284614f95565b60006133048284614f73565b6000806147b584670de0b6b3a7640000614788565b90506138408184614794565b806001600160a01b03166147e16000805160206151718339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a360008051602061517183398151915255565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301526000928391614878919061509f565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156148ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149119190614ef6565b9050818111614924576000935050505090565b61492e8282614ecd565b935050505090565b60006133048383670de0b6b3a7640000614969565b60008183116146715781613304565b60606138408484600085614982565b6000806149768585614788565b9050613d3b8184614794565b6060824710156149e35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a72565b843b614a315760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a72565b600080866001600160a01b03168587604051614a4d9190615101565b60006040518083038185875af1925050503d8060008114614a8a576040519150601f19603f3d011682016040523d82523d6000602084013e614a8f565b606091505b5091509150614a9f828286614aaa565b979650505050505050565b60608315614ab9575081613304565b825115614ac95782518084602001fd5b8160405162461bcd60e51b8152600401610a72919061511d565b828054828255906000526020600020908101928215614b38579160200282015b82811115614b3857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614b03565b506130dc9291505b808211156130dc5760008155600101614b40565b600060208284031215614b6657600080fd5b5035919050565b80356001600160a01b0381168114614b8457600080fd5b919050565b60008060408385031215614b9c57600080fd5b614ba583614b6d565b946020939093013593505050565b600080600060608486031215614bc857600080fd5b614bd184614b6d565b95602085013595506040909401359392505050565b600060208284031215614bf857600080fd5b61330482614b6d565b602080825282518282018190526000918401906040840190835b81811015614c425783516001600160a01b0316835260209384019390920191600101614c1b565b509095945050505050565b60008083601f840112614c5f57600080fd5b5081356001600160401b03811115614c7657600080fd5b6020830191508360208260051b850101111561465b57600080fd5b60008060208385031215614ca457600080fd5b82356001600160401b03811115614cba57600080fd5b614cc685828601614c4d565b90969095509350505050565b6040808252835190820181905260009060208501906060840190835b81811015614d0c578351835260209384019390920191600101614cee565b5050602093909301939093525092915050565b600080600080600060608688031215614d3757600080fd5b614d4086614b6d565b945060208601356001600160401b03811115614d5b57600080fd5b614d6788828901614c4d565b90955093505060408601356001600160401b03811115614d8657600080fd5b614d9288828901614c4d565b969995985093965092949392505050565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60208082526015908201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115611a5057611a50614eb7565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614f0857600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215614f3757600080fd5b8151801515811461330457600080fd5b80820180821115611a5057611a50614eb7565b6001600160a01b03929092168252602082015260400190565b600082614f9057634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417611a5057611a50614eb7565b6001815b6001841115614fe757808504811115614fcb57614fcb614eb7565b6001841615614fd957908102905b60019390931c928002614fb0565b935093915050565b600082614ffe57506001611a50565b8161500b57506000611a50565b8160018114615021576002811461502b57615047565b6001915050611a50565b60ff84111561503c5761503c614eb7565b50506001821b611a50565b5060208310610133831016604e8410600b841016171561506a575081810a611a50565b6150776000198484614fac565b806000190482111561508b5761508b614eb7565b029392505050565b60006133048383614fef565b6001600160801b038281168282160390811115611a5057611a50614eb7565b6001600160801b038181168382160190811115611a5057611a50614eb7565b60005b838110156150f85781810151838201526020016150e0565b50506000910152565b600082516151138184602087016150dd565b9190910192915050565b602081526000825180602084015261513c8160408501602087016150dd565b601f01601f1916919091016040019291505056fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122087f0c7c2ae81c28a8a454740a4486d0445606a5b1d80250b4aef44918d20849664736f6c634300081c0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106104075760003560e01c8063663e64ce11610220578063ae69f3cb11610130578063c7af3352116100b8578063e6cc543211610087578063e6cc5432146109e5578063ea33b8e4146109f9578063f3f18c3714610a01578063f844443614610a14578063fac5bb9b14610a2757600080fd5b8063c7af3352146109ba578063c9919112146109c2578063d38bfff4146109ca578063d4c3eea0146109dd57600080fd5b8063b9b17f9f116100ff578063b9b17f9f14610975578063bb7a632e1461097d578063c3b2886414610997578063c4d66de81461099f578063c5f00841146109b257600080fd5b8063ae69f3cb14610934578063af14052c14610947578063b2c9336d1461094f578063b4925a201461096257600080fd5b806395b166bc116101b35780639fa1826e116101825780639fa1826e146108f6578063a0712d68146108ff578063a0aead4d14610912578063ab80dafb14610919578063abaa99161461092c57600080fd5b806395b166bc146108685780639be918e61461087b5780639e428552146108bb5780639ee679e8146108ce57600080fd5b80638e510b52116101ef5780638e510b521461079c5780638ec489a2146107a5578063937b2581146107b857806394828ffd1461086057600080fd5b8063663e64ce14610750578063773540b31461076357806378f353a114610776578063840c4c7a1461078957600080fd5b806339ebf8231161031b578063527e83a8116102ae5780635802a1721161027d5780635802a172146106fe578063597c89101461070f5780635d36b190146107225780635f5152261461072a5780636217f3ea1461073d57600080fd5b8063527e83a8146106aa57806353ca9f24146106c4578063570d8e1d146106d857806357bee944146106eb57600080fd5b806345e4213b116102ea57806345e4213b1461063b57806348e30f541461064457806349c1d54d146106655780634d5f46291461067857600080fd5b806339ebf823146105a95780633b8ae397146105ed5780633dbc911f146106005780634530820a1461060857600080fd5b80631a32aad61161039e5780632acada4d1161036d5780632acada4d146104f35780632da845a81461050857806331e19cfa1461051b578063362bd1a31461052357806338d52e0f1461058257600080fd5b80631a32aad6146104ad5780631cfbe7bc146104c05780631edfe3da146104d3578063207134b0146104ea57600080fd5b80631072cbea116103da5780631072cbea14610461578063156e29f614610474578063175188e8146104875780631816dd4a1461049a57600080fd5b80630493a0fa1461040c57806309f49bf5146104215780630acbda75146104295780630c340a241461043c575b600080fd5b61041f61041a366004614b54565b610a3a565b005b61041f610af0565b61041f610437366004614b54565b610b60565b610444610c0b565b6040516001600160a01b0390911681526020015b60405180910390f35b61041f61046f366004614b89565b610c28565b61041f610482366004614bb3565b610ce6565b61041f610495366004614be6565b610d59565b61041f6104a8366004614be6565b6110f7565b603c54610444906001600160a01b031681565b61041f6104ce366004614b54565b6111fe565b6104dc60395481565b604051908152602001610458565b6104dc60435481565b6104fb6112c0565b6040516104589190614c01565b61041f610516366004614be6565b611337565b6036546104dc565b604b54604c5461054f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610458565b6104447f000000000000000000000000000000000000000000000000000000000000000081565b6105d66105b7366004614be6565b6035602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610458565b61041f6105fb366004614be6565b6113a9565b61041f6115bc565b61062b610616366004614be6565b60496020526000908152604090205460ff1681565b6040519015158152602001610458565b6104dc604e5481565b610657610652366004614c91565b611632565b604051610458929190614cd2565b604254610444906001600160a01b031681565b604f5461069290600160c01b90046001600160401b031681565b6040516001600160401b039091168152602001610458565b604f5461069290600160801b90046001600160401b031681565b60375461062b90600160a01b900460ff1681565b603f54610444906001600160a01b031681565b61041f6106f9366004614be6565b6117a8565b603c546001600160a01b0316610444565b61041f61071d366004614be6565b61195b565b61041f61199f565b6104dc610738366004614be6565b611a45565b61041f61074b366004614b54565b611a56565b61041f61075e366004614b54565b611bda565b61041f610771366004614be6565b611c33565b604f54610692906001600160401b031681565b61041f610797366004614d1f565b611ca5565b6104dc60415481565b61041f6107b3366004614b54565b611d2c565b6108196107c6366004614b54565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a001610458565b61041f611de1565b61041f610876366004614be6565b611e51565b61062b610889366004614be6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b61041f6108c9366004614be6565b611f18565b6108e16108dc366004614b54565b611f8a565b60408051928352602083019190915201610458565b6104dc603a5481565b61041f61090d366004614b54565b6122ca565b60016104dc565b61041f610927366004614b54565b61233b565b61041f61248a565b61041f610942366004614d1f565b612502565b61041f61257e565b61041f61095d366004614b54565b612639565b61041f610970366004614b54565b612692565b61041f6127b0565b604f5461069290600160401b90046001600160401b031681565b6104fb6127b8565b61041f6109ad366004614be6565b61281a565b61041f6129c5565b61062b612a3b565b61041f612a6c565b61041f6109d8366004614be6565b612aac565b6104dc612b50565b60375461062b90600160a81b900460ff1681565b6104dc612b5a565b605154610444906001600160a01b031681565b6104dc610a22366004614b54565b612be9565b605054610444906001600160a01b031681565b603f546001600160a01b0316331480610a565750610a56612a3b565b610a7b5760405162461bcd60e51b8152600401610a7290614da3565b60405180910390fd5b610a83612cda565b50610a8d81613074565b604f80546001600160401b0392909216600160401b0267ffffffffffffffff60401b199092169190911790556040518181527f406e15fbca1d8ded2dbb06765fea3a54f18395c54125a4c9916dd00ea14ee15e906020015b60405180910390a150565b603f546001600160a01b0316331480610b0c5750610b0c612a3b565b610b285760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b610b68612a3b565b610b845760405162461bcd60e51b8152600401610a7290614deb565b611388811115610bd65760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f7420657863656564203530250000000000000000006044820152606401610a72565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c790602001610ae5565b6000610c236000805160206151718339815191525490565b905090565b610c30612a3b565b610c4c5760405162461bcd60e51b8152600401610a7290614deb565b816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610cc65760405162461bcd60e51b815260206004820152601660248201527513db9b1e481d5b9cdd5c1c1bdc9d195908185cdcd95d60521b6044820152606401610a72565b610ce2610cd1610c0b565b6001600160a01b03841690836130e0565b5050565b603754600160a81b900460ff1615610d105760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101610d425760405162461bcd60e51b8152600401610a7290614e4a565b60028255610d4f84613136565b5060019055505050565b610d61612a3b565b610d7d5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff16610db55760405162461bcd60e51b8152600401610a7290614e72565b6050546001600160a01b03808316911603610e125760405162461bcd60e51b815260206004820152601d60248201527f53747261746567792069732064656661756c7420666f722061737365740000006044820152606401610a72565b6036548060005b82811015610e6857836001600160a01b031660368281548110610e3e57610e3e614ea1565b6000918252602090912001546001600160a01b031603610e6057809150610e68565b600101610e19565b50818110156110f2576036610e7e600184614ecd565b81548110610e8e57610e8e614ea1565b600091825260209091200154603680546001600160a01b039092169183908110610eba57610eba614ea1565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610ef957610ef9614ee0565b6001900381819060005260206000200160006101000a8154906001600160a01b03021916905590556000839050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610f6157600080fd5b505af1158015610f75573d6000803e3d6000fd5b505050506001600160a01b0384166000908152603560209081526040808320805460ff199081169091556049909252822080549091169055610fe26509184e72a00060ff7f00000000000000000000000000000000000000000000000000000000000000001660126132a7565b604051632fa8a91360e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192508291841690635f51522690602401602060405180830381865afa15801561104d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110719190614ef6565b106110b35760405162461bcd60e51b81526020600482015260126024820152715374726174656779206861732066756e647360701b6044820152606401610a72565b6040516001600160a01b03861681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49060200160405180910390a150505b505050565b6110ff612a3b565b61111b5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff166111535760405162461bcd60e51b8152600401610a7290614e72565b6001600160a01b03811660009081526049602052604090205460ff16156111b25760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481dda1a5d195b1a5cdd1959606a1b6044820152606401610a72565b6001600160a01b038116600081815260496020526040808220805460ff19166001179055517f47c8c96a5942f094264111c5fe7f6a4fe86efe63254a6fa7afa5fc84f07d58e89190a250565b611206612a3b565b6112225760405162461bcd60e51b8152600401610a7290614deb565b80158061123f5750610258811015801561123f57506213c6808111155b61128b5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636c61696d2064656c617920706572696f640000000000006044820152606401610a72565b604e8190556040518181527fc59f5e32049abab44ddea11021f5abb89422a2f550837afcf25df9fc8d0db6b090602001610ae5565b60408051600180825281830190925260609160009190602080830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061131a5761131a614ea1565b6001600160a01b0390921660209283029190910190910152919050565b61133f612a3b565b61135b5760405162461bcd60e51b8152600401610a7290614deb565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610ae5565b6113b1612a3b565b6113cd5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff16156114365760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f766564000000000000006044820152606401610a72565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa15801561149c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c09190614f25565b61150c5760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a72565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610ae5565b603f546001600160a01b03163314806115d857506115d8612a3b565b6115f45760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b603754606090600090600160a81b900460ff16156116625760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016116945760405162461bcd60e51b8152600401610a7290614e4a565b600282556116a061330b565b50846001600160401b038111156116b9576116b9614f0f565b6040519080825280602002602001820160405280156116e2578160200160208202803683370190505b50935060005b8581101561175e5761171187878381811061170557611705614ea1565b905060200201356134e7565b85828151811061172357611723614ea1565b60200260200101818152505084818151811061174157611741614ea1565b6020026020010151846117549190614f47565b93506001016116e8565b506117936001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130e0565b61179b613848565b6001825550509250929050565b603f546001600160a01b03163314806117c457506117c4612a3b565b6117e05760405162461bcd60e51b8152600401610a7290614da3565b6040516001600160a01b03821681527f45a9e715f8779ebeab88d3e8d081fb8b484b7730857e7c4478a95a5b1d8f79489060200160405180910390a16001600160a01b03811615611939576001600160a01b03811660009081526035602052604090205460ff166118635760405162461bcd60e51b8152600401610a7290614e72565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa1580156118c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ed9190614f25565b6119395760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a72565b605080546001600160a01b0319166001600160a01b0392909216919091179055565b603f546001600160a01b03163314806119775750611977612a3b565b6119935760405162461bcd60e51b8152600401610a7290614da3565b61199c816139bb565b50565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614611a3a5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610a72565b611a4333613a83565b565b6000611a5082613ae2565b92915050565b603754600160a81b900460ff1615611a805760405162461bcd60e51b8152600401610a7290614e22565b3360009081526035602052604090205460ff161515600114611adb5760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a72565b3360009081526049602052604090205460ff161515600114611b3a5760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a72565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051611b6b929190614f5a565b60405180910390a1603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90611ba59033908590600401614f5a565b600060405180830381600087803b158015611bbf57600080fd5b505af1158015611bd3573d6000803e3d6000fd5b5050505050565b611be2612a3b565b611bfe5760405162461bcd60e51b8152600401610a7290614deb565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610ae5565b611c3b612a3b565b611c575760405162461bcd60e51b8152600401610a7290614deb565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610ae5565b603f546001600160a01b0316331480611cc15750611cc1612a3b565b611cdd5760405162461bcd60e51b8152600401610a7290614da3565b60008051602061515183398151915280546001198101611d0f5760405162461bcd60e51b8152600401610a7290614e4a565b60028255611d208787878787613d44565b50600190555050505050565b603f546001600160a01b0316331480611d485750611d48612a3b565b611d645760405162461bcd60e51b8152600401610a7290614da3565b670de0b6b3a7640000811115611dac5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b6044820152606401610a72565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610ae5565b603f546001600160a01b0316331480611dfd5750611dfd612a3b565b611e195760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e59612a3b565b611e755760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526049602052604090205460ff16611ecf5760405162461bcd60e51b815260206004820152600f60248201526e139bdd081dda1a5d195b1a5cdd1959608a1b6044820152606401610a72565b6001600160a01b038116600081815260496020526040808220805460ff19169055517f0ec40967a61509853550658e51d0e4297f7cba244fe4adc8ba18b5631ac20e2f9190a250565b611f20612a3b565b611f3c5760405162461bcd60e51b8152600401610a7290614deb565b605180546001600160a01b0319166001600160a01b0383169081179091556040519081527fb3b3f5f64ab192e4b5fefde1f51ce9733bbdcf831951543b325aebd49cc27ec490602001610ae5565b6037546000908190600160a81b900460ff1615611fb95760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101611feb5760405162461bcd60e51b8152600401610a7290614e4a565b600282556000851161203f5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a72565b6000604e54116120915760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a72565b604c54600160801b90046001600160801b031693506120d5857f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b604b546120eb91906001600160801b0316614f47565b92506121006120fb856001614f47565b613f83565b604c80546001600160801b03928316600160801b02921691909117905561212683613f83565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff16918101919091526060810161217687613f83565b6001600160801b0316815260200161218d85613f83565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906122489033908990600401614f5a565b600060405180830381600087803b15801561226257600080fd5b505af1158015612276573d6000803e3d6000fd5b50505050612282613848565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff16156122f45760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016123265760405162461bcd60e51b8152600401610a7290614e4a565b6002825561233383613136565b506001905550565b603754600160a81b900460ff16156123655760405162461bcd60e51b8152600401610a7290614e22565b3360009081526035602052604090205460ff1615156001146123c05760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a72565b3360009081526049602052604090205460ff16151560011461241f5760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a72565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853382604051612450929190614f5a565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611ba59033908590600401614f5a565b603754600160a81b900460ff16156124b45760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016124e65760405162461bcd60e51b8152600401610a7290614e4a565b600282556124f261330b565b506124fb613fec565b5060019055565b603f546001600160a01b031633148061251e575061251e612a3b565b61253a5760405162461bcd60e51b8152600401610a7290614da3565b6000805160206151518339815191528054600119810161256c5760405162461bcd60e51b8152600401610a7290614e4a565b60028255611d20308888888888614215565b600080516020615151833981519152805460011981016125b05760405162461bcd60e51b8152600401610a7290614e4a565b600282556051546001600160a01b03163314806125d75750603f546001600160a01b031633145b806125e557506125e5612a3b565b6126295760405162461bcd60e51b815260206004820152601560248201527410d85b1b195c881b9bdd08185d5d1a1bdc9a5e9959605a1b6044820152606401610a72565b612631612cda565b505060019055565b612641612a3b565b61265d5760405162461bcd60e51b8152600401610a7290614deb565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610ae5565b603f546001600160a01b03163314806126ae57506126ae612a3b565b6126ca5760405162461bcd60e51b8152600401610a7290614da3565b6126d2612cda565b5060006301e133806126e5606484614f73565b6126ef9190614f73565b90506127056201518066b1a2bc2ec50000614f73565b8111156127445760405162461bcd60e51b815260206004820152600d60248201526c0a4c2e8ca40e8dede40d0d2ced609b1b6044820152606401610a72565b61274d81613074565b604f80546001600160401b0392909216600160801b0267ffffffffffffffff60801b199092169190911790556040518181527fef46f143af5fead0010484fe7d6ec2e2972420faa76157f5a6075aa72e614cb59060200160405180910390a15050565b61199c61330b565b6060603680548060200260200160405190810160405280929190818152602001828054801561281057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116127f2575b5050505050905090565b612822612a3b565b61283e5760405162461bcd60e51b8152600401610a7290614deb565b600054610100900460ff1680612857575060005460ff16155b6128ba5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a72565b600054610100900460ff161580156128dc576000805461ffff19166101011790555b6001600160a01b03821661292b5760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b6044820152606401610a72565b603c80546001600160a01b0384166001600160a01b03199091161790556037805461ffff60a01b1916600160a81b1790556000603981905569054b40b1f852bda00000603a55604080519182526020820190819052905161298e91603691614ae3565b50604f805467ffffffffffffffff60401b19166a093a8000000000000000001790558015610ce2576000805461ff00191690555050565b603f546001600160a01b03163314806129e157506129e1612a3b565b6129fd5760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b6000612a536000805160206151718339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612a885750612a88612a3b565b612aa45760405162461bcd60e51b8152600401610a7290614da3565b611a436143a6565b612ab4612a3b565b612ad05760405162461bcd60e51b8152600401610a7290614deb565b612af8817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612b186000805160206151718339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000610c2361443b565b6000612be3603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd69190614ef6565b612bde61443b565b61448f565b50919050565b603754600090600160a81b900460ff1615612c165760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101612c485760405162461bcd60e51b8152600401610a7290614e4a565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115612c8957612c8761330b565b505b612c92846134e7565b9250612cc86001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130e0565b612cd0613848565b5060019055919050565b603754600090600160a01b900460ff1615612d295760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b6044820152606401610a72565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612d73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d979190614ef6565b90506000612da361443b565b905081600003612db65791506130719050565b600080612dc3848461448f565b90925090506000612dd48386614f47565b90508481111580612de457508381115b15612df3575091949350505050565b612e04826001600160401b03614662565b604f805477ffffffffffffffffffffffffffffffff000000000000000016600160c01b6001600160401b039384160267ffffffffffffffff19161742929092169190911790556042546001600160a01b031660008115612f405761271060435486612e6f9190614f95565b612e799190614f73565b90508015612f4057848110612edb5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b6064820152608401610a72565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612f0d9085908590600401614f5a565b600060405180830381600087803b158015612f2757600080fd5b505af1158015612f3b573d6000803e3d6000fd5b505050505b604080516001600160a01b0384168152602081018790529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a1603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fdd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130019190614ef6565b83111561306757603c546040516339a7919f60e01b8152600481018590526001600160a01b03909116906339a7919f90602401600060405180830381600087803b15801561304e57600080fd5b505af1158015613062573d6000803e3d6000fd5b505050505b5093955050505050505b90565b60006001600160401b038211156130dc5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610a72565b5090565b6110f28363a9059cbb60e01b84846040516024016130ff929190614f5a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614678565b600081116131865760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a72565b60006131b782601260ff7f0000000000000000000000000000000000000000000000000000000000000000166132a7565b90507f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516131ea929190614f5a565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132249033908590600401614f5a565b600060405180830381600087803b15801561323e57600080fd5b505af1158015613252573d6000803e3d6000fd5b5061328d9250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016905033308561474a565b61329561330b565b50603a548110610ce257610ce2613fec565b6000818311156132d7576132d06132be8385614ecd565b6132c990600a615093565b8590614788565b9350613301565b81831015613301576132fe6132ec8484614ecd565b6132f790600a615093565b8590614794565b93505b50825b9392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c548084169686019690965292909404166060830152600092839161335d9161509f565b6001600160801b03169050806000036133795760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156133e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134049190614ef6565b905060008360400151846020015161341c919061509f565b6001600160801b0316905080821161343957600094505050505090565b60006134458284614ecd565b90508084106134545780613456565b835b955060008686602001516001600160801b03166134739190614f47565b905061347e81613f83565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f463333906134d69083908a90918252602082015260400190565b60405180910390a150505050505090565b600080604e541161353a5760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a72565b6000828152604d6020908152604091829020825160a08101845281546001600160a01b038116825260ff600160a01b82041615158285015264ffffffffff600160a81b90910481168286019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915288519081018952604b548084168252849004831697810197909752604c54808316988801989098529190960490951694840194909452604e5491519093429261360192909116614f47565b11156136455760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b6044820152606401610a72565b80602001516001600160801b031682608001516001600160801b031611156136af5760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c69717569646974790000000000000000006044820152606401610a72565b81516001600160a01b031633146136f85760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b6044820152606401610a72565b60208201511561373c5760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b6044820152606401610a72565b6000848152604d60205260409020805460ff60a01b1916600160a01b179055606082015161379c906120fb906001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b81604001516137ab91906150be565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a361384082606001516001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b949350505050565b600061385261443b565b6041549091501561199c57600081116138ad5760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e672072657175657374730000006044820152606401610a72565b600061393082603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613906573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061392a9190614ef6565b906147a0565b9050604154670de0b6b3a7640000821161395b5761395682670de0b6b3a7640000614ecd565b61396d565b61396d670de0b6b3a764000083614ecd565b1115610ce25760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f7200006044820152606401610a72565b6001600160a01b03811660009081526035602052604090205460ff16613a235760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f72746564000000000000006044820152606401610a72565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a6357600080fd5b505af1158015613a77573d6000803e3d6000fd5b505050506110f261330b565b6001600160a01b038116613ad95760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610a72565b61199c816147c1565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614613b2557506000919050565b6040516370a0823160e01b815230600482015282906001600160a01b038216906370a0823190602401602060405180830381865afa158015613b6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b8f9190614ef6565b60365490925060005b81811015613cb457600060368281548110613bb557613bb5614ea1565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af690602401602060405180830381865afa158015613c0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c2f9190614f25565b15613cab57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f51522690602401602060405180830381865afa158015613c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c9e9190614ef6565b613ca89086614f47565b94505b50600101613b98565b5060408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529091613d029086614f47565b1015613d1357506000949350505050565b805160408201516001600160801b0391821691613d31911686614f47565b613d3b9190614ecd565b95945050505050565b6001600160a01b03851660009081526035602052604090205460ff16613da25760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b6044820152606401610a72565b600183148015613db25750600181145b8015613e1657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684846000818110613df657613df6614ea1565b9050602002016020810190613e0b9190614be6565b6001600160a01b0316145b613e625760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920617373657420697320737570706f727465640000000000000000006044820152606401610a72565b613e6a614828565b82826000818110613e7d57613e7d614ea1565b905060200201351115613ed25760405162461bcd60e51b815260206004820152601b60248201527f4e6f7420656e6f7567682061737365747320617661696c61626c6500000000006044820152606401610a72565b613f298583836000818110613ee957613ee9614ea1565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166130e09092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613f6457600080fd5b505af1158015613f78573d6000803e3d6000fd5b505050505050505050565b60006001600160801b038211156130dc5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610a72565b6050546001600160a01b0316806140005750565b600061400a614828565b905080600003614018575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015614062573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140869190614ef6565b905060006140cf7f000000000000000000000000000000000000000000000000000000000000000060ff1660126140c86039548661493690919063ffffffff16565b91906132a7565b90508083116140de5750505050565b60006140ea8285614ecd565b9050846141216001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682846130e0565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061416f907f0000000000000000000000000000000000000000000000000000000000000000908690600401614f5a565b600060405180830381600087803b15801561418957600080fd5b505af115801561419d573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b6001600160a01b03851660009081526035602052604090205460ff166142755760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b6044820152606401610a72565b8281146142c45760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d61746368000000000000006044820152606401610a72565b8260005b8181101561439357866001600160a01b031663d9caed12898888858181106142f2576142f2614ea1565b90506020020160208101906143079190614be6565b87878681811061431957614319614ea1565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561437057600080fd5b505af1158015614384573d6000803e3d6000fd5b505050508060010190506142c8565b5061439c61330b565b5050505050505050565b60365460005b8181101561443257603681815481106143c7576143c7614ea1565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b15801561440f57600080fd5b505af1158015614423573d6000803e3d6000fd5b505050508060010190506143ac565b50610ce261330b565b6000610c2360127f000000000000000000000000000000000000000000000000000000000000000060ff166140c87f0000000000000000000000000000000000000000000000000000000000000000613ae2565b6000806000603c60009054906101000a90046001600160a01b03166001600160a01b031663e696393a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156144e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061450b9190614ef6565b905060006145198287614ecd565b604f54909150600090614535906001600160401b031642614ecd565b604f54600160c01b90046001600160401b031694509050801580614557575081155b8061456157508587115b8061457357506001600160401b034210155b15614584576000945050505061465b565b61458e8787614ecd565b604f54909550600160401b90046001600160401b031660018111156145f3576145cb856145bc836002614f95565b6145c69089614f73565b61494b565b94506145e0856145db8389614f73565b614662565b94506145f0866145db8488614f95565b95505b604f54614634908790670de0b6b3a764000090600160801b90046001600160401b03166146208688614f95565b61462a9190614f95565b6145db9190614f73565b955061465486670de0b6b3a764000061462a66470de4df82000087614f95565b9550505050505b9250929050565b60008183106146715781613304565b5090919050565b60006146cd826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661495a9092919063ffffffff16565b8051909150156110f257808060200190518101906146eb9190614f25565b6110f25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a72565b6040516001600160a01b03808516602483015283166044820152606481018290526147829085906323b872dd60e01b906084016130ff565b50505050565b60006133048284614f95565b60006133048284614f73565b6000806147b584670de0b6b3a7640000614788565b90506138408184614794565b806001600160a01b03166147e16000805160206151718339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a360008051602061517183398151915255565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301526000928391614878919061509f565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156148ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149119190614ef6565b9050818111614924576000935050505090565b61492e8282614ecd565b935050505090565b60006133048383670de0b6b3a7640000614969565b60008183116146715781613304565b60606138408484600085614982565b6000806149768585614788565b9050613d3b8184614794565b6060824710156149e35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a72565b843b614a315760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a72565b600080866001600160a01b03168587604051614a4d9190615101565b60006040518083038185875af1925050503d8060008114614a8a576040519150601f19603f3d011682016040523d82523d6000602084013e614a8f565b606091505b5091509150614a9f828286614aaa565b979650505050505050565b60608315614ab9575081613304565b825115614ac95782518084602001fd5b8160405162461bcd60e51b8152600401610a72919061511d565b828054828255906000526020600020908101928215614b38579160200282015b82811115614b3857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614b03565b506130dc9291505b808211156130dc5760008155600101614b40565b600060208284031215614b6657600080fd5b5035919050565b80356001600160a01b0381168114614b8457600080fd5b919050565b60008060408385031215614b9c57600080fd5b614ba583614b6d565b946020939093013593505050565b600080600060608486031215614bc857600080fd5b614bd184614b6d565b95602085013595506040909401359392505050565b600060208284031215614bf857600080fd5b61330482614b6d565b602080825282518282018190526000918401906040840190835b81811015614c425783516001600160a01b0316835260209384019390920191600101614c1b565b509095945050505050565b60008083601f840112614c5f57600080fd5b5081356001600160401b03811115614c7657600080fd5b6020830191508360208260051b850101111561465b57600080fd5b60008060208385031215614ca457600080fd5b82356001600160401b03811115614cba57600080fd5b614cc685828601614c4d565b90969095509350505050565b6040808252835190820181905260009060208501906060840190835b81811015614d0c578351835260209384019390920191600101614cee565b5050602093909301939093525092915050565b600080600080600060608688031215614d3757600080fd5b614d4086614b6d565b945060208601356001600160401b03811115614d5b57600080fd5b614d6788828901614c4d565b90955093505060408601356001600160401b03811115614d8657600080fd5b614d9288828901614c4d565b969995985093965092949392505050565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60208082526015908201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115611a5057611a50614eb7565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614f0857600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215614f3757600080fd5b8151801515811461330457600080fd5b80820180821115611a5057611a50614eb7565b6001600160a01b03929092168252602082015260400190565b600082614f9057634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417611a5057611a50614eb7565b6001815b6001841115614fe757808504811115614fcb57614fcb614eb7565b6001841615614fd957908102905b60019390931c928002614fb0565b935093915050565b600082614ffe57506001611a50565b8161500b57506000611a50565b8160018114615021576002811461502b57615047565b6001915050611a50565b60ff84111561503c5761503c614eb7565b50506001821b611a50565b5060208310610133831016604e8410600b841016171561506a575081810a611a50565b6150776000198484614fac565b806000190482111561508b5761508b614eb7565b029392505050565b60006133048383614fef565b6001600160801b038281168282160390811115611a5057611a50614eb7565b6001600160801b038181168382160190811115611a5057611a50614eb7565b60005b838110156150f85781810151838201526020016150e0565b50506000910152565b600082516151138184602087016150dd565b9190910192915050565b602081526000825180602084015261513c8160408501602087016150dd565b601f01601f1916919091016040019291505056fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122087f0c7c2ae81c28a8a454740a4486d0445606a5b1d80250b4aef44918d20849664736f6c634300081c0033", "libraries": {}, "devdoc": { "author": "Origin Protocol Inc", @@ -1518,6 +1518,9 @@ "yield": "amount of expected yield" } }, + "rebase()": { + "details": "Restricted to the Operator, Strategist or Governor." + }, "removeStrategy(address)": { "params": { "_addr": "Address of the strategy to remove" @@ -1552,14 +1555,14 @@ "_dripDuration": "Time in seconds to target a constant yield rate" } }, - "setRebaseRateMax(uint256)": { + "setOperatorAddr(address)": { "params": { - "apr": "in 1e18 notation. 3 * 1e18 = 3% APR" + "_operator": "New operator address. May be set to the zero address to disable operator-initiated rebases." } }, - "setRebaseThreshold(uint256)": { + "setRebaseRateMax(uint256)": { "params": { - "_threshold": "OToken amount with 18 fixed decimals." + "apr": "in 1e18 notation. 3 * 1e18 = 3% APR" } }, "setStrategistAddr(address)": { @@ -1693,6 +1696,9 @@ "oUSD()": { "notice": "Deprecated: use `oToken()` instead." }, + "operatorAddr()": { + "notice": "Address authorized to call `rebase()` directly. The Governor and Strategist are always allowed in addition to this address." + }, "pauseCapital()": { "notice": "Set the deposit paused flag to true to prevent capital movement." }, @@ -1714,9 +1720,6 @@ "rebasePerSecondTarget()": { "notice": "target rebase rate limit, based on past rates and funds available." }, - "rebaseThreshold()": { - "notice": "OToken mints over this amount automatically rebase. 18 decimals." - }, "removeStrategy(address)": { "notice": "Remove a strategy from the Vault." }, @@ -1738,12 +1741,12 @@ "setMaxSupplyDiff(uint256)": { "notice": "Sets the maximum allowable difference between total supply and asset' value." }, + "setOperatorAddr(address)": { + "notice": "Set the address authorized to call `rebase()`." + }, "setRebaseRateMax(uint256)": { "notice": "Set a yield streaming max rate. This spreads yield over time if it is above the max rate. This is a per rebase APR which due to compounding differs from the yearly APR. Governance should consider this fact when picking a desired APR" }, - "setRebaseThreshold(uint256)": { - "notice": "Set a minimum amount of OTokens in a mint or redeem that triggers a rebase" - }, "setStrategistAddr(address)": { "notice": "Set address of Strategist" }, @@ -1810,7 +1813,7 @@ "storageLayout": { "storage": [ { - "astId": 59818, + "astId": 42033, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "initialized", "offset": 0, @@ -1818,7 +1821,7 @@ "type": "t_bool" }, { - "astId": 59821, + "astId": 42036, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "initializing", "offset": 1, @@ -1826,7 +1829,7 @@ "type": "t_bool" }, { - "astId": 59861, + "astId": 42076, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "______gap", "offset": 0, @@ -1834,7 +1837,7 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 63565, + "astId": 45777, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "_deprecated_assets", "offset": 0, @@ -1842,7 +1845,7 @@ "type": "t_uint256" }, { - "astId": 63569, + "astId": 45781, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "_deprecated_allAssets", "offset": 0, @@ -1850,15 +1853,15 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 63580, + "astId": 45792, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "strategies", "offset": 0, "slot": "53", - "type": "t_mapping(t_address,t_struct(Strategy)63574_storage)" + "type": "t_mapping(t_address,t_struct(Strategy)45786_storage)" }, { - "astId": 63584, + "astId": 45796, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "allStrategies", "offset": 0, @@ -1866,7 +1869,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 63587, + "astId": 45799, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "_deprecated_priceProvider", "offset": 0, @@ -1874,7 +1877,7 @@ "type": "t_address" }, { - "astId": 63590, + "astId": 45802, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "rebasePaused", "offset": 20, @@ -1882,7 +1885,7 @@ "type": "t_bool" }, { - "astId": 63593, + "astId": 45805, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "capitalPaused", "offset": 21, @@ -1890,7 +1893,7 @@ "type": "t_bool" }, { - "astId": 63596, + "astId": 45808, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "_deprecated_redeemFeeBps", "offset": 0, @@ -1898,7 +1901,7 @@ "type": "t_uint256" }, { - "astId": 63599, + "astId": 45811, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "vaultBuffer", "offset": 0, @@ -1906,7 +1909,7 @@ "type": "t_uint256" }, { - "astId": 63602, + "astId": 45814, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "autoAllocateThreshold", "offset": 0, @@ -1914,23 +1917,23 @@ "type": "t_uint256" }, { - "astId": 63605, + "astId": 45817, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", - "label": "rebaseThreshold", + "label": "__deprecatedRebaseThreshold", "offset": 0, "slot": "59", "type": "t_uint256" }, { - "astId": 63609, + "astId": 45821, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "oToken", "offset": 0, "slot": "60", - "type": "t_contract(OUSD)58565" + "type": "t_contract(OUSD)41354" }, { - "astId": 63616, + "astId": 45828, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "_deprecated_rebaseHooksAddr", "offset": 0, @@ -1938,7 +1941,7 @@ "type": "t_address" }, { - "astId": 63623, + "astId": 45835, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "_deprecated_uniswapAddr", "offset": 0, @@ -1946,7 +1949,7 @@ "type": "t_address" }, { - "astId": 63630, + "astId": 45842, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "strategistAddr", "offset": 0, @@ -1954,7 +1957,7 @@ "type": "t_address" }, { - "astId": 63633, + "astId": 45845, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "_deprecated_assetDefaultStrategies", "offset": 0, @@ -1962,7 +1965,7 @@ "type": "t_uint256" }, { - "astId": 63636, + "astId": 45848, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "maxSupplyDiff", "offset": 0, @@ -1970,7 +1973,7 @@ "type": "t_uint256" }, { - "astId": 63639, + "astId": 45851, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "trusteeAddress", "offset": 0, @@ -1978,7 +1981,7 @@ "type": "t_address" }, { - "astId": 63642, + "astId": 45854, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "trusteeFeeBps", "offset": 0, @@ -1986,7 +1989,7 @@ "type": "t_uint256" }, { - "astId": 63646, + "astId": 45858, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "_deprecated_swapTokens", "offset": 0, @@ -1994,7 +1997,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 63649, + "astId": 45861, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "_deprecated_ousdMetaStrategy", "offset": 0, @@ -2002,7 +2005,7 @@ "type": "t_address" }, { - "astId": 63652, + "astId": 45864, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "_deprecated_netOusdMintedForStrategy", "offset": 0, @@ -2010,7 +2013,7 @@ "type": "t_int256" }, { - "astId": 63655, + "astId": 45867, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "_deprecated_netOusdMintForStrategyThreshold", "offset": 0, @@ -2018,7 +2021,7 @@ "type": "t_uint256" }, { - "astId": 63657, + "astId": 45869, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "_deprecated_swapConfig", "offset": 0, @@ -2026,7 +2029,7 @@ "type": "t_uint256" }, { - "astId": 63661, + "astId": 45873, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "isMintWhitelistedStrategy", "offset": 0, @@ -2034,7 +2037,7 @@ "type": "t_mapping(t_address,t_bool)" }, { - "astId": 63664, + "astId": 45876, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "_deprecated_dripper", "offset": 0, @@ -2042,23 +2045,23 @@ "type": "t_address" }, { - "astId": 63678, + "astId": 45890, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "withdrawalQueueMetadata", "offset": 0, "slot": "75", - "type": "t_struct(WithdrawalQueueMetadata)63674_storage" + "type": "t_struct(WithdrawalQueueMetadata)45886_storage" }, { - "astId": 63695, + "astId": 45907, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "withdrawalRequests", "offset": 0, "slot": "77", - "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)63689_storage)" + "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)45901_storage)" }, { - "astId": 63698, + "astId": 45910, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "withdrawalClaimDelay", "offset": 0, @@ -2066,7 +2069,7 @@ "type": "t_uint256" }, { - "astId": 63701, + "astId": 45913, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "lastRebase", "offset": 0, @@ -2074,7 +2077,7 @@ "type": "t_uint64" }, { - "astId": 63704, + "astId": 45916, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "dripDuration", "offset": 8, @@ -2082,7 +2085,7 @@ "type": "t_uint64" }, { - "astId": 63707, + "astId": 45919, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "rebasePerSecondMax", "offset": 16, @@ -2090,7 +2093,7 @@ "type": "t_uint64" }, { - "astId": 63710, + "astId": 45922, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "rebasePerSecondTarget", "offset": 24, @@ -2098,7 +2101,7 @@ "type": "t_uint64" }, { - "astId": 63724, + "astId": 45936, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "defaultStrategy", "offset": 0, @@ -2106,15 +2109,23 @@ "type": "t_address" }, { - "astId": 63728, + "astId": 45939, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", - "label": "__gap", + "label": "operatorAddr", "offset": 0, "slot": "81", - "type": "t_array(t_uint256)42_storage" + "type": "t_address" + }, + { + "astId": 45943, + "contract": "contracts/vault/OUSDVault.sol:OUSDVault", + "label": "__gap", + "offset": 0, + "slot": "82", + "type": "t_array(t_uint256)41_storage" }, { - "astId": 63731, + "astId": 45946, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "_deprecated_wethAssetIndex", "offset": 0, @@ -2134,11 +2145,11 @@ "label": "address[]", "numberOfBytes": "32" }, - "t_array(t_uint256)42_storage": { + "t_array(t_uint256)41_storage": { "base": "t_uint256", "encoding": "inplace", - "label": "uint256[42]", - "numberOfBytes": "1344" + "label": "uint256[41]", + "numberOfBytes": "1312" }, "t_array(t_uint256)50_storage": { "base": "t_uint256", @@ -2151,7 +2162,7 @@ "label": "bool", "numberOfBytes": "1" }, - "t_contract(OUSD)58565": { + "t_contract(OUSD)41354": { "encoding": "inplace", "label": "contract OUSD", "numberOfBytes": "20" @@ -2168,26 +2179,26 @@ "numberOfBytes": "32", "value": "t_bool" }, - "t_mapping(t_address,t_struct(Strategy)63574_storage)": { + "t_mapping(t_address,t_struct(Strategy)45786_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct VaultStorage.Strategy)", "numberOfBytes": "32", - "value": "t_struct(Strategy)63574_storage" + "value": "t_struct(Strategy)45786_storage" }, - "t_mapping(t_uint256,t_struct(WithdrawalRequest)63689_storage)": { + "t_mapping(t_uint256,t_struct(WithdrawalRequest)45901_storage)": { "encoding": "mapping", "key": "t_uint256", "label": "mapping(uint256 => struct VaultStorage.WithdrawalRequest)", "numberOfBytes": "32", - "value": "t_struct(WithdrawalRequest)63689_storage" + "value": "t_struct(WithdrawalRequest)45901_storage" }, - "t_struct(Strategy)63574_storage": { + "t_struct(Strategy)45786_storage": { "encoding": "inplace", "label": "struct VaultStorage.Strategy", "members": [ { - "astId": 63571, + "astId": 45783, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "isSupported", "offset": 0, @@ -2195,7 +2206,7 @@ "type": "t_bool" }, { - "astId": 63573, + "astId": 45785, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "_deprecated", "offset": 0, @@ -2205,12 +2216,12 @@ ], "numberOfBytes": "64" }, - "t_struct(WithdrawalQueueMetadata)63674_storage": { + "t_struct(WithdrawalQueueMetadata)45886_storage": { "encoding": "inplace", "label": "struct VaultStorage.WithdrawalQueueMetadata", "members": [ { - "astId": 63667, + "astId": 45879, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "queued", "offset": 0, @@ -2218,7 +2229,7 @@ "type": "t_uint128" }, { - "astId": 63669, + "astId": 45881, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "claimable", "offset": 16, @@ -2226,7 +2237,7 @@ "type": "t_uint128" }, { - "astId": 63671, + "astId": 45883, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "claimed", "offset": 0, @@ -2234,7 +2245,7 @@ "type": "t_uint128" }, { - "astId": 63673, + "astId": 45885, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "nextWithdrawalIndex", "offset": 16, @@ -2244,12 +2255,12 @@ ], "numberOfBytes": "64" }, - "t_struct(WithdrawalRequest)63689_storage": { + "t_struct(WithdrawalRequest)45901_storage": { "encoding": "inplace", "label": "struct VaultStorage.WithdrawalRequest", "members": [ { - "astId": 63680, + "astId": 45892, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "withdrawer", "offset": 0, @@ -2257,7 +2268,7 @@ "type": "t_address" }, { - "astId": 63682, + "astId": 45894, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "claimed", "offset": 20, @@ -2265,7 +2276,7 @@ "type": "t_bool" }, { - "astId": 63684, + "astId": 45896, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "timestamp", "offset": 21, @@ -2273,7 +2284,7 @@ "type": "t_uint40" }, { - "astId": 63686, + "astId": 45898, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "amount", "offset": 0, @@ -2281,7 +2292,7 @@ "type": "t_uint128" }, { - "astId": 63688, + "astId": 45900, "contract": "contracts/vault/OUSDVault.sol:OUSDVault", "label": "queued", "offset": 16, diff --git a/contracts/deployments/mainnet/solcInputs/f4384e86fd2a870879603d18d53c5b16.json b/contracts/deployments/mainnet/solcInputs/f4384e86fd2a870879603d18d53c5b16.json new file mode 100644 index 0000000000..0a3f9df551 --- /dev/null +++ b/contracts/deployments/mainnet/solcInputs/f4384e86fd2a870879603d18d53c5b16.json @@ -0,0 +1,537 @@ +{ + "language": "Solidity", + "sources": { + "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {Client} from \"../libraries/Client.sol\";\n\ninterface IRouterClient {\n error UnsupportedDestinationChain(uint64 destChainSelector);\n error InsufficientFeeTokenAmount();\n error InvalidMsgValue();\n\n /// @notice Checks if the given chain ID is supported for sending/receiving.\n /// @param chainSelector The chain to check.\n /// @return supported is true if it is supported, false if not.\n function isChainSupported(uint64 chainSelector) external view returns (bool supported);\n\n /// @notice Gets a list of all supported tokens which can be sent or received\n /// to/from a given chain id.\n /// @param chainSelector The chainSelector.\n /// @return tokens The addresses of all tokens that are supported.\n function getSupportedTokens(uint64 chainSelector) external view returns (address[] memory tokens);\n\n /// @param destinationChainSelector The destination chainSelector\n /// @param message The cross-chain CCIP message including data and/or tokens\n /// @return fee returns execution fee for the message\n /// delivery to destination chain, denominated in the feeToken specified in the message.\n /// @dev Reverts with appropriate reason upon invalid message.\n function getFee(\n uint64 destinationChainSelector,\n Client.EVM2AnyMessage memory message\n ) external view returns (uint256 fee);\n\n /// @notice Request a message to be sent to the destination chain\n /// @param destinationChainSelector The destination chain ID\n /// @param message The cross-chain CCIP message including data and/or tokens\n /// @return messageId The message ID\n /// @dev Note if msg.value is larger than the required fee (from getFee) we accept\n /// the overpayment with no refund.\n /// @dev Reverts with appropriate reason upon invalid message.\n function ccipSend(\n uint64 destinationChainSelector,\n Client.EVM2AnyMessage calldata message\n ) external payable returns (bytes32);\n}\n" + }, + "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// End consumer library.\nlibrary Client {\n /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.\n struct EVMTokenAmount {\n address token; // token address on the local chain.\n uint256 amount; // Amount of tokens.\n }\n\n struct Any2EVMMessage {\n bytes32 messageId; // MessageId corresponding to ccipSend on source.\n uint64 sourceChainSelector; // Source chain selector.\n bytes sender; // abi.decode(sender) if coming from an EVM chain.\n bytes data; // payload sent in original message.\n EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation.\n }\n\n // If extraArgs is empty bytes, the default is 200k gas limit.\n struct EVM2AnyMessage {\n bytes receiver; // abi.encode(receiver address) for dest EVM chains\n bytes data; // Data payload\n EVMTokenAmount[] tokenAmounts; // Token transfers\n address feeToken; // Address of feeToken. address(0) means you will send msg.value.\n bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV1)\n }\n\n // bytes4(keccak256(\"CCIP EVMExtraArgsV1\"));\n bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9;\n struct EVMExtraArgsV1 {\n uint256 gasLimit;\n }\n\n function _argsToBytes(EVMExtraArgsV1 memory extraArgs) internal pure returns (bytes memory bts) {\n return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs);\n }\n}\n" + }, + "@layerzerolabs/lz-evm-messagelib-v2/contracts/libs/ExecutorOptions.sol": { + "content": "// SPDX-License-Identifier: LZBL-1.2\n\npragma solidity ^0.8.20;\n\nimport \"@layerzerolabs/lz-evm-protocol-v2/contracts/libs/CalldataBytesLib.sol\";\n\nlibrary ExecutorOptions {\n using CalldataBytesLib for bytes;\n\n uint8 internal constant WORKER_ID = 1;\n\n uint8 internal constant OPTION_TYPE_LZRECEIVE = 1;\n uint8 internal constant OPTION_TYPE_NATIVE_DROP = 2;\n uint8 internal constant OPTION_TYPE_LZCOMPOSE = 3;\n uint8 internal constant OPTION_TYPE_ORDERED_EXECUTION = 4;\n uint8 internal constant OPTION_TYPE_LZREAD = 5;\n\n error Executor_InvalidLzReceiveOption();\n error Executor_InvalidNativeDropOption();\n error Executor_InvalidLzComposeOption();\n error Executor_InvalidLzReadOption();\n\n /// @dev decode the next executor option from the options starting from the specified cursor\n /// @param _options [executor_id][executor_option][executor_id][executor_option]...\n /// executor_option = [option_size][option_type][option]\n /// option_size = len(option_type) + len(option)\n /// executor_id: uint8, option_size: uint16, option_type: uint8, option: bytes\n /// @param _cursor the cursor to start decoding from\n /// @return optionType the type of the option\n /// @return option the option of the executor\n /// @return cursor the cursor to start decoding the next executor option\n function nextExecutorOption(\n bytes calldata _options,\n uint256 _cursor\n ) internal pure returns (uint8 optionType, bytes calldata option, uint256 cursor) {\n unchecked {\n // skip worker id\n cursor = _cursor + 1;\n\n // read option size\n uint16 size = _options.toU16(cursor);\n cursor += 2;\n\n // read option type\n optionType = _options.toU8(cursor);\n\n // startCursor and endCursor are used to slice the option from _options\n uint256 startCursor = cursor + 1; // skip option type\n uint256 endCursor = cursor + size;\n option = _options[startCursor:endCursor];\n cursor += size;\n }\n }\n\n function decodeLzReceiveOption(bytes calldata _option) internal pure returns (uint128 gas, uint128 value) {\n if (_option.length != 16 && _option.length != 32) revert Executor_InvalidLzReceiveOption();\n gas = _option.toU128(0);\n value = _option.length == 32 ? _option.toU128(16) : 0;\n }\n\n function decodeNativeDropOption(bytes calldata _option) internal pure returns (uint128 amount, bytes32 receiver) {\n if (_option.length != 48) revert Executor_InvalidNativeDropOption();\n amount = _option.toU128(0);\n receiver = _option.toB32(16);\n }\n\n function decodeLzComposeOption(\n bytes calldata _option\n ) internal pure returns (uint16 index, uint128 gas, uint128 value) {\n if (_option.length != 18 && _option.length != 34) revert Executor_InvalidLzComposeOption();\n index = _option.toU16(0);\n gas = _option.toU128(2);\n value = _option.length == 34 ? _option.toU128(18) : 0;\n }\n\n function decodeLzReadOption(\n bytes calldata _option\n ) internal pure returns (uint128 gas, uint32 calldataSize, uint128 value) {\n if (_option.length != 20 && _option.length != 36) revert Executor_InvalidLzReadOption();\n gas = _option.toU128(0);\n calldataSize = _option.toU32(16);\n value = _option.length == 36 ? _option.toU128(20) : 0;\n }\n\n function encodeLzReceiveOption(uint128 _gas, uint128 _value) internal pure returns (bytes memory) {\n return _value == 0 ? abi.encodePacked(_gas) : abi.encodePacked(_gas, _value);\n }\n\n function encodeNativeDropOption(uint128 _amount, bytes32 _receiver) internal pure returns (bytes memory) {\n return abi.encodePacked(_amount, _receiver);\n }\n\n function encodeLzComposeOption(uint16 _index, uint128 _gas, uint128 _value) internal pure returns (bytes memory) {\n return _value == 0 ? abi.encodePacked(_index, _gas) : abi.encodePacked(_index, _gas, _value);\n }\n\n function encodeLzReadOption(\n uint128 _gas,\n uint32 _calldataSize,\n uint128 _value\n ) internal pure returns (bytes memory) {\n return _value == 0 ? abi.encodePacked(_gas, _calldataSize) : abi.encodePacked(_gas, _calldataSize, _value);\n }\n}\n" + }, + "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/libs/DVNOptions.sol": { + "content": "// SPDX-License-Identifier: LZBL-1.2\n\npragma solidity ^0.8.20;\n\nimport { BytesLib } from \"solidity-bytes-utils/contracts/BytesLib.sol\";\n\nimport { BitMap256 } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/BitMaps.sol\";\nimport { CalldataBytesLib } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/libs/CalldataBytesLib.sol\";\n\nlibrary DVNOptions {\n using CalldataBytesLib for bytes;\n using BytesLib for bytes;\n\n uint8 internal constant WORKER_ID = 2;\n uint8 internal constant OPTION_TYPE_PRECRIME = 1;\n\n error DVN_InvalidDVNIdx();\n error DVN_InvalidDVNOptions(uint256 cursor);\n\n /// @dev group dvn options by its idx\n /// @param _options [dvn_id][dvn_option][dvn_id][dvn_option]...\n /// dvn_option = [option_size][dvn_idx][option_type][option]\n /// option_size = len(dvn_idx) + len(option_type) + len(option)\n /// dvn_id: uint8, dvn_idx: uint8, option_size: uint16, option_type: uint8, option: bytes\n /// @return dvnOptions the grouped options, still share the same format of _options\n /// @return dvnIndices the dvn indices\n function groupDVNOptionsByIdx(\n bytes memory _options\n ) internal pure returns (bytes[] memory dvnOptions, uint8[] memory dvnIndices) {\n if (_options.length == 0) return (dvnOptions, dvnIndices);\n\n uint8 numDVNs = getNumDVNs(_options);\n\n // if there is only 1 dvn, we can just return the whole options\n if (numDVNs == 1) {\n dvnOptions = new bytes[](1);\n dvnOptions[0] = _options;\n\n dvnIndices = new uint8[](1);\n dvnIndices[0] = _options.toUint8(3); // dvn idx\n return (dvnOptions, dvnIndices);\n }\n\n // otherwise, we need to group the options by dvn_idx\n dvnIndices = new uint8[](numDVNs);\n dvnOptions = new bytes[](numDVNs);\n unchecked {\n uint256 cursor = 0;\n uint256 start = 0;\n uint8 lastDVNIdx = 255; // 255 is an invalid dvn_idx\n\n while (cursor < _options.length) {\n ++cursor; // skip worker_id\n\n // optionLength asserted in getNumDVNs (skip check)\n uint16 optionLength = _options.toUint16(cursor);\n cursor += 2;\n\n // dvnIdx asserted in getNumDVNs (skip check)\n uint8 dvnIdx = _options.toUint8(cursor);\n\n // dvnIdx must equal to the lastDVNIdx for the first option\n // so it is always skipped in the first option\n // this operation slices out options whenever the scan finds a different lastDVNIdx\n if (lastDVNIdx == 255) {\n lastDVNIdx = dvnIdx;\n } else if (dvnIdx != lastDVNIdx) {\n uint256 len = cursor - start - 3; // 3 is for worker_id and option_length\n bytes memory opt = _options.slice(start, len);\n _insertDVNOptions(dvnOptions, dvnIndices, lastDVNIdx, opt);\n\n // reset the start and lastDVNIdx\n start += len;\n lastDVNIdx = dvnIdx;\n }\n\n cursor += optionLength;\n }\n\n // skip check the cursor here because the cursor is asserted in getNumDVNs\n // if we have reached the end of the options, we need to process the last dvn\n uint256 size = cursor - start;\n bytes memory op = _options.slice(start, size);\n _insertDVNOptions(dvnOptions, dvnIndices, lastDVNIdx, op);\n\n // revert dvnIndices to start from 0\n for (uint8 i = 0; i < numDVNs; ++i) {\n --dvnIndices[i];\n }\n }\n }\n\n function _insertDVNOptions(\n bytes[] memory _dvnOptions,\n uint8[] memory _dvnIndices,\n uint8 _dvnIdx,\n bytes memory _newOptions\n ) internal pure {\n // dvnIdx starts from 0 but default value of dvnIndices is 0,\n // so we tell if the slot is empty by adding 1 to dvnIdx\n if (_dvnIdx == 255) revert DVN_InvalidDVNIdx();\n uint8 dvnIdxAdj = _dvnIdx + 1;\n\n for (uint256 j = 0; j < _dvnIndices.length; ++j) {\n uint8 index = _dvnIndices[j];\n if (dvnIdxAdj == index) {\n _dvnOptions[j] = abi.encodePacked(_dvnOptions[j], _newOptions);\n break;\n } else if (index == 0) {\n // empty slot, that means it is the first time we see this dvn\n _dvnIndices[j] = dvnIdxAdj;\n _dvnOptions[j] = _newOptions;\n break;\n }\n }\n }\n\n /// @dev get the number of unique dvns\n /// @param _options the format is the same as groupDVNOptionsByIdx\n function getNumDVNs(bytes memory _options) internal pure returns (uint8 numDVNs) {\n uint256 cursor = 0;\n BitMap256 bitmap;\n\n // find number of unique dvn_idx\n unchecked {\n while (cursor < _options.length) {\n ++cursor; // skip worker_id\n\n uint16 optionLength = _options.toUint16(cursor);\n cursor += 2;\n if (optionLength < 2) revert DVN_InvalidDVNOptions(cursor); // at least 1 byte for dvn_idx and 1 byte for option_type\n\n uint8 dvnIdx = _options.toUint8(cursor);\n\n // if dvnIdx is not set, increment numDVNs\n // max num of dvns is 255, 255 is an invalid dvn_idx\n // The order of the dvnIdx is not required to be sequential, as enforcing the order may weaken\n // the composability of the options. e.g. if we refrain from enforcing the order, an OApp that has\n // already enforced certain options can append additional options to the end of the enforced\n // ones without restrictions.\n if (dvnIdx == 255) revert DVN_InvalidDVNIdx();\n if (!bitmap.get(dvnIdx)) {\n ++numDVNs;\n bitmap = bitmap.set(dvnIdx);\n }\n\n cursor += optionLength;\n }\n }\n if (cursor != _options.length) revert DVN_InvalidDVNOptions(cursor);\n }\n\n /// @dev decode the next dvn option from _options starting from the specified cursor\n /// @param _options the format is the same as groupDVNOptionsByIdx\n /// @param _cursor the cursor to start decoding\n /// @return optionType the type of the option\n /// @return option the option\n /// @return cursor the cursor to start decoding the next option\n function nextDVNOption(\n bytes calldata _options,\n uint256 _cursor\n ) internal pure returns (uint8 optionType, bytes calldata option, uint256 cursor) {\n unchecked {\n // skip worker id\n cursor = _cursor + 1;\n\n // read option size\n uint16 size = _options.toU16(cursor);\n cursor += 2;\n\n // read option type\n optionType = _options.toU8(cursor + 1); // skip dvn_idx\n\n // startCursor and endCursor are used to slice the option from _options\n uint256 startCursor = cursor + 2; // skip option type and dvn_idx\n uint256 endCursor = cursor + size;\n option = _options[startCursor:endCursor];\n cursor += size;\n }\n }\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\nimport { IMessageLibManager } from \"./IMessageLibManager.sol\";\nimport { IMessagingComposer } from \"./IMessagingComposer.sol\";\nimport { IMessagingChannel } from \"./IMessagingChannel.sol\";\nimport { IMessagingContext } from \"./IMessagingContext.sol\";\n\nstruct MessagingParams {\n uint32 dstEid;\n bytes32 receiver;\n bytes message;\n bytes options;\n bool payInLzToken;\n}\n\nstruct MessagingReceipt {\n bytes32 guid;\n uint64 nonce;\n MessagingFee fee;\n}\n\nstruct MessagingFee {\n uint256 nativeFee;\n uint256 lzTokenFee;\n}\n\nstruct Origin {\n uint32 srcEid;\n bytes32 sender;\n uint64 nonce;\n}\n\ninterface ILayerZeroEndpointV2 is IMessageLibManager, IMessagingComposer, IMessagingChannel, IMessagingContext {\n event PacketSent(bytes encodedPayload, bytes options, address sendLibrary);\n\n event PacketVerified(Origin origin, address receiver, bytes32 payloadHash);\n\n event PacketDelivered(Origin origin, address receiver);\n\n event LzReceiveAlert(\n address indexed receiver,\n address indexed executor,\n Origin origin,\n bytes32 guid,\n uint256 gas,\n uint256 value,\n bytes message,\n bytes extraData,\n bytes reason\n );\n\n event LzTokenSet(address token);\n\n event DelegateSet(address sender, address delegate);\n\n function quote(MessagingParams calldata _params, address _sender) external view returns (MessagingFee memory);\n\n function send(\n MessagingParams calldata _params,\n address _refundAddress\n ) external payable returns (MessagingReceipt memory);\n\n function verify(Origin calldata _origin, address _receiver, bytes32 _payloadHash) external;\n\n function verifiable(Origin calldata _origin, address _receiver) external view returns (bool);\n\n function initializable(Origin calldata _origin, address _receiver) external view returns (bool);\n\n function lzReceive(\n Origin calldata _origin,\n address _receiver,\n bytes32 _guid,\n bytes calldata _message,\n bytes calldata _extraData\n ) external payable;\n\n // oapp can burn messages partially by calling this function with its own business logic if messages are verified in order\n function clear(address _oapp, Origin calldata _origin, bytes32 _guid, bytes calldata _message) external;\n\n function setLzToken(address _lzToken) external;\n\n function lzToken() external view returns (address);\n\n function nativeToken() external view returns (address);\n\n function setDelegate(address _delegate) external;\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLibManager.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\nstruct SetConfigParam {\n uint32 eid;\n uint32 configType;\n bytes config;\n}\n\ninterface IMessageLibManager {\n struct Timeout {\n address lib;\n uint256 expiry;\n }\n\n event LibraryRegistered(address newLib);\n event DefaultSendLibrarySet(uint32 eid, address newLib);\n event DefaultReceiveLibrarySet(uint32 eid, address newLib);\n event DefaultReceiveLibraryTimeoutSet(uint32 eid, address oldLib, uint256 expiry);\n event SendLibrarySet(address sender, uint32 eid, address newLib);\n event ReceiveLibrarySet(address receiver, uint32 eid, address newLib);\n event ReceiveLibraryTimeoutSet(address receiver, uint32 eid, address oldLib, uint256 timeout);\n\n function registerLibrary(address _lib) external;\n\n function isRegisteredLibrary(address _lib) external view returns (bool);\n\n function getRegisteredLibraries() external view returns (address[] memory);\n\n function setDefaultSendLibrary(uint32 _eid, address _newLib) external;\n\n function defaultSendLibrary(uint32 _eid) external view returns (address);\n\n function setDefaultReceiveLibrary(uint32 _eid, address _newLib, uint256 _gracePeriod) external;\n\n function defaultReceiveLibrary(uint32 _eid) external view returns (address);\n\n function setDefaultReceiveLibraryTimeout(uint32 _eid, address _lib, uint256 _expiry) external;\n\n function defaultReceiveLibraryTimeout(uint32 _eid) external view returns (address lib, uint256 expiry);\n\n function isSupportedEid(uint32 _eid) external view returns (bool);\n\n function isValidReceiveLibrary(address _receiver, uint32 _eid, address _lib) external view returns (bool);\n\n /// ------------------- OApp interfaces -------------------\n function setSendLibrary(address _oapp, uint32 _eid, address _newLib) external;\n\n function getSendLibrary(address _sender, uint32 _eid) external view returns (address lib);\n\n function isDefaultSendLibrary(address _sender, uint32 _eid) external view returns (bool);\n\n function setReceiveLibrary(address _oapp, uint32 _eid, address _newLib, uint256 _gracePeriod) external;\n\n function getReceiveLibrary(address _receiver, uint32 _eid) external view returns (address lib, bool isDefault);\n\n function setReceiveLibraryTimeout(address _oapp, uint32 _eid, address _lib, uint256 _expiry) external;\n\n function receiveLibraryTimeout(address _receiver, uint32 _eid) external view returns (address lib, uint256 expiry);\n\n function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external;\n\n function getConfig(\n address _oapp,\n address _lib,\n uint32 _eid,\n uint32 _configType\n ) external view returns (bytes memory config);\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessagingChannel.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\ninterface IMessagingChannel {\n event InboundNonceSkipped(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce);\n event PacketNilified(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash);\n event PacketBurnt(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash);\n\n function eid() external view returns (uint32);\n\n // this is an emergency function if a message cannot be verified for some reasons\n // required to provide _nextNonce to avoid race condition\n function skip(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce) external;\n\n function nilify(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external;\n\n function burn(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external;\n\n function nextGuid(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (bytes32);\n\n function inboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64);\n\n function outboundNonce(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (uint64);\n\n function inboundPayloadHash(\n address _receiver,\n uint32 _srcEid,\n bytes32 _sender,\n uint64 _nonce\n ) external view returns (bytes32);\n\n function lazyInboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64);\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessagingComposer.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\ninterface IMessagingComposer {\n event ComposeSent(address from, address to, bytes32 guid, uint16 index, bytes message);\n event ComposeDelivered(address from, address to, bytes32 guid, uint16 index);\n event LzComposeAlert(\n address indexed from,\n address indexed to,\n address indexed executor,\n bytes32 guid,\n uint16 index,\n uint256 gas,\n uint256 value,\n bytes message,\n bytes extraData,\n bytes reason\n );\n\n function composeQueue(\n address _from,\n address _to,\n bytes32 _guid,\n uint16 _index\n ) external view returns (bytes32 messageHash);\n\n function sendCompose(address _to, bytes32 _guid, uint16 _index, bytes calldata _message) external;\n\n function lzCompose(\n address _from,\n address _to,\n bytes32 _guid,\n uint16 _index,\n bytes calldata _message,\n bytes calldata _extraData\n ) external payable;\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessagingContext.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\ninterface IMessagingContext {\n function isSendingMessage() external view returns (bool);\n\n function getSendContext() external view returns (uint32 dstEid, address sender);\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/CalldataBytesLib.sol": { + "content": "// SPDX-License-Identifier: LZBL-1.2\n\npragma solidity ^0.8.20;\n\nlibrary CalldataBytesLib {\n function toU8(bytes calldata _bytes, uint256 _start) internal pure returns (uint8) {\n return uint8(_bytes[_start]);\n }\n\n function toU16(bytes calldata _bytes, uint256 _start) internal pure returns (uint16) {\n unchecked {\n uint256 end = _start + 2;\n return uint16(bytes2(_bytes[_start:end]));\n }\n }\n\n function toU32(bytes calldata _bytes, uint256 _start) internal pure returns (uint32) {\n unchecked {\n uint256 end = _start + 4;\n return uint32(bytes4(_bytes[_start:end]));\n }\n }\n\n function toU64(bytes calldata _bytes, uint256 _start) internal pure returns (uint64) {\n unchecked {\n uint256 end = _start + 8;\n return uint64(bytes8(_bytes[_start:end]));\n }\n }\n\n function toU128(bytes calldata _bytes, uint256 _start) internal pure returns (uint128) {\n unchecked {\n uint256 end = _start + 16;\n return uint128(bytes16(_bytes[_start:end]));\n }\n }\n\n function toU256(bytes calldata _bytes, uint256 _start) internal pure returns (uint256) {\n unchecked {\n uint256 end = _start + 32;\n return uint256(bytes32(_bytes[_start:end]));\n }\n }\n\n function toAddr(bytes calldata _bytes, uint256 _start) internal pure returns (address) {\n unchecked {\n uint256 end = _start + 20;\n return address(bytes20(_bytes[_start:end]));\n }\n }\n\n function toB32(bytes calldata _bytes, uint256 _start) internal pure returns (bytes32) {\n unchecked {\n uint256 end = _start + 32;\n return bytes32(_bytes[_start:end]);\n }\n }\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/BitMaps.sol": { + "content": "// SPDX-License-Identifier: MIT\n\n// modified from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/structs/BitMaps.sol\npragma solidity ^0.8.20;\n\ntype BitMap256 is uint256;\n\nusing BitMaps for BitMap256 global;\n\nlibrary BitMaps {\n /**\n * @dev Returns whether the bit at `index` is set.\n */\n function get(BitMap256 bitmap, uint8 index) internal pure returns (bool) {\n uint256 mask = 1 << index;\n return BitMap256.unwrap(bitmap) & mask != 0;\n }\n\n /**\n * @dev Sets the bit at `index`.\n */\n function set(BitMap256 bitmap, uint8 index) internal pure returns (BitMap256) {\n uint256 mask = 1 << index;\n return BitMap256.wrap(BitMap256.unwrap(bitmap) | mask);\n }\n}\n" + }, + "@layerzerolabs/oapp-evm/contracts/oapp/interfaces/IOAppCore.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { ILayerZeroEndpointV2 } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol\";\n\n/**\n * @title IOAppCore\n */\ninterface IOAppCore {\n // Custom error messages\n error OnlyPeer(uint32 eid, bytes32 sender);\n error NoPeer(uint32 eid);\n error InvalidEndpointCall();\n error InvalidDelegate();\n\n // Event emitted when a peer (OApp) is set for a corresponding endpoint\n event PeerSet(uint32 eid, bytes32 peer);\n\n /**\n * @notice Retrieves the OApp version information.\n * @return senderVersion The version of the OAppSender.sol contract.\n * @return receiverVersion The version of the OAppReceiver.sol contract.\n */\n function oAppVersion() external view returns (uint64 senderVersion, uint64 receiverVersion);\n\n /**\n * @notice Retrieves the LayerZero endpoint associated with the OApp.\n * @return iEndpoint The LayerZero endpoint as an interface.\n */\n function endpoint() external view returns (ILayerZeroEndpointV2 iEndpoint);\n\n /**\n * @notice Retrieves the peer (OApp) associated with a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @return peer The peer address (OApp instance) associated with the corresponding endpoint.\n */\n function peers(uint32 _eid) external view returns (bytes32 peer);\n\n /**\n * @notice Sets the peer address (OApp instance) for a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @param _peer The address of the peer to be associated with the corresponding endpoint.\n */\n function setPeer(uint32 _eid, bytes32 _peer) external;\n\n /**\n * @notice Sets the delegate address for the OApp Core.\n * @param _delegate The address of the delegate to be set.\n */\n function setDelegate(address _delegate) external;\n}\n" + }, + "@layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { BytesLib } from \"solidity-bytes-utils/contracts/BytesLib.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { ExecutorOptions } from \"@layerzerolabs/lz-evm-messagelib-v2/contracts/libs/ExecutorOptions.sol\";\nimport { DVNOptions } from \"@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/libs/DVNOptions.sol\";\n\n/**\n * @title OptionsBuilder\n * @dev Library for building and encoding various message options.\n */\nlibrary OptionsBuilder {\n using SafeCast for uint256;\n using BytesLib for bytes;\n\n // Constants for options types\n uint16 internal constant TYPE_1 = 1; // legacy options type 1\n uint16 internal constant TYPE_2 = 2; // legacy options type 2\n uint16 internal constant TYPE_3 = 3;\n\n // Custom error message\n error InvalidSize(uint256 max, uint256 actual);\n error InvalidOptionType(uint16 optionType);\n\n // Modifier to ensure only options of type 3 are used\n modifier onlyType3(bytes memory _options) {\n if (_options.toUint16(0) != TYPE_3) revert InvalidOptionType(_options.toUint16(0));\n _;\n }\n\n /**\n * @dev Creates a new options container with type 3.\n * @return options The newly created options container.\n */\n function newOptions() internal pure returns (bytes memory) {\n return abi.encodePacked(TYPE_3);\n }\n\n /**\n * @dev Adds an executor LZ receive option to the existing options.\n * @param _options The existing options container.\n * @param _gas The gasLimit used on the lzReceive() function in the OApp.\n * @param _value The msg.value passed to the lzReceive() function in the OApp.\n * @return options The updated options container.\n *\n * @dev When multiples of this option are added, they are summed by the executor\n * eg. if (_gas: 200k, and _value: 1 ether) AND (_gas: 100k, _value: 0.5 ether) are sent in an option to the LayerZeroEndpoint,\n * that becomes (300k, 1.5 ether) when the message is executed on the remote lzReceive() function.\n */\n function addExecutorLzReceiveOption(\n bytes memory _options,\n uint128 _gas,\n uint128 _value\n ) internal pure onlyType3(_options) returns (bytes memory) {\n bytes memory option = ExecutorOptions.encodeLzReceiveOption(_gas, _value);\n return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZRECEIVE, option);\n }\n\n /**\n * @dev Adds an executor native drop option to the existing options.\n * @param _options The existing options container.\n * @param _amount The amount for the native value that is airdropped to the 'receiver'.\n * @param _receiver The receiver address for the native drop option.\n * @return options The updated options container.\n *\n * @dev When multiples of this option are added, they are summed by the executor on the remote chain.\n */\n function addExecutorNativeDropOption(\n bytes memory _options,\n uint128 _amount,\n bytes32 _receiver\n ) internal pure onlyType3(_options) returns (bytes memory) {\n bytes memory option = ExecutorOptions.encodeNativeDropOption(_amount, _receiver);\n return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_NATIVE_DROP, option);\n }\n\n // /**\n // * @dev Adds an executor native drop option to the existing options.\n // * @param _options The existing options container.\n // * @param _amount The amount for the native value that is airdropped to the 'receiver'.\n // * @param _receiver The receiver address for the native drop option.\n // * @return options The updated options container.\n // *\n // * @dev When multiples of this option are added, they are summed by the executor on the remote chain.\n // */\n function addExecutorLzReadOption(\n bytes memory _options,\n uint128 _gas,\n uint32 _size,\n uint128 _value\n ) internal pure onlyType3(_options) returns (bytes memory) {\n bytes memory option = ExecutorOptions.encodeLzReadOption(_gas, _size, _value);\n return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZREAD, option);\n }\n\n /**\n * @dev Adds an executor LZ compose option to the existing options.\n * @param _options The existing options container.\n * @param _index The index for the lzCompose() function call.\n * @param _gas The gasLimit for the lzCompose() function call.\n * @param _value The msg.value for the lzCompose() function call.\n * @return options The updated options container.\n *\n * @dev When multiples of this option are added, they are summed PER index by the executor on the remote chain.\n * @dev If the OApp sends N lzCompose calls on the remote, you must provide N incremented indexes starting with 0.\n * ie. When your remote OApp composes (N = 3) messages, you must set this option for index 0,1,2\n */\n function addExecutorLzComposeOption(\n bytes memory _options,\n uint16 _index,\n uint128 _gas,\n uint128 _value\n ) internal pure onlyType3(_options) returns (bytes memory) {\n bytes memory option = ExecutorOptions.encodeLzComposeOption(_index, _gas, _value);\n return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZCOMPOSE, option);\n }\n\n /**\n * @dev Adds an executor ordered execution option to the existing options.\n * @param _options The existing options container.\n * @return options The updated options container.\n */\n function addExecutorOrderedExecutionOption(\n bytes memory _options\n ) internal pure onlyType3(_options) returns (bytes memory) {\n return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_ORDERED_EXECUTION, bytes(\"\"));\n }\n\n /**\n * @dev Adds a DVN pre-crime option to the existing options.\n * @param _options The existing options container.\n * @param _dvnIdx The DVN index for the pre-crime option.\n * @return options The updated options container.\n */\n function addDVNPreCrimeOption(\n bytes memory _options,\n uint8 _dvnIdx\n ) internal pure onlyType3(_options) returns (bytes memory) {\n return addDVNOption(_options, _dvnIdx, DVNOptions.OPTION_TYPE_PRECRIME, bytes(\"\"));\n }\n\n /**\n * @dev Adds an executor option to the existing options.\n * @param _options The existing options container.\n * @param _optionType The type of the executor option.\n * @param _option The encoded data for the executor option.\n * @return options The updated options container.\n */\n function addExecutorOption(\n bytes memory _options,\n uint8 _optionType,\n bytes memory _option\n ) internal pure onlyType3(_options) returns (bytes memory) {\n return\n abi.encodePacked(\n _options,\n ExecutorOptions.WORKER_ID,\n _option.length.toUint16() + 1, // +1 for optionType\n _optionType,\n _option\n );\n }\n\n /**\n * @dev Adds a DVN option to the existing options.\n * @param _options The existing options container.\n * @param _dvnIdx The DVN index for the DVN option.\n * @param _optionType The type of the DVN option.\n * @param _option The encoded data for the DVN option.\n * @return options The updated options container.\n */\n function addDVNOption(\n bytes memory _options,\n uint8 _dvnIdx,\n uint8 _optionType,\n bytes memory _option\n ) internal pure onlyType3(_options) returns (bytes memory) {\n return\n abi.encodePacked(\n _options,\n DVNOptions.WORKER_ID,\n _option.length.toUint16() + 2, // +2 for optionType and dvnIdx\n _dvnIdx,\n _optionType,\n _option\n );\n }\n\n /**\n * @dev Encodes legacy options of type 1.\n * @param _executionGas The gasLimit value passed to lzReceive().\n * @return legacyOptions The encoded legacy options.\n */\n function encodeLegacyOptionsType1(uint256 _executionGas) internal pure returns (bytes memory) {\n if (_executionGas > type(uint128).max) revert InvalidSize(type(uint128).max, _executionGas);\n return abi.encodePacked(TYPE_1, _executionGas);\n }\n\n /**\n * @dev Encodes legacy options of type 2.\n * @param _executionGas The gasLimit value passed to lzReceive().\n * @param _nativeForDst The amount of native air dropped to the receiver.\n * @param _receiver The _nativeForDst receiver address.\n * @return legacyOptions The encoded legacy options of type 2.\n */\n function encodeLegacyOptionsType2(\n uint256 _executionGas,\n uint256 _nativeForDst,\n bytes memory _receiver // @dev Use bytes instead of bytes32 in legacy type 2 for _receiver.\n ) internal pure returns (bytes memory) {\n if (_executionGas > type(uint128).max) revert InvalidSize(type(uint128).max, _executionGas);\n if (_nativeForDst > type(uint128).max) revert InvalidSize(type(uint128).max, _nativeForDst);\n if (_receiver.length > 32) revert InvalidSize(32, _receiver.length);\n return abi.encodePacked(TYPE_2, _executionGas, _nativeForDst, _receiver);\n }\n}\n" + }, + "@layerzerolabs/oapp-evm/contracts/oapp/OAppCore.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { IOAppCore, ILayerZeroEndpointV2 } from \"./interfaces/IOAppCore.sol\";\n\n/**\n * @title OAppCore\n * @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations.\n */\nabstract contract OAppCore is IOAppCore, Ownable {\n // The LayerZero endpoint associated with the given OApp\n ILayerZeroEndpointV2 public immutable endpoint;\n\n // Mapping to store peers associated with corresponding endpoints\n mapping(uint32 eid => bytes32 peer) public peers;\n\n /**\n * @dev Constructor to initialize the OAppCore with the provided endpoint and delegate.\n * @param _endpoint The address of the LOCAL Layer Zero endpoint.\n * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.\n *\n * @dev The delegate typically should be set as the owner of the contract.\n */\n constructor(address _endpoint, address _delegate) {\n endpoint = ILayerZeroEndpointV2(_endpoint);\n\n if (_delegate == address(0)) revert InvalidDelegate();\n endpoint.setDelegate(_delegate);\n }\n\n /**\n * @notice Sets the peer address (OApp instance) for a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @param _peer The address of the peer to be associated with the corresponding endpoint.\n *\n * @dev Only the owner/admin of the OApp can call this function.\n * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.\n * @dev Set this to bytes32(0) to remove the peer address.\n * @dev Peer is a bytes32 to accommodate non-evm chains.\n */\n function setPeer(uint32 _eid, bytes32 _peer) public virtual onlyOwner {\n _setPeer(_eid, _peer);\n }\n\n /**\n * @notice Sets the peer address (OApp instance) for a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @param _peer The address of the peer to be associated with the corresponding endpoint.\n *\n * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.\n * @dev Set this to bytes32(0) to remove the peer address.\n * @dev Peer is a bytes32 to accommodate non-evm chains.\n */\n function _setPeer(uint32 _eid, bytes32 _peer) internal virtual {\n peers[_eid] = _peer;\n emit PeerSet(_eid, _peer);\n }\n\n /**\n * @notice Internal function to get the peer address associated with a specific endpoint; reverts if NOT set.\n * ie. the peer is set to bytes32(0).\n * @param _eid The endpoint ID.\n * @return peer The address of the peer associated with the specified endpoint.\n */\n function _getPeerOrRevert(uint32 _eid) internal view virtual returns (bytes32) {\n bytes32 peer = peers[_eid];\n if (peer == bytes32(0)) revert NoPeer(_eid);\n return peer;\n }\n\n /**\n * @notice Sets the delegate address for the OApp.\n * @param _delegate The address of the delegate to be set.\n *\n * @dev Only the owner/admin of the OApp can call this function.\n * @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract.\n */\n function setDelegate(address _delegate) public onlyOwner {\n endpoint.setDelegate(_delegate);\n }\n}\n" + }, + "@layerzerolabs/oapp-evm/contracts/oapp/OAppSender.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { SafeERC20, IERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { MessagingParams, MessagingFee, MessagingReceipt } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol\";\nimport { OAppCore } from \"./OAppCore.sol\";\n\n/**\n * @title OAppSender\n * @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint.\n */\nabstract contract OAppSender is OAppCore {\n using SafeERC20 for IERC20;\n\n // Custom error messages\n error NotEnoughNative(uint256 msgValue);\n error LzTokenUnavailable();\n\n // @dev The version of the OAppSender implementation.\n // @dev Version is bumped when changes are made to this contract.\n uint64 internal constant SENDER_VERSION = 1;\n\n /**\n * @notice Retrieves the OApp version information.\n * @return senderVersion The version of the OAppSender.sol contract.\n * @return receiverVersion The version of the OAppReceiver.sol contract.\n *\n * @dev Providing 0 as the default for OAppReceiver version. Indicates that the OAppReceiver is not implemented.\n * ie. this is a SEND only OApp.\n * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions\n */\n function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {\n return (SENDER_VERSION, 0);\n }\n\n /**\n * @dev Internal function to interact with the LayerZero EndpointV2.quote() for fee calculation.\n * @param _dstEid The destination endpoint ID.\n * @param _message The message payload.\n * @param _options Additional options for the message.\n * @param _payInLzToken Flag indicating whether to pay the fee in LZ tokens.\n * @return fee The calculated MessagingFee for the message.\n * - nativeFee: The native fee for the message.\n * - lzTokenFee: The LZ token fee for the message.\n */\n function _quote(\n uint32 _dstEid,\n bytes memory _message,\n bytes memory _options,\n bool _payInLzToken\n ) internal view virtual returns (MessagingFee memory fee) {\n return\n endpoint.quote(\n MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _payInLzToken),\n address(this)\n );\n }\n\n /**\n * @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message.\n * @param _dstEid The destination endpoint ID.\n * @param _message The message payload.\n * @param _options Additional options for the message.\n * @param _fee The calculated LayerZero fee for the message.\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n * @param _refundAddress The address to receive any excess fee values sent to the endpoint.\n * @return receipt The receipt for the sent message.\n * - guid: The unique identifier for the sent message.\n * - nonce: The nonce of the sent message.\n * - fee: The LayerZero fee incurred for the message.\n */\n function _lzSend(\n uint32 _dstEid,\n bytes memory _message,\n bytes memory _options,\n MessagingFee memory _fee,\n address _refundAddress\n ) internal virtual returns (MessagingReceipt memory receipt) {\n // @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint.\n uint256 messageValue = _payNative(_fee.nativeFee);\n if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee);\n\n return\n // solhint-disable-next-line check-send-result\n endpoint.send{ value: messageValue }(\n MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0),\n _refundAddress\n );\n }\n\n /**\n * @dev Internal function to pay the native fee associated with the message.\n * @param _nativeFee The native fee to be paid.\n * @return nativeFee The amount of native currency paid.\n *\n * @dev If the OApp needs to initiate MULTIPLE LayerZero messages in a single transaction,\n * this will need to be overridden because msg.value would contain multiple lzFees.\n * @dev Should be overridden in the event the LayerZero endpoint requires a different native currency.\n * @dev Some EVMs use an ERC20 as a method for paying transactions/gasFees.\n * @dev The endpoint is EITHER/OR, ie. it will NOT support both types of native payment at a time.\n */\n function _payNative(uint256 _nativeFee) internal virtual returns (uint256 nativeFee) {\n if (msg.value != _nativeFee) revert NotEnoughNative(msg.value);\n return _nativeFee;\n }\n\n /**\n * @dev Internal function to pay the LZ token fee associated with the message.\n * @param _lzTokenFee The LZ token fee to be paid.\n *\n * @dev If the caller is trying to pay in the specified lzToken, then the lzTokenFee is passed to the endpoint.\n * @dev Any excess sent, is passed back to the specified _refundAddress in the _lzSend().\n */\n function _payLzToken(uint256 _lzTokenFee) internal virtual {\n // @dev Cannot cache the token because it is not immutable in the endpoint.\n address lzToken = endpoint.lzToken();\n if (lzToken == address(0)) revert LzTokenUnavailable();\n\n // Pay LZ token fee by sending tokens to the endpoint.\n IERC20(lzToken).safeTransferFrom(msg.sender, address(endpoint), _lzTokenFee);\n }\n}\n" + }, + "@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { MessagingReceipt, MessagingFee } from \"@layerzerolabs/oapp-evm/contracts/oapp/OAppSender.sol\";\n\n/**\n * @dev Struct representing token parameters for the OFT send() operation.\n */\nstruct SendParam {\n uint32 dstEid; // Destination endpoint ID.\n bytes32 to; // Recipient address.\n uint256 amountLD; // Amount to send in local decimals.\n uint256 minAmountLD; // Minimum amount to send in local decimals.\n bytes extraOptions; // Additional options supplied by the caller to be used in the LayerZero message.\n bytes composeMsg; // The composed message for the send() operation.\n bytes oftCmd; // The OFT command to be executed, unused in default OFT implementations.\n}\n\n/**\n * @dev Struct representing OFT limit information.\n * @dev These amounts can change dynamically and are up the specific oft implementation.\n */\nstruct OFTLimit {\n uint256 minAmountLD; // Minimum amount in local decimals that can be sent to the recipient.\n uint256 maxAmountLD; // Maximum amount in local decimals that can be sent to the recipient.\n}\n\n/**\n * @dev Struct representing OFT receipt information.\n */\nstruct OFTReceipt {\n uint256 amountSentLD; // Amount of tokens ACTUALLY debited from the sender in local decimals.\n // @dev In non-default implementations, the amountReceivedLD COULD differ from this value.\n uint256 amountReceivedLD; // Amount of tokens to be received on the remote side.\n}\n\n/**\n * @dev Struct representing OFT fee details.\n * @dev Future proof mechanism to provide a standardized way to communicate fees to things like a UI.\n */\nstruct OFTFeeDetail {\n int256 feeAmountLD; // Amount of the fee in local decimals.\n string description; // Description of the fee.\n}\n\n/**\n * @title IOFT\n * @dev Interface for the OftChain (OFT) token.\n * @dev Does not inherit ERC20 to accommodate usage by OFTAdapter as well.\n * @dev This specific interface ID is '0x02e49c2c'.\n */\ninterface IOFT {\n // Custom error messages\n error InvalidLocalDecimals();\n error SlippageExceeded(uint256 amountLD, uint256 minAmountLD);\n\n // Events\n event OFTSent(\n bytes32 indexed guid, // GUID of the OFT message.\n uint32 dstEid, // Destination Endpoint ID.\n address indexed fromAddress, // Address of the sender on the src chain.\n uint256 amountSentLD, // Amount of tokens sent in local decimals.\n uint256 amountReceivedLD // Amount of tokens received in local decimals.\n );\n event OFTReceived(\n bytes32 indexed guid, // GUID of the OFT message.\n uint32 srcEid, // Source Endpoint ID.\n address indexed toAddress, // Address of the recipient on the dst chain.\n uint256 amountReceivedLD // Amount of tokens received in local decimals.\n );\n\n /**\n * @notice Retrieves interfaceID and the version of the OFT.\n * @return interfaceId The interface ID.\n * @return version The version.\n *\n * @dev interfaceId: This specific interface ID is '0x02e49c2c'.\n * @dev version: Indicates a cross-chain compatible msg encoding with other OFTs.\n * @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented.\n * ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1)\n */\n function oftVersion() external view returns (bytes4 interfaceId, uint64 version);\n\n /**\n * @notice Retrieves the address of the token associated with the OFT.\n * @return token The address of the ERC20 token implementation.\n */\n function token() external view returns (address);\n\n /**\n * @notice Indicates whether the OFT contract requires approval of the 'token()' to send.\n * @return requiresApproval Needs approval of the underlying token implementation.\n *\n * @dev Allows things like wallet implementers to determine integration requirements,\n * without understanding the underlying token implementation.\n */\n function approvalRequired() external view returns (bool);\n\n /**\n * @notice Retrieves the shared decimals of the OFT.\n * @return sharedDecimals The shared decimals of the OFT.\n */\n function sharedDecimals() external view returns (uint8);\n\n /**\n * @notice Provides the fee breakdown and settings data for an OFT. Unused in the default implementation.\n * @param _sendParam The parameters for the send operation.\n * @return limit The OFT limit information.\n * @return oftFeeDetails The details of OFT fees.\n * @return receipt The OFT receipt information.\n */\n function quoteOFT(\n SendParam calldata _sendParam\n ) external view returns (OFTLimit memory, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory);\n\n /**\n * @notice Provides a quote for the send() operation.\n * @param _sendParam The parameters for the send() operation.\n * @param _payInLzToken Flag indicating whether the caller is paying in the LZ token.\n * @return fee The calculated LayerZero messaging fee from the send() operation.\n *\n * @dev MessagingFee: LayerZero msg fee\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n */\n function quoteSend(SendParam calldata _sendParam, bool _payInLzToken) external view returns (MessagingFee memory);\n\n /**\n * @notice Executes the send() operation.\n * @param _sendParam The parameters for the send operation.\n * @param _fee The fee information supplied by the caller.\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n * @param _refundAddress The address to receive any excess funds from fees etc. on the src.\n * @return receipt The LayerZero messaging receipt from the send() operation.\n * @return oftReceipt The OFT receipt information.\n *\n * @dev MessagingReceipt: LayerZero msg receipt\n * - guid: The unique identifier for the sent message.\n * - nonce: The nonce of the sent message.\n * - fee: The LayerZero fee incurred for the message.\n */\n function send(\n SendParam calldata _sendParam,\n MessagingFee calldata _fee,\n address _refundAddress\n ) external payable returns (MessagingReceipt memory, OFTReceipt memory);\n}\n" + }, + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role, _msgSender());\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(uint160(account), 20),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/AccessControlEnumerable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/AccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlEnumerable.sol\";\nimport \"./AccessControl.sol\";\nimport \"../utils/structs/EnumerableSet.sol\";\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view override returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view override returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override {\n super._grantRole(role, account);\n _roleMembers[role].add(account);\n }\n\n /**\n * @dev Overload {_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override {\n super._revokeRole(role, account);\n _roleMembers[role].remove(account);\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControlEnumerable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n" + }, + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "@openzeppelin/contracts/security/Pausable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract Pausable is Context {\n /**\n * @dev Emitted when the pause is triggered by `account`.\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by `account`.\n */\n event Unpaused(address account);\n\n bool private _paused;\n\n /**\n * @dev Initializes the contract in unpaused state.\n */\n constructor() {\n _paused = false;\n }\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view virtual returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n modifier whenNotPaused() {\n require(!paused(), \"Pausable: paused\");\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n modifier whenPaused() {\n require(paused(), \"Pausable: not paused\");\n _;\n }\n\n /**\n * @dev Triggers stopped state.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n function _pause() internal virtual whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Returns to normal state.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n function _unpause() internal virtual whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public virtual override returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * Requirements:\n *\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for ``sender``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public virtual override returns (bool) {\n _transfer(sender, recipient, amount);\n\n uint256 currentAllowance = _allowances[sender][_msgSender()];\n require(currentAllowance >= amount, \"ERC20: transfer amount exceeds allowance\");\n unchecked {\n _approve(sender, _msgSender(), currentAllowance - amount);\n }\n\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n uint256 currentAllowance = _allowances[_msgSender()][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(_msgSender(), spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal virtual {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(sender, recipient, amount);\n\n uint256 senderBalance = _balances[sender];\n require(senderBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[sender] = senderBalance - amount;\n }\n _balances[recipient] += amount;\n\n emit Transfer(sender, recipient, amount);\n\n _afterTokenTransfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize, which returns 0 for contracts in\n // construction, since the code is only stored at the end of the\n // constructor execution.\n\n uint256 size;\n assembly {\n size := extcodesize(account)\n }\n return size > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a >= b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a / b + (a % b == 0 ? 0 : 1);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeCast.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n require(value >= 0, \"SafeCast: value must be positive\");\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v3.1._\n */\n function toInt128(int256 value) internal pure returns (int128) {\n require(value >= type(int128).min && value <= type(int128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return int128(value);\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v3.1._\n */\n function toInt64(int256 value) internal pure returns (int64) {\n require(value >= type(int64).min && value <= type(int64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return int64(value);\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v3.1._\n */\n function toInt32(int256 value) internal pure returns (int32) {\n require(value >= type(int32).min && value <= type(int32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return int32(value);\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v3.1._\n */\n function toInt16(int256 value) internal pure returns (int16) {\n require(value >= type(int16).min && value <= type(int16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return int16(value);\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n *\n * _Available since v3.1._\n */\n function toInt8(int256 value) internal pure returns (int8) {\n require(value >= type(int8).min && value <= type(int8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return int8(value);\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n return int256(value);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeMath.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/structs/EnumerableSet.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(bytes32 => uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value's index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (lastIndex != toDeleteIndex) {\n bytes32 lastvalue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastvalue;\n // Update the index for the moved value\n set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n return _values(set._inner);\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n assembly {\n result := store\n }\n\n return result;\n }\n}\n" + }, + "contracts/automation/AbstractCCIPBridgeHelperModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractSafeModule } from \"./AbstractSafeModule.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IRouterClient } from \"@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol\";\nimport { Client } from \"@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol\";\n\nabstract contract AbstractCCIPBridgeHelperModule is AbstractSafeModule {\n /**\n * @notice Bridges a token from the source chain to the destination chain using CCIP\n * @param ccipRouter The CCIP router contract\n * @param destinationChainSelector The selector for the destination chain\n * @param token The token to bridge\n * @param amount The amount of token to bridge\n */\n function _bridgeTokenWithCCIP(\n IRouterClient ccipRouter,\n uint64 destinationChainSelector,\n IERC20 token,\n uint256 amount\n ) internal {\n bool success;\n\n // Approve CCIP Router to move the token\n success = safeContract.execTransactionFromModule(\n address(token),\n 0, // Value\n abi.encodeWithSelector(token.approve.selector, ccipRouter, amount),\n 0 // Call\n );\n require(success, \"Failed to approve token\");\n\n Client.EVMTokenAmount[]\n memory tokenAmounts = new Client.EVMTokenAmount[](1);\n Client.EVMTokenAmount memory tokenAmount = Client.EVMTokenAmount({\n token: address(token),\n amount: amount\n });\n tokenAmounts[0] = tokenAmount;\n\n Client.EVM2AnyMessage memory ccipMessage = Client.EVM2AnyMessage({\n receiver: abi.encode(address(safeContract)), // ABI-encoded receiver address\n data: abi.encode(\"\"),\n tokenAmounts: tokenAmounts,\n extraArgs: Client._argsToBytes(\n Client.EVMExtraArgsV1({ gasLimit: 0 })\n ),\n feeToken: address(0)\n });\n\n // Get CCIP fee\n uint256 ccipFee = ccipRouter.getFee(\n destinationChainSelector,\n ccipMessage\n );\n\n // Send CCIP message\n success = safeContract.execTransactionFromModule(\n address(ccipRouter),\n ccipFee, // Value\n abi.encodeWithSelector(\n ccipRouter.ccipSend.selector,\n destinationChainSelector,\n ccipMessage\n ),\n 0 // Call\n );\n require(success, \"Failed to send CCIP message\");\n }\n}\n" + }, + "contracts/automation/AbstractLZBridgeHelperModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractSafeModule } from \"./AbstractSafeModule.sol\";\n\nimport { IOFT, SendParam } from \"@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol\";\nimport { MessagingFee } from \"@layerzerolabs/oapp-evm/contracts/oapp/OAppSender.sol\";\nimport { OptionsBuilder } from \"@layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol\";\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nabstract contract AbstractLZBridgeHelperModule is AbstractSafeModule {\n using OptionsBuilder for bytes;\n\n /**\n * @dev Bridges token using LayerZero.\n * @param lzEndpointId LayerZero endpoint id.\n * @param token Token to bridge.\n * @param lzAdapter LZ Adapter to use.\n * @param amount Amount of token to bridge.\n * @param slippageBps Slippage in 10^4 basis points.\n * @param isNativeToken Whether the token is native token.\n */\n function _bridgeTokenWithLz(\n uint32 lzEndpointId,\n IERC20 token,\n IOFT lzAdapter,\n uint256 amount,\n uint256 slippageBps,\n bool isNativeToken\n ) internal {\n bool success;\n\n if (!isNativeToken) {\n // Approve LZ Adapter to move the token\n success = safeContract.execTransactionFromModule(\n address(token),\n 0, // Value\n abi.encodeWithSelector(\n token.approve.selector,\n address(lzAdapter),\n amount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve token\");\n }\n\n // Calculate minimum amount to receive\n uint256 minAmount = (amount * (10000 - slippageBps)) / 10000;\n\n // Hardcoded gaslimit of 400k\n bytes memory options = OptionsBuilder\n .newOptions()\n .addExecutorLzReceiveOption(400000, 0);\n\n // Build send param\n SendParam memory sendParam = SendParam({\n dstEid: lzEndpointId,\n to: bytes32(uint256(uint160(address(safeContract)))),\n amountLD: amount,\n minAmountLD: minAmount,\n extraOptions: options,\n composeMsg: bytes(\"\"),\n oftCmd: bytes(\"\")\n });\n\n // Compute fees\n MessagingFee memory msgFee = lzAdapter.quoteSend(sendParam, false);\n\n uint256 value = isNativeToken\n ? amount + msgFee.nativeFee\n : msgFee.nativeFee;\n\n // Execute transaction\n success = safeContract.execTransactionFromModule(\n address(lzAdapter),\n value,\n abi.encodeWithSelector(\n lzAdapter.send.selector,\n sendParam,\n msgFee,\n address(safeContract)\n ),\n 0\n );\n require(success, \"Failed to bridge token\");\n }\n}\n" + }, + "contracts/automation/AbstractSafeModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AccessControlEnumerable } from \"@openzeppelin/contracts/access/AccessControlEnumerable.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { ISafe } from \"../interfaces/ISafe.sol\";\n\nabstract contract AbstractSafeModule is AccessControlEnumerable {\n ISafe public immutable safeContract;\n\n bytes32 public constant OPERATOR_ROLE = keccak256(\"OPERATOR_ROLE\");\n\n modifier onlySafe() {\n require(\n msg.sender == address(safeContract),\n \"Caller is not the safe contract\"\n );\n _;\n }\n\n modifier onlyOperator() {\n require(\n hasRole(OPERATOR_ROLE, msg.sender),\n \"Caller is not an operator\"\n );\n _;\n }\n\n constructor(address _safeContract) {\n safeContract = ISafe(_safeContract);\n _grantRole(DEFAULT_ADMIN_ROLE, address(safeContract));\n _grantRole(OPERATOR_ROLE, address(safeContract));\n }\n\n /**\n * @dev Helps recovering any tokens accidentally sent to this module.\n * @param token Token to transfer. 0x0 to transfer Native token.\n * @param amount Amount to transfer. 0 to transfer all balance.\n */\n function transferTokens(address token, uint256 amount) external onlySafe {\n if (address(token) == address(0)) {\n // Move ETH\n amount = amount > 0 ? amount : address(this).balance;\n payable(address(safeContract)).transfer(amount);\n return;\n }\n\n // Move all balance if amount set to 0\n amount = amount > 0 ? amount : IERC20(token).balanceOf(address(this));\n\n // Transfer to Safe contract\n // slither-disable-next-line unchecked-transfer unused-return\n IERC20(token).transfer(address(safeContract), amount);\n }\n\n receive() external payable {\n // Accept ETH to pay for bridge fees\n }\n}\n" + }, + "contracts/automation/AutoWithdrawalModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractSafeModule } from \"./AbstractSafeModule.sol\";\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { VaultStorage } from \"../vault/VaultStorage.sol\";\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\n\n/**\n * @title Auto Withdrawal Module\n * @notice A Gnosis Safe module that automates funding the OUSD (or OETH) vault's\n * withdrawal queue by pulling liquidity from a configured strategy.\n *\n * @dev The Safe (Guardian multisig) must:\n * 1. Deploy this module\n * 2. Call `safe.enableModule(address(this))` to authorize it\n *\n * An off-chain operator (e.g. Defender Relayer) calls `fundWithdrawals()`\n * periodically. The module:\n * - First tries to satisfy the queue from idle vault funds\n * - If there's still a shortfall, withdraws the exact shortfall amount\n * from the configured strategy (up to what the strategy holds)\n *\n * The Safe retains full override control via `setStrategy`.\n */\ncontract AutoWithdrawalModule is AbstractSafeModule {\n // ───────────────────────────────────────────────────────── Immutables ──\n\n /// @notice The vault whose withdrawal queue is being funded.\n IVault public immutable vault;\n\n /// @notice The vault's base asset (e.g. USDC for OUSD, WETH for OETH).\n /// Stored as an address to match IStrategy.checkBalance() signature.\n address public immutable asset;\n\n // ────────────────────────────────────────────────────── Mutable config ──\n\n /// @notice The strategy from which liquidity is pulled to fill the queue.\n address public strategy;\n\n // ─────────────────────────────────────────────────────────── Events ──\n\n /// @notice Emitted when liquidity is successfully moved from strategy to vault.\n event LiquidityWithdrawn(\n address indexed strategy,\n uint256 amount,\n uint256 remainingShortfall\n );\n\n /// @notice Emitted when the strategy does not hold enough funds to cover the shortfall.\n /// No withdrawal is attempted; an operator alert should fire on this event.\n event InsufficientStrategyLiquidity(\n address indexed strategy,\n uint256 shortfall,\n uint256 available\n );\n\n /// @notice Emitted when the Safe exec call to withdrawFromStrategy fails.\n event WithdrawalFailed(address indexed strategy, uint256 attemptedAmount);\n\n /// @notice Emitted when the strategy address is updated.\n event StrategyUpdated(address oldStrategy, address newStrategy);\n\n // ─────────────────────────────────────────────────────── Constructor ──\n\n /**\n * @param _safeContract Address of the Gnosis Safe (Guardian multisig).\n * @param _operator Address of the off-chain operator (e.g. Defender relayer).\n * @param _vault Address of the OUSD/OETH vault.\n * @param _strategy Initial strategy to pull liquidity from.\n */\n constructor(\n address _safeContract,\n address _operator,\n address _vault,\n address _strategy\n ) AbstractSafeModule(_safeContract) {\n require(_vault != address(0), \"Invalid vault\");\n require(_strategy != address(0), \"Invalid strategy\");\n\n vault = IVault(_vault);\n asset = IVault(_vault).asset();\n\n _setStrategy(_strategy);\n\n _grantRole(OPERATOR_ROLE, _operator);\n }\n\n // ──────────────────────────────────────────────────── Core automation ──\n\n /**\n * @notice Fund the vault's withdrawal queue from the configured strategy.\n * Called periodically by an off-chain operator (Defender Actions).\n *\n * Steps:\n * 1. Ask the vault to absorb any idle asset it already holds.\n * 2. Compute the remaining shortfall.\n * 3. Pull up to that amount from the strategy via the Safe.\n *\n * This function never reverts on \"soft\" failures (strategy underfunded,\n * Safe exec failure). It emits a descriptive event instead so off-chain\n * monitoring can alert the team without breaking the Defender action.\n */\n function fundWithdrawals() external onlyOperator {\n // Step 1: Let the vault absorb any asset it already holds idle.\n // This is a permissionless call; no Safe exec needed.\n vault.addWithdrawalQueueLiquidity();\n\n // Step 2: Read the current shortfall.\n uint256 shortfall = pendingShortfall();\n\n if (shortfall == 0) {\n // Queue is fully funded — nothing to do.\n return;\n }\n\n // Step 3: Read available balance from the strategy.\n uint256 strategyBalance = IStrategy(strategy).checkBalance(asset);\n\n // Withdraw the lesser of the shortfall and what the strategy holds.\n uint256 toWithdraw = shortfall < strategyBalance\n ? shortfall\n : strategyBalance;\n\n if (toWithdraw == 0) {\n emit InsufficientStrategyLiquidity(\n strategy,\n shortfall,\n strategyBalance\n );\n return;\n }\n\n // Step 4: Execute withdrawal via the Safe (which holds the Strategist role).\n address[] memory assets = new address[](1);\n assets[0] = asset;\n uint256[] memory amounts = new uint256[](1);\n amounts[0] = toWithdraw;\n\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0,\n abi.encodeWithSelector(\n IVault.withdrawFromStrategy.selector,\n strategy,\n assets,\n amounts\n ),\n 0 // Call (not delegatecall)\n );\n\n if (!success) {\n emit WithdrawalFailed(strategy, toWithdraw);\n return;\n }\n\n emit LiquidityWithdrawn(strategy, toWithdraw, shortfall - toWithdraw);\n }\n\n // ─────────────────────────────────────────────────────── Guardian controls ──\n\n /**\n * @notice Change the strategy from which liquidity is pulled.\n * @param _strategy New strategy address. Must not be zero.\n */\n function setStrategy(address _strategy) external onlySafe {\n _setStrategy(_strategy);\n }\n\n function _setStrategy(address _strategy) internal {\n require(_strategy != address(0), \"Invalid strategy\");\n emit StrategyUpdated(strategy, _strategy);\n strategy = _strategy;\n }\n\n // ──────────────────────────────────────────────────────── View helpers ──\n\n /**\n * @notice The current unmet shortfall in the vault's withdrawal queue.\n * @dev This is a raw read of `queued - claimable`. It does NOT account for\n * idle vault asset that `addWithdrawalQueueLiquidity()` would absorb.\n * For a fully up-to-date figure, call `vault.addWithdrawalQueueLiquidity()`\n * first (which is what `fundWithdrawals()` does).\n * @return shortfall Queue shortfall in asset units (vault asset decimals).\n */\n function pendingShortfall() public view returns (uint256 shortfall) {\n VaultStorage.WithdrawalQueueMetadata memory meta = vault\n .withdrawalQueueMetadata();\n shortfall = meta.queued - meta.claimable;\n }\n}\n" + }, + "contracts/automation/BaseBridgeHelperModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// solhint-disable-next-line max-line-length\nimport { AbstractCCIPBridgeHelperModule, AbstractSafeModule, IRouterClient } from \"./AbstractCCIPBridgeHelperModule.sol\";\n\nimport { AccessControlEnumerable } from \"@openzeppelin/contracts/access/AccessControlEnumerable.sol\";\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nimport { BridgedWOETHStrategy } from \"../strategies/BridgedWOETHStrategy.sol\";\n\ncontract BaseBridgeHelperModule is\n AccessControlEnumerable,\n AbstractCCIPBridgeHelperModule\n{\n IVault public constant vault =\n IVault(0x98a0CbeF61bD2D21435f433bE4CD42B56B38CC93);\n IWETH9 public constant weth =\n IWETH9(0x4200000000000000000000000000000000000006);\n IERC20 public constant oethb =\n IERC20(0xDBFeFD2e8460a6Ee4955A68582F85708BAEA60A3);\n IERC4626 public constant bridgedWOETH =\n IERC4626(0xD8724322f44E5c58D7A815F542036fb17DbbF839);\n\n BridgedWOETHStrategy public constant bridgedWOETHStrategy =\n BridgedWOETHStrategy(0x80c864704DD06C3693ed5179190786EE38ACf835);\n\n IRouterClient public constant CCIP_ROUTER =\n IRouterClient(0x881e3A65B4d4a04dD529061dd0071cf975F58bCD);\n\n uint64 public constant CCIP_ETHEREUM_CHAIN_SELECTOR = 5009297550715157269;\n\n constructor(address _safeContract) AbstractSafeModule(_safeContract) {}\n\n /**\n * @dev Bridges wOETH to Ethereum.\n * @param woethAmount Amount of wOETH to bridge.\n */\n function bridgeWOETHToEthereum(uint256 woethAmount)\n public\n payable\n onlyOperator\n {\n _bridgeTokenWithCCIP(\n CCIP_ROUTER,\n CCIP_ETHEREUM_CHAIN_SELECTOR,\n IERC20(address(bridgedWOETH)),\n woethAmount\n );\n }\n\n /**\n * @dev Bridges WETH to Ethereum.\n * @param wethAmount Amount of WETH to bridge.\n */\n function bridgeWETHToEthereum(uint256 wethAmount)\n public\n payable\n onlyOperator\n {\n _bridgeTokenWithCCIP(\n CCIP_ROUTER,\n CCIP_ETHEREUM_CHAIN_SELECTOR,\n IERC20(address(weth)),\n wethAmount\n );\n }\n\n /**\n * @dev Deposits wOETH into the bridgedWOETH strategy.\n * @param woethAmount Amount of wOETH to deposit.\n * @param requestWithdrawal Whether to request an async withdrawal of the\n * resulting OETHb from the Vault.\n * @return requestId The withdrawal request ID (0 if not requested).\n * @return oethbAmount Amount of OETHb received or queued for withdrawal.\n */\n function depositWOETH(uint256 woethAmount, bool requestWithdrawal)\n external\n onlyOperator\n returns (uint256 requestId, uint256 oethbAmount)\n {\n oethbAmount = _depositWOETH(woethAmount);\n if (requestWithdrawal) {\n requestId = _requestWithdrawal(oethbAmount);\n }\n }\n\n /**\n * @dev Claims a previously requested withdrawal and bridges WETH to Ethereum.\n * @param requestId The withdrawal request ID to claim.\n */\n function claimAndBridgeWETH(uint256 requestId)\n external\n payable\n onlyOperator\n {\n uint256 wethAmount = _claimWithdrawal(requestId);\n bridgeWETHToEthereum(wethAmount);\n }\n\n /**\n * @dev Claims a previously requested withdrawal.\n * @param requestId The withdrawal request ID to claim.\n * @return wethAmount Amount of WETH received.\n */\n function claimWithdrawal(uint256 requestId)\n external\n onlyOperator\n returns (uint256 wethAmount)\n {\n return _claimWithdrawal(requestId);\n }\n\n /**\n * @dev Deposits wOETH into the bridgedWOETH strategy.\n * @param woethAmount Amount of wOETH to deposit.\n * @return oethbAmount Amount of OETHb received.\n */\n function _depositWOETH(uint256 woethAmount)\n internal\n returns (uint256 oethbAmount)\n {\n // Update oracle price\n bridgedWOETHStrategy.updateWOETHOraclePrice();\n\n // Rebase to account for any yields from price update\n vault.rebase();\n\n oethbAmount = oethb.balanceOf(address(safeContract));\n\n // Approve bridgedWOETH strategy to move wOETH\n bool success = safeContract.execTransactionFromModule(\n address(bridgedWOETH),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETH.approve.selector,\n address(bridgedWOETHStrategy),\n woethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve wOETH\");\n\n // Deposit to bridgedWOETH strategy\n success = safeContract.execTransactionFromModule(\n address(bridgedWOETHStrategy),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETHStrategy.depositBridgedWOETH.selector,\n woethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to deposit bridged WOETH\");\n\n oethbAmount = oethb.balanceOf(address(safeContract)) - oethbAmount;\n\n // Rebase to account for any yields from price update\n // and backing asset change from deposit\n vault.rebase();\n }\n\n /**\n * @dev Requests an async withdrawal from the Vault.\n * @param oethbAmount Amount of OETHb to withdraw.\n * @return requestId The withdrawal request ID.\n */\n function _requestWithdrawal(uint256 oethbAmount)\n internal\n returns (uint256 requestId)\n {\n // Read the next withdrawal index before requesting\n // (safe because requestWithdrawal is nonReentrant)\n requestId = vault.withdrawalQueueMetadata().nextWithdrawalIndex;\n\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(\n vault.requestWithdrawal.selector,\n oethbAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to request withdrawal\");\n }\n\n /**\n * @dev Claims a previously requested withdrawal from the Vault.\n * @param requestId The withdrawal request ID to claim.\n * @return wethAmount Amount of WETH received.\n */\n function _claimWithdrawal(uint256 requestId)\n internal\n returns (uint256 wethAmount)\n {\n wethAmount = weth.balanceOf(address(safeContract));\n\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(vault.claimWithdrawal.selector, requestId),\n 0 // Call\n );\n require(success, \"Failed to claim withdrawal\");\n\n wethAmount = weth.balanceOf(address(safeContract)) - wethAmount;\n }\n\n /**\n * @dev Deposits WETH into the Vault and redeems wOETH from the bridgedWOETH strategy.\n * @param wethAmount Amount of WETH to deposit.\n * @return Amount of wOETH received.\n */\n function depositWETHAndRedeemWOETH(uint256 wethAmount)\n external\n onlyOperator\n returns (uint256)\n {\n return _withdrawWOETH(wethAmount);\n }\n\n function depositWETHAndBridgeWOETH(uint256 wethAmount)\n external\n onlyOperator\n returns (uint256)\n {\n uint256 woethAmount = _withdrawWOETH(wethAmount);\n bridgeWOETHToEthereum(woethAmount);\n return woethAmount;\n }\n\n /**\n * @dev Withdraws wOETH from the bridgedWOETH strategy.\n * @param wethAmount Amount of WETH to use to withdraw.\n * @return Amount of wOETH received.\n */\n function _withdrawWOETH(uint256 wethAmount) internal returns (uint256) {\n // Approve Vault to move WETH\n bool success = safeContract.execTransactionFromModule(\n address(weth),\n 0, // Value\n abi.encodeWithSelector(\n weth.approve.selector,\n address(vault),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve WETH\");\n\n // Mint OETHb with WETH\n success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(vault.mint.selector, wethAmount),\n 0 // Call\n );\n require(success, \"Failed to mint OETHb\");\n\n // Approve bridgedWOETH strategy to move OETHb\n success = safeContract.execTransactionFromModule(\n address(oethb),\n 0, // Value\n abi.encodeWithSelector(\n oethb.approve.selector,\n address(bridgedWOETHStrategy),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve OETHb\");\n\n uint256 woethAmount = bridgedWOETH.balanceOf(address(safeContract));\n\n // Withdraw from bridgedWOETH strategy\n success = safeContract.execTransactionFromModule(\n address(bridgedWOETHStrategy),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETHStrategy.withdrawBridgedWOETH.selector,\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to withdraw bridged WOETH\");\n\n woethAmount =\n bridgedWOETH.balanceOf(address(safeContract)) -\n woethAmount;\n\n return woethAmount;\n }\n}\n" + }, + "contracts/automation/EthereumBridgeHelperModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// solhint-disable-next-line max-line-length\nimport { AbstractCCIPBridgeHelperModule, AbstractSafeModule, IRouterClient } from \"./AbstractCCIPBridgeHelperModule.sol\";\n\nimport { AccessControlEnumerable } from \"@openzeppelin/contracts/access/AccessControlEnumerable.sol\";\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract EthereumBridgeHelperModule is\n AccessControlEnumerable,\n AbstractCCIPBridgeHelperModule\n{\n IVault public constant vault =\n IVault(0x39254033945AA2E4809Cc2977E7087BEE48bd7Ab);\n IWETH9 public constant weth =\n IWETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);\n IERC20 public constant oeth =\n IERC20(0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3);\n IERC4626 public constant woeth =\n IERC4626(0xDcEe70654261AF21C44c093C300eD3Bb97b78192);\n\n IRouterClient public constant CCIP_ROUTER =\n IRouterClient(0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D);\n\n uint64 public constant CCIP_BASE_CHAIN_SELECTOR = 15971525489660198786;\n\n constructor(address _safeContract) AbstractSafeModule(_safeContract) {}\n\n /**\n * @dev Bridges wOETH to Base using CCIP.\n * @param woethAmount Amount of wOETH to bridge.\n */\n function bridgeWOETHToBase(uint256 woethAmount)\n public\n payable\n onlyOperator\n {\n _bridgeTokenWithCCIP(\n CCIP_ROUTER,\n CCIP_BASE_CHAIN_SELECTOR,\n woeth,\n woethAmount\n );\n }\n\n /**\n * @dev Bridges wETH to Base using CCIP.\n * @param wethAmount Amount of wETH to bridge.\n */\n function bridgeWETHToBase(uint256 wethAmount) public payable onlyOperator {\n _bridgeTokenWithCCIP(\n CCIP_ROUTER,\n CCIP_BASE_CHAIN_SELECTOR,\n IERC20(address(weth)),\n wethAmount\n );\n }\n\n /**\n * @dev Mints OETH and wraps it into wOETH.\n * @param wethAmount Amount of WETH to mint.\n * @param useNativeToken Whether to use native token to mint.\n * @return Amount of wOETH minted.\n */\n function mintAndWrap(uint256 wethAmount, bool useNativeToken)\n external\n onlyOperator\n returns (uint256)\n {\n if (useNativeToken) {\n wrapETH(wethAmount);\n }\n\n return _mintAndWrap(wethAmount);\n }\n\n function wrapETH(uint256 ethAmount) public payable onlyOperator {\n // Deposit ETH into WETH\n safeContract.execTransactionFromModule(\n address(weth),\n ethAmount, // Value\n abi.encodeWithSelector(weth.deposit.selector),\n 0 // Call\n );\n }\n\n /**\n * @dev Mints OETH and wraps it into wOETH.\n * @param wethAmount Amount of WETH to mint.\n * @return Amount of wOETH minted.\n */\n function _mintAndWrap(uint256 wethAmount) internal returns (uint256) {\n // Approve Vault to move WETH\n bool success = safeContract.execTransactionFromModule(\n address(weth),\n 0, // Value\n abi.encodeWithSelector(\n weth.approve.selector,\n address(vault),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve WETH\");\n\n // Mint OETH\n success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(vault.mint.selector, wethAmount),\n 0 // Call\n );\n require(success, \"Failed to mint OETH\");\n\n // Approve wOETH to move OETH\n success = safeContract.execTransactionFromModule(\n address(oeth),\n 0, // Value\n abi.encodeWithSelector(\n oeth.approve.selector,\n address(woeth),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve OETH\");\n\n uint256 woethAmount = woeth.balanceOf(address(safeContract));\n\n // Wrap OETH into wOETH\n success = safeContract.execTransactionFromModule(\n address(woeth),\n 0, // Value\n abi.encodeWithSelector(\n woeth.deposit.selector,\n wethAmount,\n address(safeContract)\n ),\n 0 // Call\n );\n require(success, \"Failed to wrap OETH\");\n\n // Compute amount of wOETH minted\n return woeth.balanceOf(address(safeContract)) - woethAmount;\n }\n\n /**\n * @dev Mints OETH and wraps it into wOETH, then bridges it to Base using CCIP.\n * @param wethAmount Amount of WETH to mint.\n * @param useNativeToken Whether to use native token to mint.\n */\n function mintWrapAndBridgeToBase(uint256 wethAmount, bool useNativeToken)\n external\n payable\n onlyOperator\n {\n if (useNativeToken) {\n wrapETH(wethAmount);\n }\n\n uint256 woethAmount = _mintAndWrap(wethAmount);\n bridgeWOETHToBase(woethAmount);\n }\n\n /**\n * @dev Unwraps wOETH and requests an async withdrawal from the Vault.\n * @param woethAmount Amount of wOETH to unwrap.\n * @return requestId The withdrawal request ID.\n * @return oethAmount Amount of OETH queued for withdrawal.\n */\n function unwrapAndRequestWithdrawal(uint256 woethAmount)\n external\n onlyOperator\n returns (uint256 requestId, uint256 oethAmount)\n {\n return _unwrapAndRequestWithdrawal(woethAmount);\n }\n\n /**\n * @dev Claims a previously requested withdrawal and bridges WETH to Base.\n * @param requestId The withdrawal request ID to claim.\n */\n function claimAndBridgeToBase(uint256 requestId)\n external\n payable\n onlyOperator\n {\n uint256 wethAmount = _claimWithdrawal(requestId);\n bridgeWETHToBase(wethAmount);\n }\n\n /**\n * @dev Claims a previously requested withdrawal.\n * @param requestId The withdrawal request ID to claim.\n * @return wethAmount Amount of WETH received.\n */\n function claimWithdrawal(uint256 requestId)\n external\n onlyOperator\n returns (uint256 wethAmount)\n {\n return _claimWithdrawal(requestId);\n }\n\n /**\n * @dev Unwraps wOETH and requests an async withdrawal from the Vault.\n * @param woethAmount Amount of wOETH to unwrap.\n * @return requestId The withdrawal request ID.\n * @return oethAmount Amount of OETH queued for withdrawal.\n */\n function _unwrapAndRequestWithdrawal(uint256 woethAmount)\n internal\n returns (uint256 requestId, uint256 oethAmount)\n {\n // Read the next withdrawal index before requesting\n // (safe because requestWithdrawal is nonReentrant)\n requestId = vault.withdrawalQueueMetadata().nextWithdrawalIndex;\n\n oethAmount = oeth.balanceOf(address(safeContract));\n\n // Unwrap wOETH\n bool success = safeContract.execTransactionFromModule(\n address(woeth),\n 0, // Value\n abi.encodeWithSelector(\n woeth.redeem.selector,\n woethAmount,\n address(safeContract),\n address(safeContract)\n ),\n 0 // Call\n );\n require(success, \"Failed to unwrap wOETH\");\n\n oethAmount = oeth.balanceOf(address(safeContract)) - oethAmount;\n\n // Request async withdrawal from Vault\n success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(\n vault.requestWithdrawal.selector,\n oethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to request withdrawal\");\n }\n\n /**\n * @dev Claims a previously requested withdrawal from the Vault.\n * @param requestId The withdrawal request ID to claim.\n * @return wethAmount Amount of WETH received.\n */\n function _claimWithdrawal(uint256 requestId)\n internal\n returns (uint256 wethAmount)\n {\n wethAmount = weth.balanceOf(address(safeContract));\n\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(vault.claimWithdrawal.selector, requestId),\n 0 // Call\n );\n require(success, \"Failed to claim withdrawal\");\n\n wethAmount = weth.balanceOf(address(safeContract)) - wethAmount;\n }\n}\n" + }, + "contracts/automation/PlumeBridgeHelperModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractSafeModule } from \"./AbstractSafeModule.sol\";\nimport { AbstractLZBridgeHelperModule } from \"./AbstractLZBridgeHelperModule.sol\";\n\nimport { AccessControlEnumerable } from \"@openzeppelin/contracts/access/AccessControlEnumerable.sol\";\n\nimport { IOFT } from \"@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol\";\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nimport { BridgedWOETHStrategy } from \"../strategies/BridgedWOETHStrategy.sol\";\n\ncontract PlumeBridgeHelperModule is\n AccessControlEnumerable,\n AbstractLZBridgeHelperModule\n{\n IVault public constant vault =\n IVault(0xc8c8F8bEA5631A8AF26440AF32a55002138cB76a);\n IWETH9 public constant weth =\n IWETH9(0xca59cA09E5602fAe8B629DeE83FfA819741f14be);\n IERC20 public constant oethp =\n IERC20(0xFCbe50DbE43bF7E5C88C6F6Fb9ef432D4165406E);\n IERC4626 public constant bridgedWOETH =\n IERC4626(0xD8724322f44E5c58D7A815F542036fb17DbbF839);\n\n uint32 public constant LZ_ETHEREUM_ENDPOINT_ID = 30101;\n IOFT public constant LZ_WOETH_OMNICHAIN_ADAPTER =\n IOFT(0x592CB6A596E7919930bF49a27AdAeCA7C055e4DB);\n IOFT public constant LZ_ETH_OMNICHAIN_ADAPTER =\n IOFT(0x4683CE822272CD66CEa73F5F1f9f5cBcaEF4F066);\n\n BridgedWOETHStrategy public constant bridgedWOETHStrategy =\n BridgedWOETHStrategy(0x1E3EdD5e019207D6355Ea77F724b1F1BF639B569);\n\n constructor(address _safeContract) AbstractSafeModule(_safeContract) {}\n\n /**\n * @dev Bridges wOETH to Ethereum.\n * @param woethAmount Amount of wOETH to bridge.\n * @param slippageBps Slippage in 10^4 basis points.\n */\n function bridgeWOETHToEthereum(uint256 woethAmount, uint256 slippageBps)\n public\n payable\n onlyOperator\n {\n _bridgeTokenWithLz(\n LZ_ETHEREUM_ENDPOINT_ID,\n IERC20(address(bridgedWOETH)),\n LZ_WOETH_OMNICHAIN_ADAPTER,\n woethAmount,\n slippageBps,\n false\n );\n }\n\n /**\n * @dev Bridges wETH to Ethereum.\n * @param wethAmount Amount of wETH to bridge.\n * @param slippageBps Slippage in 10^4 basis points.\n */\n function bridgeWETHToEthereum(uint256 wethAmount, uint256 slippageBps)\n public\n payable\n onlyOperator\n {\n _bridgeTokenWithLz(\n LZ_ETHEREUM_ENDPOINT_ID,\n IERC20(address(weth)),\n LZ_ETH_OMNICHAIN_ADAPTER,\n wethAmount,\n slippageBps,\n false\n );\n }\n\n /**\n * @dev Deposits wOETH into the bridgedWOETH strategy.\n * @param woethAmount Amount of wOETH to deposit.\n * @param redeemWithVault Whether to redeem with Vault.\n * @return Amount of OETHp received.\n */\n function depositWOETH(uint256 woethAmount, bool redeemWithVault)\n external\n onlyOperator\n returns (uint256)\n {\n return _depositWOETH(woethAmount, redeemWithVault);\n }\n\n /**\n * @dev Deposits wOETH into the bridgedWOETH strategy and bridges it to Ethereum.\n * @param woethAmount Amount of wOETH to deposit.\n * @param slippageBps Slippage in 10^4 basis points.\n * @return Amount of WETH received.\n */\n function depositWOETHAndBridgeWETH(uint256 woethAmount, uint256 slippageBps)\n external\n payable\n onlyOperator\n returns (uint256)\n {\n uint256 wethAmount = _depositWOETH(woethAmount, true);\n bridgeWETHToEthereum(wethAmount, slippageBps);\n return wethAmount;\n }\n\n /**\n * @dev Deposits wOETH into the bridgedWOETH strategy.\n * @param woethAmount Amount of wOETH to deposit.\n * @param redeemWithVault Whether to redeem with Vault.\n * @return Amount of OETHp received.\n */\n function _depositWOETH(uint256 woethAmount, bool redeemWithVault)\n internal\n returns (uint256)\n {\n // Update oracle price\n bridgedWOETHStrategy.updateWOETHOraclePrice();\n\n // Rebase to account for any yields from price update\n vault.rebase();\n\n uint256 oethpAmount = oethp.balanceOf(address(safeContract));\n\n // Approve bridgedWOETH strategy to move wOETH\n bool success = safeContract.execTransactionFromModule(\n address(bridgedWOETH),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETH.approve.selector,\n address(bridgedWOETHStrategy),\n woethAmount\n ),\n 0 // Call\n );\n\n // Deposit to bridgedWOETH strategy\n success = safeContract.execTransactionFromModule(\n address(bridgedWOETHStrategy),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETHStrategy.depositBridgedWOETH.selector,\n woethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to deposit bridged WOETH\");\n\n oethpAmount = oethp.balanceOf(address(safeContract)) - oethpAmount;\n\n // Rebase to account for any yields from price update\n // and backing asset change from deposit\n vault.rebase();\n\n if (!redeemWithVault) {\n return oethpAmount;\n }\n\n // Redeem for WETH using Vault\n // redeem(uint256,uint256) was removed from VaultCore; use hardcoded selector\n success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(\n bytes4(keccak256(\"redeem(uint256,uint256)\")),\n oethpAmount,\n oethpAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to redeem OETHp\");\n\n return oethpAmount;\n }\n\n /**\n * @dev Deposits wETH into the vault.\n * @param wethAmount Amount of wETH to deposit.\n * @return Amount of OETHp received.\n */\n function depositWETHAndRedeemWOETH(uint256 wethAmount)\n external\n onlyOperator\n returns (uint256)\n {\n return _withdrawWOETH(wethAmount);\n }\n\n /**\n * @dev Deposits wETH into the vault and bridges it to Ethereum.\n * @param wethAmount Amount of wETH to deposit.\n * @param slippageBps Slippage in 10^4 basis points.\n * @return Amount of WOETH received.\n */\n function depositWETHAndBridgeWOETH(uint256 wethAmount, uint256 slippageBps)\n external\n payable\n onlyOperator\n returns (uint256)\n {\n uint256 woethAmount = _withdrawWOETH(wethAmount);\n bridgeWOETHToEthereum(woethAmount, slippageBps);\n return woethAmount;\n }\n\n /**\n * @dev Withdraws wOETH from the bridgedWOETH strategy.\n * @param wethAmount Amount of WETH to use to withdraw.\n * @return Amount of wOETH received.\n */\n function _withdrawWOETH(uint256 wethAmount) internal returns (uint256) {\n // Approve Vault to move WETH\n bool success = safeContract.execTransactionFromModule(\n address(weth),\n 0, // Value\n abi.encodeWithSelector(\n weth.approve.selector,\n address(vault),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve WETH\");\n\n // Mint OETHp with WETH\n // mint(address,uint256,uint256) was removed from IVault; use hardcoded selector\n success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(\n bytes4(keccak256(\"mint(address,uint256,uint256)\")),\n address(weth),\n wethAmount,\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to mint OETHp\");\n\n // Approve bridgedWOETH strategy to move OETHp\n success = safeContract.execTransactionFromModule(\n address(oethp),\n 0, // Value\n abi.encodeWithSelector(\n oethp.approve.selector,\n address(bridgedWOETHStrategy),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve OETHp\");\n\n uint256 woethAmount = bridgedWOETH.balanceOf(address(safeContract));\n\n // Withdraw from bridgedWOETH strategy\n success = safeContract.execTransactionFromModule(\n address(bridgedWOETHStrategy),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETHStrategy.withdrawBridgedWOETH.selector,\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to withdraw bridged WOETH\");\n\n woethAmount =\n bridgedWOETH.balanceOf(address(safeContract)) -\n woethAmount;\n\n return woethAmount;\n }\n}\n" + }, + "contracts/automation/RebalancerModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractSafeModule } from \"./AbstractSafeModule.sol\";\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { VaultStorage } from \"../vault/VaultStorage.sol\";\n\n/**\n * @title Rebalancer Module\n * @notice A Gnosis Safe module that automates OUSD vault rebalancing by\n * withdrawing from overallocated strategies and depositing to\n * underallocated strategies.\n *\n * @dev The Safe (Guardian multisig) must:\n * 1. Deploy this module\n * 2. Call `safe.enableModule(address(this))` to authorize it\n *\n * An off-chain operator (e.g. Defender Action) calls\n * `processWithdrawalsAndDeposits` periodically with computed strategy/amount\n * arrays. Either array may be empty. All intelligence (APY fetching, target\n * allocation, constraint enforcement) lives off-chain. This contract is a\n * dumb executor.\n *\n * The function uses soft failures: if a single strategy call fails via the\n * Safe, the module emits an event and continues to the next strategy rather\n * than reverting the entire batch.\n *\n * The Safe retains full control via `setPaused`.\n */\ncontract RebalancerModule is AbstractSafeModule {\n // ───────────────────────────────────────────────────────── Immutables ──\n\n /// @notice The vault whose strategies are being rebalanced.\n IVault public immutable vault;\n\n /// @notice The vault's base asset (e.g. USDC for OUSD).\n address public immutable asset;\n\n // ────────────────────────────────────────────────────── Mutable config ──\n\n /// @notice When true, processWithdrawalsAndDeposits is blocked.\n bool public paused;\n\n /// @notice Strategies that this module is permitted to withdraw from or deposit into.\n mapping(address => bool) public isAllowedStrategy;\n\n /// @notice Cumulative amount moved (withdrawals + deposits) per calendar day.\n /// Day key = block.timestamp / 1 days (i.e. days since Unix epoch).\n mapping(uint256 => uint256) public amountMovedPerDay;\n\n /// @notice Max percentage of vault TVL that can be moved in a single day.\n /// In basis points (e.g. 20000 = 200%).\n uint256 public maxDailyMovementBps;\n\n // ─────────────────────────────────────────────────────────── Events ──\n\n /// @notice Emitted after processWithdrawals completes (even if some failed).\n event WithdrawalsProcessed(\n address[] strategies,\n uint256[] amounts,\n uint256 remainingShortfall\n );\n\n /// @notice Emitted after processDeposits completes (even if some failed).\n event DepositsProcessed(address[] strategies, uint256[] amounts);\n\n /// @notice Emitted when a single withdrawFromStrategy call fails via the Safe.\n event WithdrawalFailed(address indexed strategy, uint256 attemptedAmount);\n\n /// @notice Emitted when a single depositToStrategy call fails via the Safe.\n event DepositFailed(address indexed strategy, uint256 attemptedAmount);\n\n /// @notice Emitted when the paused state changes.\n event PausedStateChanged(bool paused);\n\n /// @notice Emitted when a strategy is added to the whitelist.\n event StrategyAllowed(address indexed strategy);\n\n /// @notice Emitted when a strategy is removed from the whitelist.\n event StrategyRevoked(address indexed strategy);\n\n /// @notice Emitted when the daily movement limit is updated.\n event MaxDailyMovementBpsSet(uint256 maxDailyMovementBps);\n\n // ─────────────────────────────────────────────────────── Constructor ──\n\n /**\n * @param _safeContract Address of the Gnosis Safe (Guardian multisig).\n * @param _operator Address of the off-chain operator (e.g. Defender relayer).\n * @param _vault Address of the OUSD vault.\n */\n constructor(\n address _safeContract,\n address _operator,\n address _vault\n ) AbstractSafeModule(_safeContract) {\n require(_vault != address(0), \"Invalid vault\");\n\n vault = IVault(_vault);\n asset = IVault(_vault).asset();\n maxDailyMovementBps = 20000; // 200%\n\n _grantRole(OPERATOR_ROLE, _operator);\n }\n\n // ──────────────────────────────────────────────────────── Modifiers ──\n\n modifier whenNotPaused() {\n require(!paused, \"Module is paused\");\n _;\n }\n\n // ──────────────────────────────────────────────── Core automation ──\n\n // slither-disable-start reentrancy-no-eth\n /**\n * @notice Withdraw from overallocated strategies then deposit to underallocated\n * ones. Either array may be empty — the contract loops over zero entries\n * without reverting.\n *\n * @param _withdrawStrategies Strategies to withdraw from.\n * @param _withdrawAmounts Amounts to withdraw from each strategy.\n * @param _depositStrategies Strategies to deposit into.\n * @param _depositAmounts Amounts to deposit into each strategy.\n */\n function processWithdrawalsAndDeposits(\n address[] calldata _withdrawStrategies,\n uint256[] calldata _withdrawAmounts,\n address[] calldata _depositStrategies,\n uint256[] calldata _depositAmounts\n ) external onlyOperator whenNotPaused {\n require(\n _withdrawStrategies.length == _withdrawAmounts.length,\n \"Withdraw array length mismatch\"\n );\n require(\n _depositStrategies.length == _depositAmounts.length,\n \"Deposit array length mismatch\"\n );\n // This is a permissionless call; no Safe exec needed.\n vault.addWithdrawalQueueLiquidity();\n uint256 _limit = dailyLimit();\n _executeWithdrawals(_withdrawStrategies, _withdrawAmounts, _limit);\n _executeDeposits(_depositStrategies, _depositAmounts, _limit);\n emit WithdrawalsProcessed(\n _withdrawStrategies,\n _withdrawAmounts,\n pendingShortfall()\n );\n emit DepositsProcessed(_depositStrategies, _depositAmounts);\n }\n\n // ─────────────────────────────────────── Guardian controls ──\n\n /**\n * @notice Pause or unpause the module.\n * @param _paused True to pause, false to unpause.\n */\n function setPaused(bool _paused) external onlySafe {\n paused = _paused;\n emit PausedStateChanged(_paused);\n }\n\n /**\n * @notice Add a strategy to the whitelist, allowing the operator to move\n * funds into or out of it.\n * @param _strategy Strategy address to allow.\n */\n function allowStrategy(address _strategy) external onlySafe {\n require(_strategy != address(0), \"Invalid strategy\");\n isAllowedStrategy[_strategy] = true;\n emit StrategyAllowed(_strategy);\n }\n\n /**\n * @notice Remove a strategy from the whitelist.\n * @param _strategy Strategy address to revoke.\n */\n function revokeStrategy(address _strategy) external onlySafe {\n isAllowedStrategy[_strategy] = false;\n emit StrategyRevoked(_strategy);\n }\n\n /**\n * @notice Set the maximum percentage of vault TVL that can be moved per day.\n * @param _maxDailyMovementBps Limit in basis points (e.g. 20000 = 200%).\n * Set to 0 for unlimited daily movement.\n */\n function setMaxDailyMovementBps(uint256 _maxDailyMovementBps)\n external\n onlySafe\n {\n maxDailyMovementBps = _maxDailyMovementBps;\n emit MaxDailyMovementBpsSet(_maxDailyMovementBps);\n }\n\n // ──────────────────────────────────────────────────────── View helpers ──\n\n /**\n * @notice The current unmet shortfall in the vault's withdrawal queue.\n * @dev This is a raw read of `queued - claimable`. It does NOT account for\n * idle vault asset that `addWithdrawalQueueLiquidity()` would absorb.\n * For a fully up-to-date figure, call `vault.addWithdrawalQueueLiquidity()`\n * first (which is what `processWithdrawals` does).\n * @return shortfall Queue shortfall in asset units (vault asset decimals).\n */\n function pendingShortfall() public view returns (uint256 shortfall) {\n VaultStorage.WithdrawalQueueMetadata memory meta = vault\n .withdrawalQueueMetadata();\n shortfall = meta.queued - meta.claimable;\n }\n\n /**\n * @notice The daily movement limit based on current vault TVL.\n * @dev vault.totalValue() includes AMO (Automated Market Operations)\n * value. Excluding AMO would add significant complexity for minimal\n * accuracy gain, so the limit is slightly more generous than intended.\n * Additionally, if the vault's TVL changes significantly mid-day (e.g.\n * large mint/redeem), the limit will reflect the TVL at call time —\n * this is acceptable since the limit is a safety backstop, not a\n * precise cap.\n * If maxDailyMovementBps is set to 0, this returns type(uint256).max\n * as a sentinel value to represent an unlimited cap.\n * @return limit Amount in asset units (vault asset decimals).\n */\n function dailyLimit() public view returns (uint256 limit) {\n if (maxDailyMovementBps == 0) {\n return type(uint256).max;\n }\n limit = (vault.totalValue() * maxDailyMovementBps) / 10000;\n }\n\n /**\n * @notice The remaining amount that can be moved today before hitting the\n * daily movement limit.\n * @return remaining Amount in asset units (vault asset decimals).\n */\n function remainingDailyLimit() public view returns (uint256 remaining) {\n uint256 limit = dailyLimit();\n uint256 used = amountMovedPerDay[block.timestamp / 1 days];\n remaining = used >= limit ? 0 : limit - used;\n }\n\n // ──────────────────────────────────────────────── Internal helpers ──\n\n /// @dev Track cumulative daily movement and revert if the limit is exceeded.\n function _trackMovement(uint256 _amount, uint256 _dailyLimit) internal {\n uint256 dayKey = block.timestamp / 1 days;\n amountMovedPerDay[dayKey] += _amount;\n\n require(\n amountMovedPerDay[dayKey] <= _dailyLimit,\n \"Daily movement limit exceeded\"\n );\n }\n\n /// @dev Execute withdrawFromStrategy for each (strategy, amount) pair via the Safe.\n function _executeWithdrawals(\n address[] calldata _strategies,\n uint256[] calldata _amounts,\n uint256 _dailyLimit\n ) internal {\n address[] memory assets = _toAddressArray(asset);\n for (uint256 i = 0; i < _strategies.length; i++) {\n if (_amounts[i] == 0) continue;\n require(isAllowedStrategy[_strategies[i]], \"Strategy not allowed\");\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0,\n abi.encodeWithSelector(\n IVault.withdrawFromStrategy.selector,\n _strategies[i],\n assets,\n _toUint256Array(_amounts[i])\n ),\n 0\n );\n if (success) {\n _trackMovement(_amounts[i], _dailyLimit);\n } else {\n emit WithdrawalFailed(_strategies[i], _amounts[i]);\n }\n }\n }\n\n /// @dev Execute depositToStrategy for each (strategy, amount) pair via the Safe.\n function _executeDeposits(\n address[] calldata _strategies,\n uint256[] calldata _amounts,\n uint256 _dailyLimit\n ) internal {\n address[] memory assets = _toAddressArray(asset);\n for (uint256 i = 0; i < _strategies.length; i++) {\n if (_amounts[i] == 0) continue;\n require(isAllowedStrategy[_strategies[i]], \"Strategy not allowed\");\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0,\n abi.encodeWithSelector(\n IVault.depositToStrategy.selector,\n _strategies[i],\n assets,\n _toUint256Array(_amounts[i])\n ),\n 0\n );\n if (success) {\n _trackMovement(_amounts[i], _dailyLimit);\n } else {\n emit DepositFailed(_strategies[i], _amounts[i]);\n }\n }\n }\n\n // slither-disable-end reentrancy-no-eth\n\n function _toAddressArray(address _addr)\n internal\n pure\n returns (address[] memory arr)\n {\n arr = new address[](1);\n arr[0] = _addr;\n }\n\n function _toUint256Array(uint256 _val)\n internal\n pure\n returns (uint256[] memory arr)\n {\n arr = new uint256[](1);\n arr[0] = _val;\n }\n}\n" + }, + "contracts/beacon/BeaconConsolidation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library to request validator consolidation on the beacon chain.\n * @author Origin Protocol Inc\n */\nlibrary BeaconConsolidation {\n /// @notice The address the validator consolidation requests are sent\n /// See https://eips.ethereum.org/EIPS/eip-7251\n address internal constant CONSOLIDATION_REQUEST_ADDRESS =\n 0x0000BBdDc7CE488642fb579F8B00f3a590007251;\n\n function request(bytes calldata source, bytes calldata target)\n internal\n returns (uint256 fee_)\n {\n require(source.length == 48, \"Invalid source byte length\");\n require(target.length == 48, \"Invalid target byte length\");\n\n fee_ = fee();\n\n // Call the Consolidation Request contract with the public keys of the source and target\n // validators packed together.\n // This does not have a function signature, so we use a call\n (bool success, ) = CONSOLIDATION_REQUEST_ADDRESS.call{ value: fee_ }(\n abi.encodePacked(source, target)\n );\n\n require(success, \"Consolidation request failed\");\n }\n\n function fee() internal view returns (uint256) {\n // Get fee from the consolidation request contract\n (bool success, bytes memory result) = CONSOLIDATION_REQUEST_ADDRESS\n .staticcall(\"\");\n\n require(success && result.length > 0, \"Failed to get fee\");\n return abi.decode(result, (uint256));\n }\n}\n" + }, + "contracts/beacon/BeaconRoots.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library to retrieve beacon block roots.\n * @author Origin Protocol Inc\n */\nlibrary BeaconRoots {\n /// @notice The address of beacon block roots oracle\n /// See https://eips.ethereum.org/EIPS/eip-4788\n address internal constant BEACON_ROOTS_ADDRESS =\n 0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02;\n\n /// @notice Returns the beacon block root for the previous block.\n /// This comes from the Beacon Roots contract defined in EIP-4788.\n /// This will revert if the block is more than 8,191 blocks old as\n /// that is the size of the beacon root's ring buffer.\n /// @param timestamp The timestamp of the block for which to get the parent root.\n /// @return parentRoot The parent block root for the given timestamp.\n function parentBlockRoot(uint64 timestamp)\n internal\n view\n returns (bytes32 parentRoot)\n {\n // Call the Beacon Roots contract to get the parent block root.\n // This does not have a function signature, so we use a staticcall.\n (bool success, bytes memory result) = BEACON_ROOTS_ADDRESS.staticcall(\n abi.encode(timestamp)\n );\n\n require(success && result.length > 0, \"Invalid beacon timestamp\");\n parentRoot = abi.decode(result, (bytes32));\n }\n}\n" + }, + "contracts/beacon/PartialWithdrawal.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library to request full or partial withdrawals from validators on the beacon chain.\n * @author Origin Protocol Inc\n */\nlibrary PartialWithdrawal {\n /// @notice The address where the withdrawal request is sent to\n /// See https://eips.ethereum.org/EIPS/eip-7002\n address internal constant WITHDRAWAL_REQUEST_ADDRESS =\n 0x00000961Ef480Eb55e80D19ad83579A64c007002;\n\n /// @notice Requests a partial withdrawal for a given validator public key and amount.\n /// @param validatorPubKey The public key of the validator to withdraw from\n /// @param amount The amount of ETH to withdraw\n function request(bytes calldata validatorPubKey, uint64 amount)\n internal\n returns (uint256 fee_)\n {\n require(validatorPubKey.length == 48, \"Invalid validator byte length\");\n fee_ = fee();\n\n // Call the Withdrawal Request contract with the validator public key\n // and amount to be withdrawn packed together\n\n // This is a general purpose EL to CL request:\n // https://eips.ethereum.org/EIPS/eip-7685\n (bool success, ) = WITHDRAWAL_REQUEST_ADDRESS.call{ value: fee_ }(\n abi.encodePacked(validatorPubKey, amount)\n );\n\n require(success, \"Withdrawal request failed\");\n }\n\n /// @notice Gets fee for withdrawal requests contract on Beacon chain\n function fee() internal view returns (uint256) {\n // Get fee from the withdrawal request contract\n (bool success, bytes memory result) = WITHDRAWAL_REQUEST_ADDRESS\n .staticcall(\"\");\n\n require(success && result.length > 0, \"Failed to get fee\");\n return abi.decode(result, (uint256));\n }\n}\n" + }, + "contracts/echidna/Debugger.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Debugger {\n event Debug(string debugString);\n event Debug(string description, string data);\n event Debug(string prefix, string description, string data);\n event Debug(string description, bytes32 data);\n event Debug(string prefix, string description, bytes32 data);\n event Debug(string description, uint256 data);\n event Debug(string prefix, string description, uint256 data);\n event Debug(string description, int256 data);\n event Debug(string prefix, string description, int256 data);\n event Debug(string description, address data);\n event Debug(string prefix, string description, address data);\n event Debug(string description, bool data);\n event Debug(string prefix, string description, bool data);\n\n function log(string memory debugString) internal {\n emit Debug(debugString);\n }\n\n function log(string memory description, string memory data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n string memory data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, bytes32 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n bytes32 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, uint256 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n uint256 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, int256 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n int256 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, address data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n address data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, bool data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n bool data\n ) internal {\n emit Debug(prefix, description, data);\n }\n}\n" + }, + "contracts/echidna/Echidna.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaTestApproval.sol\";\n\n/**\n * @title Echidna test contract for OUSD\n * @notice Target contract to be tested, containing all mixins\n * @author Rappie\n */\ncontract Echidna is EchidnaTestApproval {\n\n}\n" + }, + "contracts/echidna/EchidnaConfig.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Top-level mixin for configuring the desired fuzzing setup\n * @author Rappie\n */\ncontract EchidnaConfig {\n address internal constant ADDRESS_VAULT = address(0x10000);\n address internal constant ADDRESS_OUTSIDER_USER = address(0x20000);\n\n address internal constant ADDRESS_USER0 = address(0x30000);\n address internal constant ADDRESS_USER1 = address(0x40000);\n\n // Will be set in EchidnaSetup constructor\n address internal ADDRESS_OUTSIDER_CONTRACT;\n address internal ADDRESS_CONTRACT0;\n address internal ADDRESS_CONTRACT1;\n\n // Toggle known issues\n //\n // This can be used to skip tests that are known to fail. This is useful\n // when debugging a specific issue, but should be disabled when running\n // the full test suite.\n //\n // True => skip tests that are known to fail\n // False => run all tests\n //\n bool internal constant TOGGLE_KNOWN_ISSUES = false;\n\n // Toggle known issues within limits\n //\n // Same as TOGGLE_KNOWN_ISSUES, but also skip tests that are known to fail\n // within limits set by the variables below.\n //\n bool internal constant TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS = true;\n\n // Starting balance\n //\n // Gives OUSD a non-zero starting supply, which can be useful to ignore\n // certain edge cases.\n //\n // The starting balance is given to outsider accounts that are not used as\n // accounts while fuzzing.\n //\n bool internal constant TOGGLE_STARTING_BALANCE = true;\n uint256 internal constant STARTING_BALANCE = 1_000_000e18;\n\n // Change supply\n //\n // Set a limit to the amount of change per rebase, which can be useful to\n // ignore certain edge cases.\n //\n // True => limit the amount of change to a percentage of total supply\n // False => no limit\n //\n bool internal constant TOGGLE_CHANGESUPPLY_LIMIT = true;\n uint256 internal constant CHANGESUPPLY_DIVISOR = 10; // 10% of total supply\n\n // Mint limit\n //\n // Set a limit the amount minted per mint, which can be useful to\n // ignore certain edge cases.\n //\n // True => limit the amount of minted tokens\n // False => no limit\n //\n bool internal constant TOGGLE_MINT_LIMIT = true;\n uint256 internal constant MINT_MODULO = 1_000_000_000_000e18;\n\n // Known rounding errors\n uint256 internal constant TRANSFER_ROUNDING_ERROR = 1e18 - 1;\n uint256 internal constant OPT_IN_ROUNDING_ERROR = 1e18 - 1;\n uint256 internal constant MINT_ROUNDING_ERROR = 1e18 - 1;\n\n /**\n * @notice Modifier to skip tests that are known to fail\n * @dev see TOGGLE_KNOWN_ISSUES for more information\n */\n modifier hasKnownIssue() {\n if (TOGGLE_KNOWN_ISSUES) return;\n _;\n }\n\n /**\n * @notice Modifier to skip tests that are known to fail within limits\n * @dev see TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS for more information\n */\n modifier hasKnownIssueWithinLimits() {\n if (TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS) return;\n _;\n }\n\n /**\n * @notice Translate an account ID to an address\n * @param accountId The ID of the account\n * @return account The address of the account\n */\n function getAccount(uint8 accountId)\n internal\n view\n returns (address account)\n {\n accountId = accountId / 64;\n if (accountId == 0) return account = ADDRESS_USER0;\n if (accountId == 1) return account = ADDRESS_USER1;\n if (accountId == 2) return account = ADDRESS_CONTRACT0;\n if (accountId == 3) return account = ADDRESS_CONTRACT1;\n require(false, \"Unknown account ID\");\n }\n}\n" + }, + "contracts/echidna/EchidnaDebug.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"./EchidnaHelper.sol\";\nimport \"./Debugger.sol\";\n\nimport \"../token/OUSD.sol\";\n\n/**\n * @title Room for random debugging functions\n * @author Rappie\n */\ncontract EchidnaDebug is EchidnaHelper {\n function debugOUSD() public pure {\n // assert(ousd.balanceOf(ADDRESS_USER0) == 1000);\n // assert(ousd.rebaseState(ADDRESS_USER0) != OUSD.RebaseOptions.OptIn);\n // assert(Address.isContract(ADDRESS_CONTRACT0));\n // Debugger.log(\"nonRebasingSupply\", ousd.nonRebasingSupply());\n // assert(false);\n }\n}\n" + }, + "contracts/echidna/EchidnaHelper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaSetup.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin containing helper functions\n * @author Rappie\n */\ncontract EchidnaHelper is EchidnaSetup {\n /**\n * @notice Mint tokens to an account\n * @param toAcc Account to mint to\n * @param amount Amount to mint\n * @return Amount minted (in case of capped mint with modulo)\n */\n function mint(uint8 toAcc, uint256 amount) public returns (uint256) {\n address to = getAccount(toAcc);\n\n if (TOGGLE_MINT_LIMIT) {\n amount = amount % MINT_MODULO;\n }\n\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(to, amount);\n\n return amount;\n }\n\n /**\n * @notice Burn tokens from an account\n * @param fromAcc Account to burn from\n * @param amount Amount to burn\n */\n function burn(uint8 fromAcc, uint256 amount) public {\n address from = getAccount(fromAcc);\n hevm.prank(ADDRESS_VAULT);\n ousd.burn(from, amount);\n }\n\n /**\n * @notice Change the total supply of OUSD (rebase)\n * @param amount New total supply\n */\n function changeSupply(uint256 amount) public {\n if (TOGGLE_CHANGESUPPLY_LIMIT) {\n amount =\n ousd.totalSupply() +\n (amount % (ousd.totalSupply() / CHANGESUPPLY_DIVISOR));\n }\n\n hevm.prank(ADDRESS_VAULT);\n ousd.changeSupply(amount);\n }\n\n /**\n * @notice Transfer tokens between accounts\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function transfer(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n ousd.transfer(to, amount);\n }\n\n /**\n * @notice Transfer approved tokens between accounts\n * @param authorizedAcc Account that is authorized to transfer\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function transferFrom(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n ousd.transferFrom(from, to, amount);\n }\n\n /**\n * @notice Opt in to rebasing\n * @param targetAcc Account to opt in\n */\n function optIn(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n hevm.prank(target);\n ousd.rebaseOptIn();\n }\n\n /**\n * @notice Opt out of rebasing\n * @param targetAcc Account to opt out\n */\n function optOut(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n hevm.prank(target);\n ousd.rebaseOptOut();\n }\n\n /**\n * @notice Approve an account to spend OUSD\n * @param ownerAcc Account that owns the OUSD\n * @param spenderAcc Account that is approved to spend the OUSD\n * @param amount Amount to approve\n */\n function approve(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n hevm.prank(owner);\n // slither-disable-next-line unused-return\n ousd.approve(spender, amount);\n }\n\n /**\n * @notice Get the sum of all OUSD balances\n * @return total Total balance\n */\n function getTotalBalance() public view returns (uint256 total) {\n total += ousd.balanceOf(ADDRESS_VAULT);\n total += ousd.balanceOf(ADDRESS_OUTSIDER_USER);\n total += ousd.balanceOf(ADDRESS_OUTSIDER_CONTRACT);\n total += ousd.balanceOf(ADDRESS_USER0);\n total += ousd.balanceOf(ADDRESS_USER1);\n total += ousd.balanceOf(ADDRESS_CONTRACT0);\n total += ousd.balanceOf(ADDRESS_CONTRACT1);\n }\n\n /**\n * @notice Get the sum of all non-rebasing OUSD balances\n * @return total Total balance\n */\n function getTotalNonRebasingBalance() public returns (uint256 total) {\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_VAULT)\n ? ousd.balanceOf(ADDRESS_VAULT)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_OUTSIDER_USER)\n ? ousd.balanceOf(ADDRESS_OUTSIDER_USER)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_OUTSIDER_CONTRACT)\n ? ousd.balanceOf(ADDRESS_OUTSIDER_CONTRACT)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_USER0)\n ? ousd.balanceOf(ADDRESS_USER0)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_USER1)\n ? ousd.balanceOf(ADDRESS_USER1)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_CONTRACT0)\n ? ousd.balanceOf(ADDRESS_CONTRACT0)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_CONTRACT1)\n ? ousd.balanceOf(ADDRESS_CONTRACT1)\n : 0;\n }\n}\n" + }, + "contracts/echidna/EchidnaSetup.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./IHevm.sol\";\nimport \"./EchidnaConfig.sol\";\nimport \"./OUSDEchidna.sol\";\n\ncontract Dummy {}\n\n/**\n * @title Mixin for setup and deployment\n * @author Rappie\n */\ncontract EchidnaSetup is EchidnaConfig {\n IHevm hevm = IHevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);\n OUSDEchidna ousd = new OUSDEchidna();\n\n /**\n * @notice Deploy the OUSD contract and set up initial state\n */\n constructor() {\n ousd.initialize(ADDRESS_VAULT, 1e18);\n\n // Deploy dummny contracts as users\n Dummy outsider = new Dummy();\n ADDRESS_OUTSIDER_CONTRACT = address(outsider);\n Dummy dummy0 = new Dummy();\n ADDRESS_CONTRACT0 = address(dummy0);\n Dummy dummy1 = new Dummy();\n ADDRESS_CONTRACT1 = address(dummy1);\n\n // Start out with a reasonable amount of OUSD\n if (TOGGLE_STARTING_BALANCE) {\n // Rebasing tokens\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(ADDRESS_OUTSIDER_USER, STARTING_BALANCE / 2);\n\n // Non-rebasing tokens\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(ADDRESS_OUTSIDER_CONTRACT, STARTING_BALANCE / 2);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestAccounting.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestSupply.sol\";\n\n/**\n * @title Mixin for testing accounting functions\n * @author Rappie\n */\ncontract EchidnaTestAccounting is EchidnaTestSupply {\n /**\n * @notice After opting in, balance should not increase. (Ok to lose rounding funds doing this)\n * @param targetAcc Account to opt in\n */\n function testOptInBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optIn(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter <= balanceBefore);\n }\n\n /**\n * @notice After opting out, balance should remain the same\n * @param targetAcc Account to opt out\n */\n function testOptOutBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optOut(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Account balance should remain the same after opting in minus rounding error\n * @param targetAcc Account to opt in\n */\n function testOptInBalanceRounding(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optIn(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n int256 delta = int256(balanceAfter) - int256(balanceBefore);\n Debugger.log(\"delta\", delta);\n\n // slither-disable-next-line tautology\n assert(-1 * delta >= 0);\n assert(-1 * delta <= int256(OPT_IN_ROUNDING_ERROR));\n }\n\n /**\n * @notice After opting in, total supply should remain the same\n * @param targetAcc Account to opt in\n */\n function testOptInTotalSupply(uint8 targetAcc) public {\n uint256 totalSupplyBefore = ousd.totalSupply();\n optIn(targetAcc);\n uint256 totalSupplyAfter = ousd.totalSupply();\n\n assert(totalSupplyAfter == totalSupplyBefore);\n }\n\n /**\n * @notice After opting out, total supply should remain the same\n * @param targetAcc Account to opt out\n */\n function testOptOutTotalSupply(uint8 targetAcc) public {\n uint256 totalSupplyBefore = ousd.totalSupply();\n optOut(targetAcc);\n uint256 totalSupplyAfter = ousd.totalSupply();\n\n assert(totalSupplyAfter == totalSupplyBefore);\n }\n\n /**\n * @notice Account balance should remain the same when a smart contract auto converts\n * @param targetAcc Account to auto convert\n */\n function testAutoConvertBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n // slither-disable-next-line unused-return\n ousd._isNonRebasingAccountEchidna(target);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice The `balanceOf` function should never revert\n * @param targetAcc Account to check balance of\n */\n function testBalanceOfShouldNotRevert(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n // slither-disable-next-line unused-return\n try ousd.balanceOf(target) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestApproval.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaTestMintBurn.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin for testing approval related functions\n * @author Rappie\n */\ncontract EchidnaTestApproval is EchidnaTestMintBurn {\n /**\n * @notice Performing `transferFrom` with an amount inside the allowance should not revert\n * @param authorizedAcc The account that is authorized to transfer\n * @param fromAcc The account that is transferring\n * @param toAcc The account that is receiving\n * @param amount The amount to transfer\n */\n function testTransferFromShouldNotRevert(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount <= ousd.balanceOf(from));\n require(amount <= ousd.allowance(from, authorized));\n\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n try ousd.transferFrom(from, to, amount) {\n // pass\n } catch {\n assert(false);\n }\n }\n\n /**\n * @notice Performing `transferFrom` with an amount outside the allowance should revert\n * @param authorizedAcc The account that is authorized to transfer\n * @param fromAcc The account that is transferring\n * @param toAcc The account that is receiving\n * @param amount The amount to transfer\n */\n function testTransferFromShouldRevert(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount > 0);\n require(\n !(amount <= ousd.balanceOf(from) &&\n amount <= ousd.allowance(from, authorized))\n );\n\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n try ousd.transferFrom(from, to, amount) {\n assert(false);\n } catch {\n // pass\n }\n }\n\n /**\n * @notice Approving an amount should update the allowance and overwrite any previous allowance\n * @param ownerAcc The account that is approving\n * @param spenderAcc The account that is being approved\n * @param amount The amount to approve\n */\n function testApprove(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n\n approve(ownerAcc, spenderAcc, amount);\n uint256 allowanceAfter1 = ousd.allowance(owner, spender);\n\n assert(allowanceAfter1 == amount);\n\n approve(ownerAcc, spenderAcc, amount / 2);\n uint256 allowanceAfter2 = ousd.allowance(owner, spender);\n\n assert(allowanceAfter2 == amount / 2);\n }\n}\n" + }, + "contracts/echidna/EchidnaTestMintBurn.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestAccounting.sol\";\n\n/**\n * @title Mixin for testing Mint and Burn functions\n * @author Rappie\n */\ncontract EchidnaTestMintBurn is EchidnaTestAccounting {\n /**\n * @notice Minting 0 tokens should not affect account balance\n * @param targetAcc Account to mint to\n */\n function testMintZeroBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n mint(targetAcc, 0);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Burning 0 tokens should not affect account balance\n * @param targetAcc Account to burn from\n */\n function testBurnZeroBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n burn(targetAcc, 0);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Minting tokens must increase the account balance by at least amount\n * @param targetAcc Account to mint to\n * @param amount Amount to mint\n * @custom:error testMintBalance(uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * testMintBalance(0,1)\n * Event sequence:\n * Debug(«balanceBefore», 0)\n * Debug(«balanceAfter», 0)\n */\n function testMintBalance(uint8 targetAcc, uint256 amount)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n uint256 amountMinted = mint(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n Debugger.log(\"amountMinted\", amountMinted);\n Debugger.log(\"balanceBefore\", balanceBefore);\n Debugger.log(\"balanceAfter\", balanceAfter);\n\n assert(balanceAfter >= balanceBefore + amountMinted);\n }\n\n /**\n * @notice Burning tokens must decrease the account balance by at least amount\n * @param targetAcc Account to burn from\n * @param amount Amount to burn\n * @custom:error testBurnBalance(uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * mint(0,3)\n * testBurnBalance(0,1)\n * Event sequence:\n * Debug(«balanceBefore», 2)\n * Debug(«balanceAfter», 2)\n */\n function testBurnBalance(uint8 targetAcc, uint256 amount)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n burn(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n Debugger.log(\"balanceBefore\", balanceBefore);\n Debugger.log(\"balanceAfter\", balanceAfter);\n\n assert(balanceAfter <= balanceBefore - amount);\n }\n\n /**\n * @notice Minting tokens should not increase the account balance by less than rounding error above amount\n * @param targetAcc Account to mint to\n * @param amount Amount to mint\n */\n function testMintBalanceRounding(uint8 targetAcc, uint256 amount) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n uint256 amountMinted = mint(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n int256 delta = int256(balanceAfter) - int256(balanceBefore);\n\n // delta == amount, if no error\n // delta < amount, if too little is minted\n // delta > amount, if too much is minted\n int256 error = int256(amountMinted) - delta;\n\n assert(error >= 0);\n assert(error <= int256(MINT_ROUNDING_ERROR));\n }\n\n /**\n * @notice A burn of an account balance must result in a zero balance\n * @param targetAcc Account to burn from\n */\n function testBurnAllBalanceToZero(uint8 targetAcc) public hasKnownIssue {\n address target = getAccount(targetAcc);\n\n burn(targetAcc, ousd.balanceOf(target));\n assert(ousd.balanceOf(target) == 0);\n }\n\n /**\n * @notice You should always be able to burn an account's balance\n * @param targetAcc Account to burn from\n */\n function testBurnAllBalanceShouldNotRevert(uint8 targetAcc)\n public\n hasKnownIssue\n {\n address target = getAccount(targetAcc);\n uint256 balance = ousd.balanceOf(target);\n\n hevm.prank(ADDRESS_VAULT);\n try ousd.burn(target, balance) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestSupply.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestTransfer.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n/**\n * @title Mixin for testing supply related functions\n * @author Rappie\n */\ncontract EchidnaTestSupply is EchidnaTestTransfer {\n using StableMath for uint256;\n\n uint256 prevRebasingCreditsPerToken = type(uint256).max;\n\n /**\n * @notice After a `changeSupply`, the total supply should exactly\n * match the target total supply. (This is needed to ensure successive\n * rebases are correct).\n * @param supply New total supply\n * @custom:error testChangeSupply(uint256): failed!💥\n * Call sequence:\n * testChangeSupply(1044505275072865171609)\n * Event sequence:\n * TotalSupplyUpdatedHighres(1044505275072865171610, 1000000000000000000000000, 957391048054055578595)\n */\n function testChangeSupply(uint256 supply)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n hevm.prank(ADDRESS_VAULT);\n ousd.changeSupply(supply);\n\n assert(ousd.totalSupply() == supply);\n }\n\n /**\n * @notice The total supply must not be less than the sum of account balances.\n * (The difference will go into future rebases)\n * @custom:error testTotalSupplyLessThanTotalBalance(): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(1)\n * optOut(64)\n * transfer(0,64,1)\n * testTotalSupplyLessThanTotalBalance()\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000001000001)\n * Debug(«totalBalance», 1000000000000000001000002)\n */\n function testTotalSupplyLessThanTotalBalance()\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n uint256 totalSupply = ousd.totalSupply();\n uint256 totalBalance = getTotalBalance();\n\n Debugger.log(\"totalSupply\", totalSupply);\n Debugger.log(\"totalBalance\", totalBalance);\n\n assert(totalSupply >= totalBalance);\n }\n\n /**\n * @notice Non-rebasing supply should not be larger than total supply\n * @custom:error testNonRebasingSupplyVsTotalSupply(): failed!💥\n * Call sequence:\n * mint(0,2)\n * changeSupply(3)\n * burn(0,1)\n * optOut(0)\n * testNonRebasingSupplyVsTotalSupply()\n */\n function testNonRebasingSupplyVsTotalSupply() public hasKnownIssue {\n uint256 nonRebasingSupply = ousd.nonRebasingSupply();\n uint256 totalSupply = ousd.totalSupply();\n\n assert(nonRebasingSupply <= totalSupply);\n }\n\n /**\n * @notice Global `rebasingCreditsPerToken` should never increase\n * @custom:error testRebasingCreditsPerTokenNotIncreased(): failed!💥\n * Call sequence:\n * testRebasingCreditsPerTokenNotIncreased()\n * changeSupply(1)\n * testRebasingCreditsPerTokenNotIncreased()\n */\n function testRebasingCreditsPerTokenNotIncreased() public hasKnownIssue {\n uint256 curRebasingCreditsPerToken = ousd\n .rebasingCreditsPerTokenHighres();\n\n Debugger.log(\n \"prevRebasingCreditsPerToken\",\n prevRebasingCreditsPerToken\n );\n Debugger.log(\"curRebasingCreditsPerToken\", curRebasingCreditsPerToken);\n\n assert(curRebasingCreditsPerToken <= prevRebasingCreditsPerToken);\n\n prevRebasingCreditsPerToken = curRebasingCreditsPerToken;\n }\n\n /**\n * @notice The rebasing credits per token ratio must greater than zero\n */\n function testRebasingCreditsPerTokenAboveZero() public {\n assert(ousd.rebasingCreditsPerTokenHighres() > 0);\n }\n\n /**\n * @notice The sum of all non-rebasing balances should not be larger than\n * non-rebasing supply\n * @custom:error testTotalNonRebasingSupplyLessThanTotalBalance(): failed!💥\n * Call sequence\n * mint(0,2)\n * changeSupply(1)\n * optOut(0)\n * burn(0,1)\n * testTotalNonRebasingSupplyLessThanTotalBalance()\n * Event sequence:\n * Debug(«totalNonRebasingSupply», 500000000000000000000001)\n * Debug(«totalNonRebasingBalance», 500000000000000000000002)\n */\n function testTotalNonRebasingSupplyLessThanTotalBalance()\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n uint256 totalNonRebasingSupply = ousd.nonRebasingSupply();\n uint256 totalNonRebasingBalance = getTotalNonRebasingBalance();\n\n Debugger.log(\"totalNonRebasingSupply\", totalNonRebasingSupply);\n Debugger.log(\"totalNonRebasingBalance\", totalNonRebasingBalance);\n\n assert(totalNonRebasingSupply >= totalNonRebasingBalance);\n }\n\n /**\n * @notice An accounts credits / credits per token should not be larger it's balance\n * @param targetAcc The account to check\n */\n function testCreditsPerTokenVsBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n (uint256 credits, uint256 creditsPerToken, ) = ousd\n .creditsBalanceOfHighres(target);\n uint256 expectedBalance = credits.divPrecisely(creditsPerToken);\n\n uint256 balance = ousd.balanceOf(target);\n\n Debugger.log(\"credits\", credits);\n Debugger.log(\"creditsPerToken\", creditsPerToken);\n Debugger.log(\"expectedBalance\", expectedBalance);\n Debugger.log(\"balance\", balance);\n\n assert(expectedBalance == balance);\n }\n}\n" + }, + "contracts/echidna/EchidnaTestTransfer.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin for testing transfer related functions\n * @author Rappie\n */\ncontract EchidnaTestTransfer is EchidnaDebug {\n /**\n * @notice The receiving account's balance after a transfer must not increase by\n * less than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferBalanceReceivedLess(uint8,uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * mint(64,2)\n * testTransferBalanceReceivedLess(64,0,1)\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000000500002)\n * Debug(«toBalBefore», 0)\n * Debug(«toBalAfter», 0)\n */\n function testTransferBalanceReceivedLess(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue hasKnownIssueWithinLimits {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n\n assert(toBalAfter >= toBalBefore + amount);\n }\n\n /**\n * @notice The receiving account's balance after a transfer must not\n * increase by more than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceReceivedMore(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n\n assert(toBalAfter <= toBalBefore + amount);\n }\n\n /**\n * @notice The sending account's balance after a transfer must not\n * decrease by less than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferBalanceSentLess(uint8,uint8,uint256): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(1)\n * testTransferBalanceSentLess(0,64,1)\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000000500001)\n * Debug(«fromBalBefore», 1)\n * Debug(«fromBalAfter», 1)\n */\n function testTransferBalanceSentLess(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue hasKnownIssueWithinLimits {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n\n assert(fromBalAfter <= fromBalBefore - amount);\n }\n\n /**\n * @notice The sending account's balance after a transfer must not\n * decrease by more than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceSentMore(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n\n assert(fromBalAfter >= fromBalBefore - amount);\n }\n\n /**\n * @notice The receiving account's balance after a transfer must not\n * increase by less than the amount transferred (minus rounding error)\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceReceivedLessRounding(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n int256 toDelta = int256(toBalAfter) - int256(toBalBefore);\n\n // delta == amount, if no error\n // delta < amount, if too little is sent\n // delta > amount, if too much is sent\n int256 error = int256(amount) - toDelta;\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n Debugger.log(\"toDelta\", toDelta);\n Debugger.log(\"error\", error);\n\n assert(error >= 0);\n assert(error <= int256(TRANSFER_ROUNDING_ERROR));\n }\n\n /**\n * @notice The sending account's balance after a transfer must\n * not decrease by less than the amount transferred (minus rounding error)\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceSentLessRounding(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n int256 fromDelta = int256(fromBalAfter) - int256(fromBalBefore);\n\n // delta == -amount, if no error\n // delta < -amount, if too much is sent\n // delta > -amount, if too little is sent\n int256 error = int256(amount) + fromDelta;\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n Debugger.log(\"fromDelta\", fromDelta);\n Debugger.log(\"error\", error);\n\n assert(error >= 0);\n assert(error <= int256(TRANSFER_ROUNDING_ERROR));\n }\n\n /**\n * @notice An account should always be able to successfully transfer\n * an amount within its balance.\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferWithinBalanceDoesNotRevert(uint8,uint8,uint8): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(3)\n * optOut(0)\n * testTransferWithinBalanceDoesNotRevert(0,128,2)\n * optIn(0)\n * testTransferWithinBalanceDoesNotRevert(128,0,1)\n * Event sequence:\n * error Revert Panic(17): SafeMath over-/under-flows\n */\n function testTransferWithinBalanceDoesNotRevert(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount > 0);\n amount = amount % ousd.balanceOf(from);\n\n Debugger.log(\"Total supply\", ousd.totalSupply());\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(to, amount) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n\n /**\n * @notice An account should never be able to successfully transfer\n * an amount greater than their balance.\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferExceedingBalanceReverts(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n amount = ousd.balanceOf(from) + 1 + amount;\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(to, amount) {\n assert(false);\n } catch {\n assert(true);\n }\n }\n\n /**\n * @notice A transfer to the same account should not change that account's balance\n * @param targetAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferSelf(uint8 targetAcc, uint256 amount) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n transfer(targetAcc, targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceBefore == balanceAfter);\n }\n\n /**\n * @notice Transfers to the zero account revert\n * @param fromAcc Account to transfer from\n * @param amount Amount to transfer\n */\n function testTransferToZeroAddress(uint8 fromAcc, uint256 amount) public {\n address from = getAccount(fromAcc);\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(address(0), amount) {\n assert(false);\n } catch {\n assert(true);\n }\n }\n}\n" + }, + "contracts/echidna/IHevm.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// https://github.com/ethereum/hevm/blob/main/doc/src/controlling-the-unit-testing-environment.md#cheat-codes\n\ninterface IHevm {\n function warp(uint256 x) external;\n\n function roll(uint256 x) external;\n\n function store(\n address c,\n bytes32 loc,\n bytes32 val\n ) external;\n\n function load(address c, bytes32 loc) external returns (bytes32 val);\n\n function sign(uint256 sk, bytes32 digest)\n external\n returns (\n uint8 v,\n bytes32 r,\n bytes32 s\n );\n\n function addr(uint256 sk) external returns (address addr);\n\n function ffi(string[] calldata) external returns (bytes memory);\n\n function prank(address sender) external;\n}\n" + }, + "contracts/echidna/OUSDEchidna.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../token/OUSD.sol\";\n\ncontract OUSDEchidna is OUSD {\n constructor() OUSD() {}\n\n function _isNonRebasingAccountEchidna(address _account)\n public\n returns (bool)\n {\n _autoMigrate(_account);\n return alternativeCreditsPerToken[_account] > 0;\n }\n}\n" + }, + "contracts/governance/Governable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\n * from owner to governor and renounce methods removed. Does not use\n * Context.sol like Ownable.sol does for simplification.\n * @author Origin Protocol Inc\n */\nabstract contract Governable {\n // Storage position of the owner and pendingOwner of the contract\n // keccak256(\"OUSD.governor\");\n bytes32 private constant governorPosition =\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\n\n // keccak256(\"OUSD.pending.governor\");\n bytes32 private constant pendingGovernorPosition =\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\n\n // keccak256(\"OUSD.reentry.status\");\n bytes32 private constant reentryStatusPosition =\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\n\n // See OpenZeppelin ReentrancyGuard implementation\n uint256 constant _NOT_ENTERED = 1;\n uint256 constant _ENTERED = 2;\n\n event PendingGovernorshipTransfer(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n\n event GovernorshipTransferred(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n\n /**\n * @notice Returns the address of the current Governor.\n */\n function governor() public view returns (address) {\n return _governor();\n }\n\n /**\n * @dev Returns the address of the current Governor.\n */\n function _governor() internal view returns (address governorOut) {\n bytes32 position = governorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n governorOut := sload(position)\n }\n }\n\n /**\n * @dev Returns the address of the pending Governor.\n */\n function _pendingGovernor()\n internal\n view\n returns (address pendingGovernor)\n {\n bytes32 position = pendingGovernorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n pendingGovernor := sload(position)\n }\n }\n\n /**\n * @dev Throws if called by any account other than the Governor.\n */\n modifier onlyGovernor() {\n require(isGovernor(), \"Caller is not the Governor\");\n _;\n }\n\n /**\n * @notice Returns true if the caller is the current Governor.\n */\n function isGovernor() public view returns (bool) {\n return msg.sender == _governor();\n }\n\n function _setGovernor(address newGovernor) internal {\n emit GovernorshipTransferred(_governor(), newGovernor);\n\n bytes32 position = governorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, newGovernor)\n }\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and make it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n bytes32 position = reentryStatusPosition;\n uint256 _reentry_status;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n _reentry_status := sload(position)\n }\n\n // On the first call to nonReentrant, _notEntered will be true\n require(_reentry_status != _ENTERED, \"Reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, _ENTERED)\n }\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, _NOT_ENTERED)\n }\n }\n\n function _setPendingGovernor(address newGovernor) internal {\n bytes32 position = pendingGovernorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, newGovernor)\n }\n }\n\n /**\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\n * Can only be called by the current Governor. Must be claimed for this to complete\n * @param _newGovernor Address of the new Governor\n */\n function transferGovernance(address _newGovernor) external onlyGovernor {\n _setPendingGovernor(_newGovernor);\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\n }\n\n /**\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\n * Can only be called by the new Governor.\n */\n function claimGovernance() external {\n require(\n msg.sender == _pendingGovernor(),\n \"Only the pending Governor can complete the claim\"\n );\n _changeGovernor(msg.sender);\n }\n\n /**\n * @dev Change Governance of the contract to a new account (`newGovernor`).\n * @param _newGovernor Address of the new Governor\n */\n function _changeGovernor(address _newGovernor) internal {\n require(_newGovernor != address(0), \"New Governor is address(0)\");\n _setGovernor(_newGovernor);\n }\n}\n" + }, + "contracts/governance/Strategizable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Governable } from \"./Governable.sol\";\n\ncontract Strategizable is Governable {\n event StrategistUpdated(address _address);\n\n // Address of strategist\n address public strategistAddr;\n\n // For future use\n uint256[50] private __gap;\n\n /**\n * @dev Verifies that the caller is either Governor or Strategist.\n */\n modifier onlyGovernorOrStrategist() virtual {\n require(\n msg.sender == strategistAddr || isGovernor(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n /**\n * @dev Set address of Strategist\n * @param _address Address of Strategist\n */\n function setStrategistAddr(address _address) external onlyGovernor {\n _setStrategistAddr(_address);\n }\n\n /**\n * @dev Set address of Strategist\n * @param _address Address of Strategist\n */\n function _setStrategistAddr(address _address) internal {\n strategistAddr = _address;\n emit StrategistUpdated(_address);\n }\n}\n" + }, + "contracts/harvest/AbstractHarvester.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { IUniswapV2Router } from \"../interfaces/uniswap/IUniswapV2Router02.sol\";\nimport { IUniswapV3Router } from \"../interfaces/uniswap/IUniswapV3Router.sol\";\nimport { IBalancerVault } from \"../interfaces/balancer/IBalancerVault.sol\";\nimport { ICurvePool } from \"../strategies/ICurvePool.sol\";\nimport \"../utils/Helpers.sol\";\n\nabstract contract AbstractHarvester is Governable {\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n using StableMath for uint256;\n\n enum SwapPlatform {\n UniswapV2Compatible,\n UniswapV3,\n Balancer,\n Curve\n }\n\n event SupportedStrategyUpdate(address strategyAddress, bool isSupported);\n event RewardTokenConfigUpdated(\n address tokenAddress,\n uint16 allowedSlippageBps,\n uint16 harvestRewardBps,\n SwapPlatform swapPlatform,\n address swapPlatformAddr,\n bytes swapData,\n uint256 liquidationLimit,\n bool doSwapRewardToken\n );\n event RewardTokenSwapped(\n address indexed rewardToken,\n address indexed swappedInto,\n SwapPlatform swapPlatform,\n uint256 amountIn,\n uint256 amountOut\n );\n event RewardProceedsTransferred(\n address indexed token,\n address farmer,\n uint256 protcolYield,\n uint256 farmerFee\n );\n event RewardProceedsAddressChanged(address newProceedsAddress);\n\n error EmptyAddress();\n error InvalidSlippageBps();\n error InvalidHarvestRewardBps();\n\n error InvalidSwapPlatform(SwapPlatform swapPlatform);\n\n error InvalidUniswapV2PathLength();\n error InvalidTokenInSwapPath(address token);\n error EmptyBalancerPoolId();\n error InvalidCurvePoolAssetIndex(address token);\n\n error UnsupportedStrategy(address strategyAddress);\n\n error SlippageError(uint256 actualBalance, uint256 minExpected);\n error BalanceMismatchAfterSwap(uint256 actualBalance, uint256 minExpected);\n\n // Configuration properties for harvesting logic of reward tokens\n struct RewardTokenConfig {\n // Max allowed slippage when swapping reward token for a stablecoin denominated in basis points.\n uint16 allowedSlippageBps;\n // Reward when calling a harvest function denominated in basis points.\n uint16 harvestRewardBps;\n // Address of compatible exchange protocol (Uniswap V2/V3, SushiSwap, Balancer and Curve).\n address swapPlatformAddr;\n /* When true the reward token is being swapped. In a need of (temporarily) disabling the swapping of\n * a reward token this needs to be set to false.\n */\n bool doSwapRewardToken;\n // Platform to use for Swapping\n SwapPlatform swapPlatform;\n /* How much token can be sold per one harvest call. If the balance of rewards tokens\n * exceeds that limit multiple harvest calls are required to harvest all of the tokens.\n * Set it to MAX_INT to effectively disable the limit.\n */\n uint256 liquidationLimit;\n }\n\n mapping(address => RewardTokenConfig) public rewardTokenConfigs;\n mapping(address => bool) public supportedStrategies;\n\n address public immutable vaultAddress;\n\n /**\n * Address receiving rewards proceeds. Initially the Vault contract later will possibly\n * be replaced by another contract that eases out rewards distribution.\n **/\n address public rewardProceedsAddress;\n\n /**\n * All tokens are swapped to this token before it gets transferred\n * to the `rewardProceedsAddress`. USDT for OUSD and WETH for OETH.\n **/\n address public immutable baseTokenAddress;\n // Cached decimals for `baseTokenAddress`\n uint256 public immutable baseTokenDecimals;\n\n // Uniswap V2 path for reward tokens using Uniswap V2 Router\n mapping(address => address[]) public uniswapV2Path;\n // Uniswap V3 path for reward tokens using Uniswap V3 Router\n mapping(address => bytes) public uniswapV3Path;\n // Pool ID to use for reward tokens on Balancer\n mapping(address => bytes32) public balancerPoolId;\n\n struct CurvePoolIndices {\n // Casted into uint128 and stored in a struct to save gas\n uint128 rewardTokenIndex;\n uint128 baseTokenIndex;\n }\n // Packed indices of assets on the Curve pool\n mapping(address => CurvePoolIndices) public curvePoolIndices;\n\n constructor(address _vaultAddress, address _baseTokenAddress) {\n require(_vaultAddress != address(0));\n require(_baseTokenAddress != address(0));\n\n vaultAddress = _vaultAddress;\n baseTokenAddress = _baseTokenAddress;\n\n // Cache decimals as well\n baseTokenDecimals = Helpers.getDecimals(_baseTokenAddress);\n }\n\n /***************************************\n Configuration\n ****************************************/\n\n /**\n * Set the Address receiving rewards proceeds.\n * @param _rewardProceedsAddress Address of the reward token\n */\n function setRewardProceedsAddress(address _rewardProceedsAddress)\n external\n onlyGovernor\n {\n if (_rewardProceedsAddress == address(0)) {\n revert EmptyAddress();\n }\n\n rewardProceedsAddress = _rewardProceedsAddress;\n emit RewardProceedsAddressChanged(_rewardProceedsAddress);\n }\n\n /**\n * @dev Add/update a reward token configuration that holds harvesting config variables\n * @param _tokenAddress Address of the reward token\n * @param tokenConfig.allowedSlippageBps uint16 maximum allowed slippage denominated in basis points.\n * Example: 300 == 3% slippage\n * @param tokenConfig.harvestRewardBps uint16 amount of reward tokens the caller of the function is rewarded.\n * Example: 100 == 1%\n * @param tokenConfig.swapPlatformAddr Address Address of a UniswapV2 compatible contract to perform\n * the exchange from reward tokens to stablecoin (currently hard-coded to USDT)\n * @param tokenConfig.liquidationLimit uint256 Maximum amount of token to be sold per one swap function call.\n * When value is 0 there is no limit.\n * @param tokenConfig.doSwapRewardToken bool Disables swapping of the token when set to true,\n * does not cause it to revert though.\n * @param tokenConfig.swapPlatform SwapPlatform to use for Swapping\n * @param swapData Additional data required for swapping\n */\n function setRewardTokenConfig(\n address _tokenAddress,\n RewardTokenConfig calldata tokenConfig,\n bytes calldata swapData\n ) external onlyGovernor {\n if (tokenConfig.allowedSlippageBps > 1000) {\n revert InvalidSlippageBps();\n }\n\n if (tokenConfig.harvestRewardBps > 1000) {\n revert InvalidHarvestRewardBps();\n }\n\n address newRouterAddress = tokenConfig.swapPlatformAddr;\n if (newRouterAddress == address(0)) {\n // Swap router address should be non zero address\n revert EmptyAddress();\n }\n\n address oldRouterAddress = rewardTokenConfigs[_tokenAddress]\n .swapPlatformAddr;\n rewardTokenConfigs[_tokenAddress] = tokenConfig;\n\n // Revert if feed does not exist\n // slither-disable-next-line unused-return\n\n IERC20 token = IERC20(_tokenAddress);\n // if changing token swap provider cancel existing allowance\n if (\n /* oldRouterAddress == address(0) when there is no pre-existing\n * configuration for said rewards token\n */\n oldRouterAddress != address(0) &&\n oldRouterAddress != newRouterAddress\n ) {\n token.safeApprove(oldRouterAddress, 0);\n }\n\n // Give SwapRouter infinite approval when needed\n if (oldRouterAddress != newRouterAddress) {\n token.safeApprove(newRouterAddress, 0);\n token.safeApprove(newRouterAddress, type(uint256).max);\n }\n\n SwapPlatform _platform = tokenConfig.swapPlatform;\n if (_platform == SwapPlatform.UniswapV2Compatible) {\n uniswapV2Path[_tokenAddress] = _decodeUniswapV2Path(\n swapData,\n _tokenAddress\n );\n } else if (_platform == SwapPlatform.UniswapV3) {\n uniswapV3Path[_tokenAddress] = _decodeUniswapV3Path(\n swapData,\n _tokenAddress\n );\n } else if (_platform == SwapPlatform.Balancer) {\n balancerPoolId[_tokenAddress] = _decodeBalancerPoolId(\n swapData,\n newRouterAddress,\n _tokenAddress\n );\n } else if (_platform == SwapPlatform.Curve) {\n curvePoolIndices[_tokenAddress] = _decodeCurvePoolIndices(\n swapData,\n newRouterAddress,\n _tokenAddress\n );\n } else {\n // Note: This code is unreachable since Solidity reverts when\n // the value is outside the range of defined values of the enum\n // (even if it's under the max length of the base type)\n revert InvalidSwapPlatform(_platform);\n }\n\n emit RewardTokenConfigUpdated(\n _tokenAddress,\n tokenConfig.allowedSlippageBps,\n tokenConfig.harvestRewardBps,\n _platform,\n newRouterAddress,\n swapData,\n tokenConfig.liquidationLimit,\n tokenConfig.doSwapRewardToken\n );\n }\n\n /**\n * @dev Decodes the data passed into Uniswap V2 path and validates\n * it to make sure the path is for `token` to `baseToken`\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @param token The address of the reward token\n * @return path The validated Uniswap V2 path\n */\n function _decodeUniswapV2Path(bytes calldata data, address token)\n internal\n view\n returns (address[] memory path)\n {\n (path) = abi.decode(data, (address[]));\n uint256 len = path.length;\n\n if (len < 2) {\n // Path should have at least two tokens\n revert InvalidUniswapV2PathLength();\n }\n\n // Do some validation\n if (path[0] != token) {\n revert InvalidTokenInSwapPath(path[0]);\n }\n\n if (path[len - 1] != baseTokenAddress) {\n revert InvalidTokenInSwapPath(path[len - 1]);\n }\n }\n\n /**\n * @dev Decodes the data passed into Uniswap V3 path and validates\n * it to make sure the path is for `token` to `baseToken`\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @param token The address of the reward token\n * @return path The validated Uniswap V3 path\n */\n function _decodeUniswapV3Path(bytes calldata data, address token)\n internal\n view\n returns (bytes calldata path)\n {\n path = data;\n\n address decodedAddress = address(uint160(bytes20(data[0:20])));\n\n if (decodedAddress != token) {\n // Invalid Reward Token in swap path\n revert InvalidTokenInSwapPath(decodedAddress);\n }\n\n decodedAddress = address(uint160(bytes20(data[path.length - 20:])));\n if (decodedAddress != baseTokenAddress) {\n // Invalid Base Token in swap path\n revert InvalidTokenInSwapPath(decodedAddress);\n }\n }\n\n /**\n * @dev Decodes the data passed to Balancer Pool ID\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @return poolId The pool ID\n */\n function _decodeBalancerPoolId(\n bytes calldata data,\n address balancerVault,\n address token\n ) internal view returns (bytes32 poolId) {\n (poolId) = abi.decode(data, (bytes32));\n\n if (poolId == bytes32(0)) {\n revert EmptyBalancerPoolId();\n }\n\n IBalancerVault bVault = IBalancerVault(balancerVault);\n\n // Note: this reverts if token is not a pool asset\n // slither-disable-next-line unused-return\n bVault.getPoolTokenInfo(poolId, token);\n\n // slither-disable-next-line unused-return\n bVault.getPoolTokenInfo(poolId, baseTokenAddress);\n }\n\n /**\n * @dev Decodes the data passed to get the pool indices and\n * checks it against the Curve Pool to make sure it's\n * not misconfigured. The indices are packed into a single\n * uint256 for gas savings\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @param poolAddress Curve pool address\n * @param token The address of the reward token\n * @return indices Packed pool asset indices\n */\n function _decodeCurvePoolIndices(\n bytes calldata data,\n address poolAddress,\n address token\n ) internal view returns (CurvePoolIndices memory indices) {\n indices = abi.decode(data, (CurvePoolIndices));\n\n ICurvePool pool = ICurvePool(poolAddress);\n if (token != pool.coins(indices.rewardTokenIndex)) {\n revert InvalidCurvePoolAssetIndex(token);\n }\n if (baseTokenAddress != pool.coins(indices.baseTokenIndex)) {\n revert InvalidCurvePoolAssetIndex(baseTokenAddress);\n }\n }\n\n /**\n * @dev Flags a strategy as supported or not supported one\n * @param _strategyAddress Address of the strategy\n * @param _isSupported Bool marking strategy as supported or not supported\n */\n function setSupportedStrategy(address _strategyAddress, bool _isSupported)\n external\n onlyGovernor\n {\n supportedStrategies[_strategyAddress] = _isSupported;\n emit SupportedStrategyUpdate(_strategyAddress, _isSupported);\n }\n\n /***************************************\n Rewards\n ****************************************/\n\n /**\n * @dev Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform. Can be called by anyone.\n * Rewards incentivizing the caller are sent to the caller of this function.\n * @param _strategyAddr Address of the strategy to collect rewards from\n */\n function harvestAndSwap(address _strategyAddr) external nonReentrant {\n // Remember _harvest function checks for the validity of _strategyAddr\n _harvestAndSwap(_strategyAddr, msg.sender);\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform. Can be called by anyone\n * @param _strategyAddr Address of the strategy to collect rewards from\n * @param _rewardTo Address where to send a share of harvest rewards to as an incentive\n * for executing this function\n */\n function harvestAndSwap(address _strategyAddr, address _rewardTo)\n external\n nonReentrant\n {\n // Remember _harvest function checks for the validity of _strategyAddr\n _harvestAndSwap(_strategyAddr, _rewardTo);\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform\n * @param _strategyAddr Address of the strategy to collect rewards from\n * @param _rewardTo Address where to send a share of harvest rewards to as an incentive\n * for executing this function\n */\n function _harvestAndSwap(address _strategyAddr, address _rewardTo)\n internal\n {\n _harvest(_strategyAddr);\n IStrategy strategy = IStrategy(_strategyAddr);\n address[] memory rewardTokens = strategy.getRewardTokenAddresses();\n uint256 len = rewardTokens.length;\n for (uint256 i = 0; i < len; ++i) {\n // This harvester contract is not used anymore. Keeping the code\n // for passing test deployment. Safe to use address(0x1) as oracle.\n _swap(rewardTokens[i], _rewardTo, IOracle(address(0x1)));\n }\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform\n * @param _strategyAddr Address of the strategy to collect rewards from.\n */\n function _harvest(address _strategyAddr) internal virtual {\n if (!supportedStrategies[_strategyAddr]) {\n revert UnsupportedStrategy(_strategyAddr);\n }\n\n IStrategy strategy = IStrategy(_strategyAddr);\n strategy.collectRewardTokens();\n }\n\n /**\n * @dev Swap a reward token for the base token on the configured\n * swap platform. The token must have a registered price feed\n * with the price provider\n * @param _swapToken Address of the token to swap\n * @param _rewardTo Address where to send the share of harvest rewards to\n * @param _priceProvider Oracle to get prices of the swap token\n */\n // This function is called by the harvestAndSwap function, which is only called by\n // functions that have the nonReentrant modifier. Therefore, this function is also non-reentrant.\n // slither-disable-start reentrancy-eth,reentrancy-no-eth,reentrancy-benign\n // slither-disable-start reentrancy-events,reentrancy-unlimited-gas,reentrancy-balance\n function _swap(\n address _swapToken,\n address _rewardTo,\n IOracle _priceProvider\n ) internal virtual {\n uint256 balance = IERC20(_swapToken).balanceOf(address(this));\n\n // No need to swap if the reward token is the base token. eg USDT or WETH.\n // There is also no limit on the transfer. Everything in the harvester will be transferred\n // to the Dripper regardless of the liquidationLimit config.\n if (_swapToken == baseTokenAddress) {\n IERC20(_swapToken).safeTransfer(rewardProceedsAddress, balance);\n // currently not paying the farmer any rewards as there is no swap\n emit RewardProceedsTransferred(\n baseTokenAddress,\n address(0),\n balance,\n 0\n );\n return;\n }\n\n RewardTokenConfig memory tokenConfig = rewardTokenConfigs[_swapToken];\n\n /* This will trigger a return when reward token configuration has not yet been set\n * or we have temporarily disabled swapping of specific reward token via setting\n * doSwapRewardToken to false.\n */\n if (!tokenConfig.doSwapRewardToken) {\n return;\n }\n\n if (balance == 0) {\n return;\n }\n\n if (tokenConfig.liquidationLimit > 0) {\n balance = Math.min(balance, tokenConfig.liquidationLimit);\n }\n\n // This'll revert if there is no price feed\n uint256 oraclePrice = _priceProvider.price(_swapToken);\n\n // Oracle price is 1e18\n uint256 minExpected = (balance *\n (1e4 - tokenConfig.allowedSlippageBps) * // max allowed slippage\n oraclePrice).scaleBy(\n baseTokenDecimals,\n Helpers.getDecimals(_swapToken)\n ) /\n 1e4 / // fix the max slippage decimal position\n 1e18; // and oracle price decimals position\n\n // Do the swap\n uint256 amountReceived = _doSwap(\n tokenConfig.swapPlatform,\n tokenConfig.swapPlatformAddr,\n _swapToken,\n balance,\n minExpected\n );\n\n if (amountReceived < minExpected) {\n revert SlippageError(amountReceived, minExpected);\n }\n\n emit RewardTokenSwapped(\n _swapToken,\n baseTokenAddress,\n tokenConfig.swapPlatform,\n balance,\n amountReceived\n );\n\n IERC20 baseToken = IERC20(baseTokenAddress);\n uint256 baseTokenBalance = baseToken.balanceOf(address(this));\n if (baseTokenBalance < amountReceived) {\n // Note: It's possible to bypass this check by transferring `baseToken`\n // directly to Harvester before calling the `harvestAndSwap`. However,\n // there's no incentive for an attacker to do that. Doing a balance diff\n // will increase the gas cost significantly\n revert BalanceMismatchAfterSwap(baseTokenBalance, amountReceived);\n }\n\n // Farmer only gets fee from the base amount they helped farm,\n // They do not get anything from anything that already was there\n // on the Harvester\n uint256 farmerFee = amountReceived.mulTruncateScale(\n tokenConfig.harvestRewardBps,\n 1e4\n );\n uint256 protocolYield = baseTokenBalance - farmerFee;\n\n baseToken.safeTransfer(rewardProceedsAddress, protocolYield);\n baseToken.safeTransfer(_rewardTo, farmerFee);\n emit RewardProceedsTransferred(\n baseTokenAddress,\n _rewardTo,\n protocolYield,\n farmerFee\n );\n }\n\n // slither-disable-end reentrancy-events,reentrancy-unlimited-gas,reentrancy-balance\n // slither-disable-end reentrancy-eth,reentrancy-no-eth,reentrancy-benign\n\n function _doSwap(\n SwapPlatform swapPlatform,\n address routerAddress,\n address rewardTokenAddress,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n if (swapPlatform == SwapPlatform.UniswapV2Compatible) {\n return\n _swapWithUniswapV2(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else if (swapPlatform == SwapPlatform.UniswapV3) {\n return\n _swapWithUniswapV3(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else if (swapPlatform == SwapPlatform.Balancer) {\n return\n _swapWithBalancer(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else if (swapPlatform == SwapPlatform.Curve) {\n return\n _swapWithCurve(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else {\n // Should never be invoked since we catch invalid values\n // in the `setRewardTokenConfig` function before it's set\n revert InvalidSwapPlatform(swapPlatform);\n }\n }\n\n /**\n * @dev Swaps the token to `baseToken` with Uniswap V2\n *\n * @param routerAddress Uniswap V2 Router address\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithUniswapV2(\n address routerAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n address[] memory path = uniswapV2Path[swapToken];\n\n uint256[] memory amounts = IUniswapV2Router(routerAddress)\n .swapExactTokensForTokens(\n amountIn,\n minAmountOut,\n path,\n address(this),\n block.timestamp\n );\n\n amountOut = amounts[amounts.length - 1];\n }\n\n /**\n * @dev Swaps the token to `baseToken` with Uniswap V3\n *\n * @param routerAddress Uniswap V3 Router address\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithUniswapV3(\n address routerAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n bytes memory path = uniswapV3Path[swapToken];\n\n IUniswapV3Router.ExactInputParams memory params = IUniswapV3Router\n .ExactInputParams({\n path: path,\n recipient: address(this),\n deadline: block.timestamp,\n amountIn: amountIn,\n amountOutMinimum: minAmountOut\n });\n amountOut = IUniswapV3Router(routerAddress).exactInput(params);\n }\n\n /**\n * @dev Swaps the token to `baseToken` on Balancer\n *\n * @param balancerVaultAddress BalancerVaultAddress\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithBalancer(\n address balancerVaultAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n bytes32 poolId = balancerPoolId[swapToken];\n\n IBalancerVault.SingleSwap memory singleSwap = IBalancerVault\n .SingleSwap({\n poolId: poolId,\n kind: IBalancerVault.SwapKind.GIVEN_IN,\n assetIn: swapToken,\n assetOut: baseTokenAddress,\n amount: amountIn,\n userData: hex\"\"\n });\n\n IBalancerVault.FundManagement memory fundMgmt = IBalancerVault\n .FundManagement({\n sender: address(this),\n fromInternalBalance: false,\n recipient: payable(address(this)),\n toInternalBalance: false\n });\n\n amountOut = IBalancerVault(balancerVaultAddress).swap(\n singleSwap,\n fundMgmt,\n minAmountOut,\n block.timestamp\n );\n }\n\n /**\n * @dev Swaps the token to `baseToken` on Curve\n *\n * @param poolAddress Curve Pool Address\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithCurve(\n address poolAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n CurvePoolIndices memory indices = curvePoolIndices[swapToken];\n\n // Note: Not all CurvePools return the `amountOut`, make sure\n // to use only pool that do. Otherwise the swap would revert\n // always\n amountOut = ICurvePool(poolAddress).exchange(\n uint256(indices.rewardTokenIndex),\n uint256(indices.baseTokenIndex),\n amountIn,\n minAmountOut\n );\n }\n}\n" + }, + "contracts/harvest/Dripper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\n/**\n * @title OUSD Dripper\n *\n * The dripper contract smooths out the yield from point-in-time yield events\n * and spreads the yield out over a configurable time period. This ensures a\n * continuous per block yield to makes users happy as their next rebase\n * amount is always moving up. Also, this makes historical day to day yields\n * smooth, rather than going from a near zero day, to a large APY day, then\n * back to a near zero day again.\n *\n *\n * Design notes\n * - USDT has a smaller resolution than the number of seconds\n * in a week, which can make per second payouts have a rounding error. However\n * the total effect is not large - cents per day, and this money is\n * not lost, just distributed in the future. While we could use a higher\n * decimal precision for the drip perSecond, we chose simpler code.\n * - By calculating the changing drip rates on collects only, harvests and yield\n * events don't have to call anything on this contract or pay any extra gas.\n * Collect() is already be paying for a single write, since it has to reset\n * the lastCollect time.\n * - By having a collectAndRebase method, and having our external systems call\n * that, the OUSD vault does not need any changes, not even to know the address\n * of the dripper.\n * - A rejected design was to retro-calculate the drip rate on each collect,\n * based on the balance at the time of the collect. While this would have\n * required less state, and would also have made the contract respond more quickly\n * to new income, it would break the predictability that is this contract's entire\n * purpose. If we did this, the amount of fundsAvailable() would make sharp increases\n * when funds were deposited.\n * - When the dripper recalculates the rate, it targets spending the balance over\n * the duration. This means that every time that collect is called, if no\n * new funds have been deposited the duration is being pushed back and the\n * rate decreases. This is expected, and ends up following a smoother but\n * longer curve the more collect() is called without incoming yield.\n *\n */\n\ncontract Dripper is Governable {\n using SafeERC20 for IERC20;\n\n struct Drip {\n uint64 lastCollect; // overflows 262 billion years after the sun dies\n uint192 perSecond; // drip rate per second\n }\n\n address immutable vault; // OUSD vault\n address immutable token; // token to drip out\n uint256 public dripDuration; // in seconds\n Drip public drip; // active drip parameters\n\n constructor(address _vault, address _token) {\n vault = _vault;\n token = _token;\n }\n\n /// @notice How much funds have dripped out already and are currently\n // available to be sent to the vault.\n /// @return The amount that would be sent if a collect was called\n function availableFunds() external view returns (uint256) {\n uint256 balance = IERC20(token).balanceOf(address(this));\n return _availableFunds(balance, drip);\n }\n\n /// @notice Collect all dripped funds and send to vault.\n /// Recalculate new drip rate.\n function collect() external {\n _collect();\n }\n\n /// @notice Collect all dripped funds, send to vault, recalculate new drip\n /// rate, and rebase OUSD.\n function collectAndRebase() external {\n _collect();\n IVault(vault).rebase();\n }\n\n /// @dev Change the drip duration. Governor only.\n /// @param _durationSeconds the number of seconds to drip out the entire\n /// balance over if no collects were called during that time.\n function setDripDuration(uint256 _durationSeconds)\n external\n virtual\n onlyGovernor\n {\n require(_durationSeconds > 0, \"duration must be non-zero\");\n dripDuration = _durationSeconds;\n _collect(); // duration change take immediate effect\n }\n\n /// @dev Transfer out ERC20 tokens held by the contract. Governor only.\n /// @param _asset ERC20 token address\n /// @param _amount amount to transfer\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /// @dev Calculate available funds by taking the lower of either the\n /// currently dripped out funds or the balance available.\n /// Uses passed in parameters to calculate with for gas savings.\n /// @param _balance current balance in contract\n /// @param _drip current drip parameters\n function _availableFunds(uint256 _balance, Drip memory _drip)\n internal\n view\n returns (uint256)\n {\n uint256 elapsed = block.timestamp - _drip.lastCollect;\n uint256 allowed = (elapsed * _drip.perSecond);\n return (allowed > _balance) ? _balance : allowed;\n }\n\n /// @dev Sends the currently dripped funds to be vault, and sets\n /// the new drip rate based on the new balance.\n function _collect() internal virtual {\n // Calculate send\n uint256 balance = IERC20(token).balanceOf(address(this));\n uint256 amountToSend = _availableFunds(balance, drip);\n uint256 remaining = balance - amountToSend;\n // Calculate new drip perSecond\n // Gas savings by setting entire struct at one time\n drip = Drip({\n perSecond: uint192(remaining / dripDuration),\n lastCollect: uint64(block.timestamp)\n });\n // Send funds\n IERC20(token).safeTransfer(vault, amountToSend);\n }\n\n /// @dev Transfer out all ERC20 held by the contract. Governor only.\n /// @param _asset ERC20 token address\n function transferAllToken(address _asset, address _receiver)\n external\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(\n _receiver,\n IERC20(_asset).balanceOf(address(this))\n );\n }\n}\n" + }, + "contracts/harvest/FixedRateDripper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { Dripper } from \"./Dripper.sol\";\n\n/**\n * @title Fixed Rate Dripper\n *\n * Similar to the Dripper, Fixed Rate Dripper drips out yield per second.\n * However the Strategist decides the rate and it doesn't change after\n * a drip.\n *\n */\n\ncontract FixedRateDripper is Dripper {\n using SafeERC20 for IERC20;\n\n event DripRateUpdated(uint192 oldDripRate, uint192 newDripRate);\n\n /**\n * @dev Verifies that the caller is the Governor or Strategist.\n */\n modifier onlyGovernorOrStrategist() {\n require(\n isGovernor() || msg.sender == IVault(vault).strategistAddr(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n constructor(address _vault, address _token) Dripper(_vault, _token) {}\n\n /// @inheritdoc Dripper\n function setDripDuration(uint256) external virtual override {\n // Not used in FixedRateDripper\n revert(\"Drip duration disabled\");\n }\n\n /// @inheritdoc Dripper\n function _collect() internal virtual override {\n // Calculate amount to send\n uint256 balance = IERC20(token).balanceOf(address(this));\n uint256 amountToSend = _availableFunds(balance, drip);\n\n // Update timestamp\n drip.lastCollect = uint64(block.timestamp);\n\n // Send funds\n IERC20(token).safeTransfer(vault, amountToSend);\n }\n\n /**\n * @dev Sets the drip rate. Callable by Strategist or Governor.\n * Can be set to zero to stop dripper.\n * @param _perSecond Rate of WETH to drip per second\n */\n function setDripRate(uint192 _perSecond) external onlyGovernorOrStrategist {\n emit DripRateUpdated(_perSecond, drip.perSecond);\n\n /**\n * Note: It's important to call `_collect` before updating\n * the drip rate especially on a new proxy contract.\n * When `lastCollect` is not set/initialized, the elapsed\n * time would be calculated as `block.number` seconds,\n * resulting in a huge yield, if `collect` isn't called first.\n */\n // Collect at existing rate\n _collect();\n\n // Update rate\n drip.perSecond = _perSecond;\n }\n}\n" + }, + "contracts/harvest/OETHFixedRateDripper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { FixedRateDripper } from \"./FixedRateDripper.sol\";\n\n/**\n * @title OETH FixedRateDripper Contract\n * @author Origin Protocol Inc\n */\ncontract OETHFixedRateDripper is FixedRateDripper {\n constructor(address _vault, address _token)\n FixedRateDripper(_vault, _token)\n {}\n}\n" + }, + "contracts/interfaces/aerodrome/ICLGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\ninterface ICLGauge {\n /// @notice Returns the claimable rewards for a given account and tokenId\n /// @dev Throws if account is not the position owner\n /// @dev pool.updateRewardsGrowthGlobal() needs to be called first, to return the correct claimable rewards\n /// @param account The address of the user\n /// @param tokenId The tokenId of the position\n /// @return The amount of claimable reward\n function earned(address account, uint256 tokenId)\n external\n view\n returns (uint256);\n\n /// @notice Retrieve rewards for all tokens owned by an account\n /// @dev Throws if not called by the voter\n /// @param account The account of the user\n function getReward(address account) external;\n\n /// @notice Retrieve rewards for a tokenId\n /// @dev Throws if not called by the position owner\n /// @param tokenId The tokenId of the position\n function getReward(uint256 tokenId) external;\n\n /// @notice Notifies gauge of gauge rewards.\n /// @param amount Amount of gauge rewards (emissions) to notify. Must be greater than 604_800.\n function notifyRewardAmount(uint256 amount) external;\n\n /// @dev Notifies gauge of gauge rewards without distributing its fees.\n /// Assumes gauge reward tokens is 18 decimals.\n /// If not 18 decimals, rewardRate may have rounding issues.\n /// @param amount Amount of gauge rewards (emissions) to notify. Must be greater than 604_800.\n function notifyRewardWithoutClaim(uint256 amount) external;\n\n /// @notice Used to deposit a CL position into the gauge\n /// @notice Allows the user to receive emissions instead of fees\n /// @param tokenId The tokenId of the position\n function deposit(uint256 tokenId) external;\n\n /// @notice Used to withdraw a CL position from the gauge\n /// @notice Allows the user to receive fees instead of emissions\n /// @notice Outstanding emissions will be collected on withdrawal\n /// @param tokenId The tokenId of the position\n function withdraw(uint256 tokenId) external;\n\n // /// @notice Fetch all tokenIds staked by a given account\n // /// @param depositor The address of the user\n // /// @return The tokenIds of the staked positions\n // function stakedValues(address depositor) external view returns (uint256[] memory);\n\n // /// @notice Fetch a staked tokenId by index\n // /// @param depositor The address of the user\n // /// @param index The index of the staked tokenId\n // /// @return The tokenId of the staked position\n // function stakedByIndex(address depositor, uint256 index) external view returns (uint256);\n\n // /// @notice Check whether a position is staked in the gauge by a certain user\n // /// @param depositor The address of the user\n // /// @param tokenId The tokenId of the position\n // /// @return Whether the position is staked in the gauge\n // function stakedContains(address depositor, uint256 tokenId) external view returns (bool);\n\n // /// @notice The amount of positions staked in the gauge by a certain user\n // /// @param depositor The address of the user\n // /// @return The amount of positions staked in the gauge\n // function stakedLength(address depositor) external view returns (uint256);\n\n function feesVotingReward() external view returns (address);\n}\n" + }, + "contracts/interfaces/aerodrome/ICLPool.sol": { + "content": "pragma solidity >=0.5.0;\n\n/// @title The interface for a CL Pool\n/// @notice A CL pool facilitates swapping and automated market making between any two assets that strictly conform\n/// to the ERC20 specification\n/// @dev The pool interface is broken up into many smaller pieces\ninterface ICLPool {\n function slot0()\n external\n view\n returns (\n uint160 sqrtPriceX96,\n int24 tick,\n uint16 observationIndex,\n uint16 observationCardinality,\n uint16 observationCardinalityNext,\n bool unlocked\n );\n\n /// @notice The first of the two tokens of the pool, sorted by address\n /// @return The token contract address\n function token0() external view returns (address);\n\n /// @notice The second of the two tokens of the pool, sorted by address\n /// @return The token contract address\n function token1() external view returns (address);\n\n function tickSpacing() external view returns (int24);\n\n /// @notice The gauge corresponding to this pool\n /// @return The gauge contract address\n function gauge() external view returns (address);\n\n /// @notice The currently in range liquidity available to the pool\n /// @dev This value has no relationship to the total liquidity across all ticks\n /// @dev This value includes staked liquidity\n function liquidity() external view returns (uint128);\n\n /// @notice Look up information about a specific tick in the pool\n /// @param tick The tick to look up\n /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or\n /// tick upper,\n /// liquidityNet how much liquidity changes when the pool price crosses the tick,\n /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,\n /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,\n /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick\n /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from\n /// the current tick,\n /// secondsOutside the seconds spent on the other side of the tick from the current tick,\n /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise\n /// equal to false.\n /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.\n /// In addition, these values are only relative and must be used only in comparison to previous snapshots for\n /// a specific position.\n function ticks(int24 tick)\n external\n view\n returns (\n uint128 liquidityGross,\n int128 liquidityNet,\n uint256 feeGrowthOutside0X128,\n uint256 feeGrowthOutside1X128,\n int56 tickCumulativeOutside,\n uint160 secondsPerLiquidityOutsideX128,\n uint32 secondsOutside,\n bool initialized\n );\n}\n" + }, + "contracts/interfaces/aerodrome/INonfungiblePositionManager.sol": { + "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.7.5;\npragma abicoder v2;\n\n/// @title Non-fungible token for positions\n/// @notice Wraps CL positions in a non-fungible token interface which allows for them to be transferred\n/// and authorized.\n// slither-disable-start erc20-interface\ninterface INonfungiblePositionManager {\n /**\n * @dev See {IERC721-approve}.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev See {IERC721-getApproved}.\n */\n function getApproved(uint256 tokenId) external returns (address);\n\n /**\n * @dev See {IERC721-ownerOf}.\n */\n function ownerOf(uint256 tokenId) external view returns (address);\n\n /// @notice Returns the position information associated with a given token ID.\n /// @dev Throws if the token ID is not valid.\n /// @param tokenId The ID of the token that represents the position\n /// @return nonce The nonce for permits\n /// @return operator The address that is approved for spending\n /// @return token0 The address of the token0 for a specific pool\n /// @return token1 The address of the token1 for a specific pool\n /// @return tickSpacing The tick spacing associated with the pool\n /// @return tickLower The lower end of the tick range for the position\n /// @return tickUpper The higher end of the tick range for the position\n /// @return liquidity The liquidity of the position\n /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position\n /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position\n /// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation\n /// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation\n function positions(uint256 tokenId)\n external\n view\n returns (\n uint96 nonce,\n address operator,\n address token0,\n address token1,\n int24 tickSpacing,\n int24 tickLower,\n int24 tickUpper,\n uint128 liquidity,\n uint256 feeGrowthInside0LastX128,\n uint256 feeGrowthInside1LastX128,\n uint128 tokensOwed0,\n uint128 tokensOwed1\n );\n\n struct MintParams {\n address token0;\n address token1;\n int24 tickSpacing;\n int24 tickLower;\n int24 tickUpper;\n uint256 amount0Desired;\n uint256 amount1Desired;\n uint256 amount0Min;\n uint256 amount1Min;\n address recipient;\n uint256 deadline;\n uint160 sqrtPriceX96;\n }\n\n /// @notice Creates a new position wrapped in a NFT\n /// @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized\n /// a method does not exist, i.e. the pool is assumed to be initialized.\n /// @param params The params necessary to mint a position, encoded as `MintParams` in calldata\n /// @return tokenId The ID of the token that represents the minted position\n /// @return liquidity The amount of liquidity for this position\n /// @return amount0 The amount of token0\n /// @return amount1 The amount of token1\n function mint(MintParams calldata params)\n external\n payable\n returns (\n uint256 tokenId,\n uint128 liquidity,\n uint256 amount0,\n uint256 amount1\n );\n\n struct IncreaseLiquidityParams {\n uint256 tokenId;\n uint256 amount0Desired;\n uint256 amount1Desired;\n uint256 amount0Min;\n uint256 amount1Min;\n uint256 deadline;\n }\n\n /// @notice Increases the amount of liquidity in a position, with tokens paid by the `msg.sender`\n /// @param params tokenId The ID of the token for which liquidity is being increased,\n /// amount0Desired The desired amount of token0 to be spent,\n /// amount1Desired The desired amount of token1 to be spent,\n /// amount0Min The minimum amount of token0 to spend, which serves as a slippage check,\n /// amount1Min The minimum amount of token1 to spend, which serves as a slippage check,\n /// deadline The time by which the transaction must be included to effect the change\n /// @return liquidity The new liquidity amount as a result of the increase\n /// @return amount0 The amount of token0 to acheive resulting liquidity\n /// @return amount1 The amount of token1 to acheive resulting liquidity\n function increaseLiquidity(IncreaseLiquidityParams calldata params)\n external\n payable\n returns (\n uint128 liquidity,\n uint256 amount0,\n uint256 amount1\n );\n\n struct DecreaseLiquidityParams {\n uint256 tokenId;\n uint128 liquidity;\n uint256 amount0Min;\n uint256 amount1Min;\n uint256 deadline;\n }\n\n /// @notice Decreases the amount of liquidity in a position and accounts it to the position\n /// @param params tokenId The ID of the token for which liquidity is being decreased,\n /// amount The amount by which liquidity will be decreased,\n /// amount0Min The minimum amount of token0 that should be accounted for the burned liquidity,\n /// amount1Min The minimum amount of token1 that should be accounted for the burned liquidity,\n /// deadline The time by which the transaction must be included to effect the change\n /// @return amount0 The amount of token0 accounted to the position's tokens owed\n /// @return amount1 The amount of token1 accounted to the position's tokens owed\n /// @dev The use of this function can cause a loss to users of the NonfungiblePositionManager\n /// @dev for tokens that have very high decimals.\n /// @dev The amount of tokens necessary for the loss is: 3.4028237e+38.\n /// @dev This is equivalent to 1e20 value with 18 decimals.\n function decreaseLiquidity(DecreaseLiquidityParams calldata params)\n external\n payable\n returns (uint256 amount0, uint256 amount1);\n\n struct CollectParams {\n uint256 tokenId;\n address recipient;\n uint128 amount0Max;\n uint128 amount1Max;\n }\n\n /// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient\n /// @notice Used to update staked positions before deposit and withdraw\n /// @param params tokenId The ID of the NFT for which tokens are being collected,\n /// recipient The account that should receive the tokens,\n /// amount0Max The maximum amount of token0 to collect,\n /// amount1Max The maximum amount of token1 to collect\n /// @return amount0 The amount of fees collected in token0\n /// @return amount1 The amount of fees collected in token1\n function collect(CollectParams calldata params)\n external\n payable\n returns (uint256 amount0, uint256 amount1);\n\n /// @notice Burns a token ID, which deletes it from the NFT contract. The token must have 0 liquidity and all tokens\n /// must be collected first.\n /// @param tokenId The ID of the token that is being burned\n function burn(uint256 tokenId) external payable;\n\n /// @notice Sets a new Token Descriptor\n /// @param _tokenDescriptor Address of the new Token Descriptor to be chosen\n function setTokenDescriptor(address _tokenDescriptor) external;\n\n /// @notice Sets a new Owner address\n /// @param _owner Address of the new Owner to be chosen\n function setOwner(address _owner) external;\n}\n// slither-disable-end erc20-interface\n" + }, + "contracts/interfaces/aerodrome/ISugarHelper.sol": { + "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\npragma abicoder v2;\n\nimport { INonfungiblePositionManager } from \"./INonfungiblePositionManager.sol\";\n\ninterface ISugarHelper {\n struct PopulatedTick {\n int24 tick;\n uint160 sqrtRatioX96;\n int128 liquidityNet;\n uint128 liquidityGross;\n }\n\n ///\n /// Wrappers for LiquidityAmounts\n ///\n\n function getAmountsForLiquidity(\n uint160 sqrtRatioX96,\n uint160 sqrtRatioAX96,\n uint160 sqrtRatioBX96,\n uint128 liquidity\n ) external pure returns (uint256 amount0, uint256 amount1);\n\n function getLiquidityForAmounts(\n uint256 amount0,\n uint256 amount1,\n uint160 sqrtRatioX96,\n uint160 sqrtRatioAX96,\n uint160 sqrtRatioBX96\n ) external pure returns (uint128 liquidity);\n\n /// @notice Computes the amount of token0 for a given amount of token1 and price range\n /// @param amount1 Amount of token1 to estimate liquidity\n /// @param pool Address of the pool to be used\n /// @param sqrtRatioX96 A sqrt price representing the current pool prices\n /// @param tickLow Lower tick boundary\n /// @param tickLow Upper tick boundary\n /// @dev If the given pool address is not the zero address, will fetch `sqrtRatioX96` from pool\n /// @return amount0 Estimated amount of token0\n function estimateAmount0(\n uint256 amount1,\n address pool,\n uint160 sqrtRatioX96,\n int24 tickLow,\n int24 tickHigh\n ) external view returns (uint256 amount0);\n\n /// @notice Computes the amount of token1 for a given amount of token0 and price range\n /// @param amount0 Amount of token0 to estimate liquidity\n /// @param pool Address of the pool to be used\n /// @param sqrtRatioX96 A sqrt price representing the current pool prices\n /// @param tickLow Lower tick boundary\n /// @param tickLow Upper tick boundary\n /// @dev If the given pool address is not the zero address, will fetch `sqrtRatioX96` from pool\n /// @return amount1 Estimated amount of token1\n function estimateAmount1(\n uint256 amount0,\n address pool,\n uint160 sqrtRatioX96,\n int24 tickLow,\n int24 tickHigh\n ) external view returns (uint256 amount1);\n\n ///\n /// Wrappers for PositionValue\n ///\n\n function principal(\n INonfungiblePositionManager positionManager,\n uint256 tokenId,\n uint160 sqrtRatioX96\n ) external view returns (uint256 amount0, uint256 amount1);\n\n function fees(INonfungiblePositionManager positionManager, uint256 tokenId)\n external\n view\n returns (uint256 amount0, uint256 amount1);\n\n ///\n /// Wrappers for TickMath\n ///\n\n function getSqrtRatioAtTick(int24 tick)\n external\n pure\n returns (uint160 sqrtRatioX96);\n\n function getTickAtSqrtRatio(uint160 sqrtRatioX96)\n external\n pure\n returns (int24 tick);\n\n /// @notice Fetches Tick Data for all populated Ticks in given bitmaps\n /// @param pool Address of the pool from which to fetch data\n /// @param startTick Tick from which the first bitmap will be fetched\n /// @dev The number of bitmaps fetched by this function should always be `MAX_BITMAPS`,\n /// unless there are less than `MAX_BITMAPS` left to iterate through\n /// @return populatedTicks Array of all Populated Ticks in the provided bitmaps\n function getPopulatedTicks(address pool, int24 startTick)\n external\n view\n returns (PopulatedTick[] memory populatedTicks);\n}\n" + }, + "contracts/interfaces/aerodrome/ISwapRouter.sol": { + "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.7.5;\npragma abicoder v2;\n\n/// @title Router token swapping functionality\n/// @notice Functions for swapping tokens via CL\ninterface ISwapRouter {\n struct ExactInputSingleParams {\n address tokenIn;\n address tokenOut;\n int24 tickSpacing;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n uint160 sqrtPriceLimitX96;\n }\n\n /// @notice Swaps `amountIn` of one token for as much as possible of another token\n /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata\n /// @return amountOut The amount of the received token\n function exactInputSingle(ExactInputSingleParams calldata params)\n external\n payable\n returns (uint256 amountOut);\n\n struct ExactInputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n }\n\n /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path\n /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata\n /// @return amountOut The amount of the received token\n function exactInput(ExactInputParams calldata params)\n external\n payable\n returns (uint256 amountOut);\n\n struct ExactOutputSingleParams {\n address tokenIn;\n address tokenOut;\n int24 tickSpacing;\n address recipient;\n uint256 deadline;\n uint256 amountOut;\n uint256 amountInMaximum;\n uint160 sqrtPriceLimitX96;\n }\n\n /// @notice Swaps as little as possible of one token for `amountOut` of another token\n /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata\n /// @return amountIn The amount of the input token\n function exactOutputSingle(ExactOutputSingleParams calldata params)\n external\n payable\n returns (uint256 amountIn);\n\n struct ExactOutputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountOut;\n uint256 amountInMaximum;\n }\n\n /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)\n /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata\n /// @return amountIn The amount of the input token\n function exactOutput(ExactOutputParams calldata params)\n external\n payable\n returns (uint256 amountIn);\n}\n" + }, + "contracts/interfaces/algebra/IAlgebraGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IGauge {\n function owner() external view returns (address);\n\n function TOKEN() external view returns (address);\n\n function DISTRIBUTION() external view returns (address);\n\n function balanceOf(address account) external view returns (uint256);\n\n function claimFees() external returns (uint256 claimed0, uint256 claimed1);\n\n function deposit(uint256 amount) external;\n\n function depositAll() external;\n\n function earned(address account) external view returns (uint256);\n\n function getReward() external;\n\n function getReward(address _user) external;\n\n function isForPair() external view returns (bool);\n\n function lastTimeRewardApplicable() external view returns (uint256);\n\n function lastUpdateTime() external view returns (uint256);\n\n function notifyRewardAmount(address token, uint256 reward) external;\n\n function periodFinish() external view returns (uint256);\n\n function rewardForDuration() external view returns (uint256);\n\n function rewardPerToken() external view returns (uint256);\n\n function rewardPerTokenStored() external view returns (uint256);\n\n function rewardRate() external view returns (uint256);\n\n function rewardToken() external view returns (address);\n\n function rewards(address) external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function userRewardPerTokenPaid(address) external view returns (uint256);\n\n function withdraw(uint256 amount) external;\n\n function withdrawAll() external;\n\n function withdrawAllAndHarvest() external;\n\n function withdrawExcess(address token, uint256 amount) external;\n\n function emergency() external returns (bool);\n\n function emergencyWithdraw() external;\n\n function activateEmergencyMode() external;\n\n function stopEmergencyMode() external;\n}\n" + }, + "contracts/interfaces/algebra/IAlgebraPair.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IPair {\n event Approval(address indexed src, address indexed guy, uint256 wad);\n event Transfer(address indexed src, address indexed dst, uint256 wad);\n\n event Mint(address indexed sender, uint256 amount0, uint256 amount1);\n event Burn(\n address indexed sender,\n uint256 amount0,\n uint256 amount1,\n address indexed to\n );\n event Swap(\n address indexed sender,\n uint256 amount0In,\n uint256 amount1In,\n uint256 amount0Out,\n uint256 amount1Out,\n address indexed to\n );\n event Claim(\n address indexed sender,\n address indexed recipient,\n uint256 amount0,\n uint256 amount1\n );\n\n function metadata()\n external\n view\n returns (\n uint256 dec0,\n uint256 dec1,\n uint256 r0,\n uint256 r1,\n bool st,\n address t0,\n address t1\n );\n\n function claimFees() external returns (uint256, uint256);\n\n function tokens() external view returns (address, address);\n\n function token0() external view returns (address);\n\n function token1() external view returns (address);\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n function swap(\n uint256 amount0Out,\n uint256 amount1Out,\n address to,\n bytes calldata data\n ) external;\n\n function burn(address to)\n external\n returns (uint256 amount0, uint256 amount1);\n\n function mint(address to) external returns (uint256 liquidity);\n\n function getReserves()\n external\n view\n returns (\n uint256 _reserve0,\n uint256 _reserve1,\n uint256 _blockTimestampLast\n );\n\n function getAmountOut(uint256, address) external view returns (uint256);\n\n // ERC20 methods\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address) external view returns (uint256);\n\n function transfer(address recipient, uint256 amount)\n external\n returns (bool);\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n function allowance(address owner, address spender)\n external\n view\n returns (uint256);\n\n function approve(address spender, uint256 value) external returns (bool);\n\n function claimable0(address _user) external view returns (uint256);\n\n function claimable1(address _user) external view returns (uint256);\n\n function isStable() external view returns (bool);\n\n function skim(address to) external;\n\n function sync() external;\n}\n" + }, + "contracts/interfaces/balancer/IBalancerVault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\n\ninterface IBalancerVault {\n enum WeightedPoolJoinKind {\n INIT,\n EXACT_TOKENS_IN_FOR_BPT_OUT,\n TOKEN_IN_FOR_EXACT_BPT_OUT,\n ALL_TOKENS_IN_FOR_EXACT_BPT_OUT,\n ADD_TOKEN\n }\n\n enum WeightedPoolExitKind {\n EXACT_BPT_IN_FOR_ONE_TOKEN_OUT,\n EXACT_BPT_IN_FOR_TOKENS_OUT,\n BPT_IN_FOR_EXACT_TOKENS_OUT,\n REMOVE_TOKEN\n }\n\n /**\n * @dev Called by users to join a Pool, which transfers tokens from `sender` into the Pool's balance. This will\n * trigger custom Pool behavior, which will typically grant something in return to `recipient` - often tokenized\n * Pool shares.\n *\n * If the caller is not `sender`, it must be an authorized relayer for them.\n *\n * The `assets` and `maxAmountsIn` arrays must have the same length, and each entry indicates the maximum amount\n * to send for each asset. The amounts to send are decided by the Pool and not the Vault: it just enforces\n * these maximums.\n *\n * If joining a Pool that holds WETH, it is possible to send ETH directly: the Vault will do the wrapping. To enable\n * this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead of the\n * WETH address. Note that it is not possible to combine ETH and WETH in the same join. Any excess ETH will be sent\n * back to the caller (not the sender, which is important for relayers).\n *\n * `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when\n * interacting with Pools that register and deregister tokens frequently. If sending ETH however, the array must be\n * sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the final\n * `assets` array might not be sorted. Pools with no registered tokens cannot be joined.\n *\n * If `fromInternalBalance` is true, the caller's Internal Balance will be preferred: ERC20 transfers will only\n * be made for the difference between the requested amount and Internal Balance (if any). Note that ETH cannot be\n * withdrawn from Internal Balance: attempting to do so will trigger a revert.\n *\n * This causes the Vault to call the `IBasePool.onJoinPool` hook on the Pool's contract, where Pools implement\n * their own custom logic. This typically requires additional information from the user (such as the expected number\n * of Pool shares). This can be encoded in the `userData` argument, which is ignored by the Vault and passed\n * directly to the Pool's contract, as is `recipient`.\n *\n * Emits a `PoolBalanceChanged` event.\n */\n function joinPool(\n bytes32 poolId,\n address sender,\n address recipient,\n JoinPoolRequest memory request\n ) external payable;\n\n struct JoinPoolRequest {\n address[] assets;\n uint256[] maxAmountsIn;\n bytes userData;\n bool fromInternalBalance;\n }\n\n /**\n * @dev Called by users to exit a Pool, which transfers tokens from the Pool's balance to `recipient`. This will\n * trigger custom Pool behavior, which will typically ask for something in return from `sender` - often tokenized\n * Pool shares. The amount of tokens that can be withdrawn is limited by the Pool's `cash` balance (see\n * `getPoolTokenInfo`).\n *\n * If the caller is not `sender`, it must be an authorized relayer for them.\n *\n * The `tokens` and `minAmountsOut` arrays must have the same length, and each entry in these indicates the minimum\n * token amount to receive for each token contract. The amounts to send are decided by the Pool and not the Vault:\n * it just enforces these minimums.\n *\n * If exiting a Pool that holds WETH, it is possible to receive ETH directly: the Vault will do the unwrapping. To\n * enable this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead\n * of the WETH address. Note that it is not possible to combine ETH and WETH in the same exit.\n *\n * `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when\n * interacting with Pools that register and deregister tokens frequently. If receiving ETH however, the array must\n * be sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the\n * final `assets` array might not be sorted. Pools with no registered tokens cannot be exited.\n *\n * If `toInternalBalance` is true, the tokens will be deposited to `recipient`'s Internal Balance. Otherwise,\n * an ERC20 transfer will be performed. Note that ETH cannot be deposited to Internal Balance: attempting to\n * do so will trigger a revert.\n *\n * `minAmountsOut` is the minimum amount of tokens the user expects to get out of the Pool, for each token in the\n * `tokens` array. This array must match the Pool's registered tokens.\n *\n * This causes the Vault to call the `IBasePool.onExitPool` hook on the Pool's contract, where Pools implement\n * their own custom logic. This typically requires additional information from the user (such as the expected number\n * of Pool shares to return). This can be encoded in the `userData` argument, which is ignored by the Vault and\n * passed directly to the Pool's contract.\n *\n * Emits a `PoolBalanceChanged` event.\n */\n function exitPool(\n bytes32 poolId,\n address sender,\n address payable recipient,\n ExitPoolRequest memory request\n ) external;\n\n struct ExitPoolRequest {\n address[] assets;\n uint256[] minAmountsOut;\n bytes userData;\n bool toInternalBalance;\n }\n\n /**\n * @dev Returns a Pool's registered tokens, the total balance for each, and the latest block when *any* of\n * the tokens' `balances` changed.\n *\n * The order of the `tokens` array is the same order that will be used in `joinPool`, `exitPool`, as well as in all\n * Pool hooks (where applicable). Calls to `registerTokens` and `deregisterTokens` may change this order.\n *\n * If a Pool only registers tokens once, and these are sorted in ascending order, they will be stored in the same\n * order as passed to `registerTokens`.\n *\n * Total balances include both tokens held by the Vault and those withdrawn by the Pool's Asset Managers. These are\n * the amounts used by joins, exits and swaps. For a detailed breakdown of token balances, use `getPoolTokenInfo`\n * instead.\n */\n function getPoolTokens(bytes32 poolId)\n external\n view\n returns (\n IERC20[] memory tokens,\n uint256[] memory balances,\n uint256 lastChangeBlock\n );\n\n /**\n * @dev Performs a set of user balance operations, which involve Internal Balance (deposit, withdraw or transfer)\n * and plain ERC20 transfers using the Vault's allowance. This last feature is particularly useful for relayers, as\n * it lets integrators reuse a user's Vault allowance.\n *\n * For each operation, if the caller is not `sender`, it must be an authorized relayer for them.\n */\n function manageUserBalance(UserBalanceOp[] memory ops) external payable;\n\n struct UserBalanceOp {\n UserBalanceOpKind kind;\n address asset;\n uint256 amount;\n address sender;\n address payable recipient;\n }\n\n enum UserBalanceOpKind {\n DEPOSIT_INTERNAL,\n WITHDRAW_INTERNAL,\n TRANSFER_INTERNAL,\n TRANSFER_EXTERNAL\n }\n\n enum SwapKind {\n GIVEN_IN,\n GIVEN_OUT\n }\n\n struct SingleSwap {\n bytes32 poolId;\n SwapKind kind;\n address assetIn;\n address assetOut;\n uint256 amount;\n bytes userData;\n }\n\n struct FundManagement {\n address sender;\n bool fromInternalBalance;\n address payable recipient;\n bool toInternalBalance;\n }\n\n function swap(\n SingleSwap calldata singleSwap,\n FundManagement calldata funds,\n uint256 limit,\n uint256 deadline\n ) external returns (uint256 amountCalculated);\n\n function getPoolTokenInfo(bytes32 poolId, address token)\n external\n view\n returns (\n uint256 cash,\n uint256 managed,\n uint256 lastChangeBlock,\n address assetManager\n );\n}\n" + }, + "contracts/interfaces/cctp/ICCTP.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface ICCTPTokenMessenger {\n function depositForBurn(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller,\n uint256 maxFee,\n uint32 minFinalityThreshold\n ) external;\n\n function depositForBurnWithHook(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller,\n uint256 maxFee,\n uint32 minFinalityThreshold,\n bytes memory hookData\n ) external;\n\n function getMinFeeAmount(uint256 amount) external view returns (uint256);\n}\n\ninterface ICCTPMessageTransmitter {\n function sendMessage(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n uint32 minFinalityThreshold,\n bytes memory messageBody\n ) external;\n\n function receiveMessage(bytes calldata message, bytes calldata attestation)\n external\n returns (bool);\n}\n\ninterface IMessageHandlerV2 {\n /**\n * @notice Handles an incoming finalized message from an IReceiverV2\n * @dev Finalized messages have finality threshold values greater than or equal to 2000\n * @param sourceDomain The source domain of the message\n * @param sender The sender of the message\n * @param finalityThresholdExecuted the finality threshold at which the message was attested to\n * @param messageBody The raw bytes of the message body\n * @return success True, if successful; false, if not.\n */\n function handleReceiveFinalizedMessage(\n uint32 sourceDomain,\n bytes32 sender,\n uint32 finalityThresholdExecuted,\n bytes calldata messageBody\n ) external returns (bool);\n\n /**\n * @notice Handles an incoming unfinalized message from an IReceiverV2\n * @dev Unfinalized messages have finality threshold values less than 2000\n * @param sourceDomain The source domain of the message\n * @param sender The sender of the message\n * @param finalityThresholdExecuted The finality threshold at which the message was attested to\n * @param messageBody The raw bytes of the message body\n * @return success True, if successful; false, if not.\n */\n function handleReceiveUnfinalizedMessage(\n uint32 sourceDomain,\n bytes32 sender,\n uint32 finalityThresholdExecuted,\n bytes calldata messageBody\n ) external returns (bool);\n}\n" + }, + "contracts/interfaces/chainlink/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n}\n" + }, + "contracts/interfaces/hydrex/IHydrexGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title IHydrexGauge\n * @notice Minimal interface exposing the staked-token getter used by the\n * Hydrex GaugeV2 (>= v2.5). Hydrex renamed `TOKEN()` to `stakeToken()`\n * in v2.5; the rest of the gauge surface (deposit / withdraw /\n * getReward / emergency / emergencyWithdraw / balanceOf) is\n * ABI-compatible with `IAlgebraGauge` and is invoked through that\n * interface elsewhere in the strategy.\n */\ninterface IHydrexGauge {\n function stakeToken() external view returns (address);\n}\n" + }, + "contracts/interfaces/IBasicToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IBasicToken {\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\n}\n" + }, + "contracts/interfaces/IBeaconProofs.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IBeaconProofs {\n function verifyValidator(\n bytes32 beaconBlockRoot,\n bytes32 pubKeyHash,\n bytes calldata validatorPubKeyProof,\n uint40 validatorIndex,\n bytes32 withdrawalCredentials\n ) external view;\n\n function verifyValidatorWithdrawable(\n bytes32 beaconBlockRoot,\n uint40 validatorIndex,\n uint64 withdrawableEpoch,\n bytes calldata withdrawableEpochProof\n ) external view;\n\n function verifyBalancesContainer(\n bytes32 beaconBlockRoot,\n bytes32 balancesContainerLeaf,\n bytes calldata balancesContainerProof\n ) external view;\n\n function verifyValidatorBalance(\n bytes32 balancesContainerRoot,\n bytes32 validatorBalanceLeaf,\n bytes calldata balanceProof,\n uint40 validatorIndex\n ) external view returns (uint256 validatorBalance);\n\n function verifyPendingDepositsContainer(\n bytes32 beaconBlockRoot,\n bytes32 pendingDepositsContainerRoot,\n bytes calldata proof\n ) external view;\n\n function verifyPendingDeposit(\n bytes32 pendingDepositsContainerRoot,\n bytes32 pendingDepositRoot,\n bytes calldata proof,\n uint32 pendingDepositIndex\n ) external view;\n\n function verifyFirstPendingDeposit(\n bytes32 beaconBlockRoot,\n uint64 slot,\n bytes calldata firstPendingDepositSlotProof\n ) external view returns (bool isEmptyDepositQueue);\n\n function merkleizePendingDeposit(\n bytes32 pubKeyHash,\n bytes calldata withdrawalCredentials,\n uint64 amountGwei,\n bytes calldata signature,\n uint64 slot\n ) external pure returns (bytes32 root);\n\n function merkleizeSignature(bytes calldata signature)\n external\n pure\n returns (bytes32 root);\n}\n" + }, + "contracts/interfaces/IChildLiquidityGaugeFactory.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface IChildLiquidityGaugeFactory {\n event DeployedGauge(\n address indexed _implementation,\n address indexed _lp_token,\n address indexed _deployer,\n bytes32 _salt,\n address _gauge\n );\n event Minted(\n address indexed _user,\n address indexed _gauge,\n uint256 _new_total\n );\n event TransferOwnership(address _old_owner, address _new_owner);\n event UpdateCallProxy(address _old_call_proxy, address _new_call_proxy);\n event UpdateImplementation(\n address _old_implementation,\n address _new_implementation\n );\n event UpdateManager(address _manager);\n event UpdateMirrored(address indexed _gauge, bool _mirrored);\n event UpdateRoot(address _factory, address _implementation);\n event UpdateVotingEscrow(\n address _old_voting_escrow,\n address _new_voting_escrow\n );\n\n function accept_transfer_ownership() external;\n\n function call_proxy() external view returns (address);\n\n function commit_transfer_ownership(address _future_owner) external;\n\n function crv() external view returns (address);\n\n function deploy_gauge(address _lp_token, bytes32 _salt)\n external\n returns (address);\n\n function deploy_gauge(\n address _lp_token,\n bytes32 _salt,\n address _manager\n ) external returns (address);\n\n function future_owner() external view returns (address);\n\n function gauge_data(address arg0) external view returns (uint256);\n\n function get_gauge(uint256 arg0) external view returns (address);\n\n function get_gauge_count() external view returns (uint256);\n\n function get_gauge_from_lp_token(address arg0)\n external\n view\n returns (address);\n\n function get_implementation() external view returns (address);\n\n function is_mirrored(address _gauge) external view returns (bool);\n\n function is_valid_gauge(address _gauge) external view returns (bool);\n\n function last_request(address _gauge) external view returns (uint256);\n\n function manager() external view returns (address);\n\n function mint(address _gauge) external;\n\n function mint_many(address[32] memory _gauges) external;\n\n function minted(address arg0, address arg1) external view returns (uint256);\n\n function owner() external view returns (address);\n\n function root_factory() external view returns (address);\n\n function root_implementation() external view returns (address);\n\n function set_call_proxy(address _new_call_proxy) external;\n\n function set_crv(address _crv) external;\n\n function set_implementation(address _implementation) external;\n\n function set_manager(address _new_manager) external;\n\n function set_mirrored(address _gauge, bool _mirrored) external;\n\n function set_root(address _factory, address _implementation) external;\n\n function set_voting_escrow(address _voting_escrow) external;\n\n function version() external view returns (string memory);\n\n function voting_escrow() external view returns (address);\n}\n" + }, + "contracts/interfaces/ICurveLiquidityGaugeV6.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface ICurveLiquidityGaugeV6 {\n event ApplyOwnership(address admin);\n event Approval(\n address indexed _owner,\n address indexed _spender,\n uint256 _value\n );\n event CommitOwnership(address admin);\n event Deposit(address indexed provider, uint256 value);\n event SetGaugeManager(address _gauge_manager);\n event Transfer(address indexed _from, address indexed _to, uint256 _value);\n event UpdateLiquidityLimit(\n address indexed user,\n uint256 original_balance,\n uint256 original_supply,\n uint256 working_balance,\n uint256 working_supply\n );\n event Withdraw(address indexed provider, uint256 value);\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n function add_reward(address _reward_token, address _distributor) external;\n\n function allowance(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function balanceOf(address arg0) external view returns (uint256);\n\n function claim_rewards() external;\n\n function claim_rewards(address _addr) external;\n\n function claim_rewards(address _addr, address _receiver) external;\n\n function claimable_reward(address _user, address _reward_token)\n external\n view\n returns (uint256);\n\n function claimable_tokens(address addr) external returns (uint256);\n\n function claimed_reward(address _addr, address _token)\n external\n view\n returns (uint256);\n\n function decimals() external view returns (uint256);\n\n function decreaseAllowance(address _spender, uint256 _subtracted_value)\n external\n returns (bool);\n\n function deposit(uint256 _value) external;\n\n function deposit(uint256 _value, address _addr) external;\n\n function deposit(\n uint256 _value,\n address _addr,\n bool _claim_rewards\n ) external;\n\n function deposit_reward_token(address _reward_token, uint256 _amount)\n external;\n\n function deposit_reward_token(\n address _reward_token,\n uint256 _amount,\n uint256 _epoch\n ) external;\n\n function factory() external view returns (address);\n\n function future_epoch_time() external view returns (uint256);\n\n function increaseAllowance(address _spender, uint256 _added_value)\n external\n returns (bool);\n\n function inflation_rate() external view returns (uint256);\n\n function integrate_checkpoint() external view returns (uint256);\n\n function integrate_checkpoint_of(address arg0)\n external\n view\n returns (uint256);\n\n function integrate_fraction(address arg0) external view returns (uint256);\n\n function integrate_inv_supply(uint256 arg0) external view returns (uint256);\n\n function integrate_inv_supply_of(address arg0)\n external\n view\n returns (uint256);\n\n function is_killed() external view returns (bool);\n\n function kick(address addr) external;\n\n function lp_token() external view returns (address);\n\n function manager() external view returns (address);\n\n function name() external view returns (string memory);\n\n function nonces(address arg0) external view returns (uint256);\n\n function period() external view returns (int128);\n\n function period_timestamp(uint256 arg0) external view returns (uint256);\n\n function permit(\n address _owner,\n address _spender,\n uint256 _value,\n uint256 _deadline,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) external returns (bool);\n\n function reward_count() external view returns (uint256);\n\n function reward_integral_for(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function reward_tokens(uint256 arg0) external view returns (address);\n\n function rewards_receiver(address arg0) external view returns (address);\n\n function salt() external view returns (bytes32);\n\n function set_gauge_manager(address _gauge_manager) external;\n\n function set_killed(bool _is_killed) external;\n\n function set_reward_distributor(address _reward_token, address _distributor)\n external;\n\n function set_rewards_receiver(address _receiver) external;\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function user_checkpoint(address addr) external returns (bool);\n\n function version() external view returns (string memory);\n\n function withdraw(uint256 _value) external;\n\n function withdraw(uint256 _value, bool _claim_rewards) external;\n\n function working_balances(address arg0) external view returns (uint256);\n\n function working_supply() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/ICurveMinter.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface ICurveMinter {\n event Minted(address indexed recipient, address gauge, uint256 minted);\n\n function allowed_to_mint_for(address arg0, address arg1)\n external\n view\n returns (bool);\n\n function controller() external view returns (address);\n\n function mint(address gauge_addr) external;\n\n function mint_for(address gauge_addr, address _for) external;\n\n function mint_many(address[8] memory gauge_addrs) external;\n\n function minted(address arg0, address arg1) external view returns (uint256);\n\n function toggle_approve_mint(address minting_user) external;\n\n function token() external view returns (address);\n}\n" + }, + "contracts/interfaces/ICurveStableSwapNG.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface ICurveStableSwapNG {\n event AddLiquidity(\n address indexed provider,\n uint256[] token_amounts,\n uint256[] fees,\n uint256 invariant,\n uint256 token_supply\n );\n event ApplyNewFee(uint256 fee, uint256 offpeg_fee_multiplier);\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n event RampA(\n uint256 old_A,\n uint256 new_A,\n uint256 initial_time,\n uint256 future_time\n );\n event RemoveLiquidity(\n address indexed provider,\n uint256[] token_amounts,\n uint256[] fees,\n uint256 token_supply\n );\n event RemoveLiquidityImbalance(\n address indexed provider,\n uint256[] token_amounts,\n uint256[] fees,\n uint256 invariant,\n uint256 token_supply\n );\n event RemoveLiquidityOne(\n address indexed provider,\n int128 token_id,\n uint256 token_amount,\n uint256 coin_amount,\n uint256 token_supply\n );\n event SetNewMATime(uint256 ma_exp_time, uint256 D_ma_time);\n event StopRampA(uint256 A, uint256 t);\n event TokenExchange(\n address indexed buyer,\n int128 sold_id,\n uint256 tokens_sold,\n int128 bought_id,\n uint256 tokens_bought\n );\n event TokenExchangeUnderlying(\n address indexed buyer,\n int128 sold_id,\n uint256 tokens_sold,\n int128 bought_id,\n uint256 tokens_bought\n );\n event Transfer(\n address indexed sender,\n address indexed receiver,\n uint256 value\n );\n\n function A() external view returns (uint256);\n\n function A_precise() external view returns (uint256);\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n function D_ma_time() external view returns (uint256);\n\n function D_oracle() external view returns (uint256);\n\n function N_COINS() external view returns (uint256);\n\n function add_liquidity(uint256[] memory _amounts, uint256 _min_mint_amount)\n external\n returns (uint256);\n\n function add_liquidity(\n uint256[] memory _amounts,\n uint256 _min_mint_amount,\n address _receiver\n ) external returns (uint256);\n\n function admin_balances(uint256 arg0) external view returns (uint256);\n\n function admin_fee() external view returns (uint256);\n\n function allowance(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function balanceOf(address arg0) external view returns (uint256);\n\n function balances(uint256 i) external view returns (uint256);\n\n function calc_token_amount(uint256[] memory _amounts, bool _is_deposit)\n external\n view\n returns (uint256);\n\n function calc_withdraw_one_coin(uint256 _burn_amount, int128 i)\n external\n view\n returns (uint256);\n\n function coins(uint256 arg0) external view returns (address);\n\n function decimals() external view returns (uint8);\n\n function dynamic_fee(int128 i, int128 j) external view returns (uint256);\n\n function ema_price(uint256 i) external view returns (uint256);\n\n function exchange(\n int128 i,\n int128 j,\n uint256 _dx,\n uint256 _min_dy\n ) external returns (uint256);\n\n function exchange(\n int128 i,\n int128 j,\n uint256 _dx,\n uint256 _min_dy,\n address _receiver\n ) external returns (uint256);\n\n function exchange_received(\n int128 i,\n int128 j,\n uint256 _dx,\n uint256 _min_dy\n ) external returns (uint256);\n\n function exchange_received(\n int128 i,\n int128 j,\n uint256 _dx,\n uint256 _min_dy,\n address _receiver\n ) external returns (uint256);\n\n function fee() external view returns (uint256);\n\n function future_A() external view returns (uint256);\n\n function future_A_time() external view returns (uint256);\n\n function get_balances() external view returns (uint256[] memory);\n\n function get_dx(\n int128 i,\n int128 j,\n uint256 dy\n ) external view returns (uint256);\n\n function get_dy(\n int128 i,\n int128 j,\n uint256 dx\n ) external view returns (uint256);\n\n function get_p(uint256 i) external view returns (uint256);\n\n function get_virtual_price() external view returns (uint256);\n\n function initial_A() external view returns (uint256);\n\n function initial_A_time() external view returns (uint256);\n\n function last_price(uint256 i) external view returns (uint256);\n\n function ma_exp_time() external view returns (uint256);\n\n function ma_last_time() external view returns (uint256);\n\n function name() external view returns (string memory);\n\n function nonces(address arg0) external view returns (uint256);\n\n function offpeg_fee_multiplier() external view returns (uint256);\n\n function permit(\n address _owner,\n address _spender,\n uint256 _value,\n uint256 _deadline,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) external returns (bool);\n\n function price_oracle(uint256 i) external view returns (uint256);\n\n function ramp_A(uint256 _future_A, uint256 _future_time) external;\n\n function remove_liquidity(\n uint256 _burn_amount,\n uint256[] memory _min_amounts\n ) external returns (uint256[] memory);\n\n function remove_liquidity(\n uint256 _burn_amount,\n uint256[] memory _min_amounts,\n address _receiver\n ) external returns (uint256[] memory);\n\n function remove_liquidity(\n uint256 _burn_amount,\n uint256[] memory _min_amounts,\n address _receiver,\n bool _claim_admin_fees\n ) external returns (uint256[] memory);\n\n function remove_liquidity_imbalance(\n uint256[] memory _amounts,\n uint256 _max_burn_amount\n ) external returns (uint256);\n\n function remove_liquidity_imbalance(\n uint256[] memory _amounts,\n uint256 _max_burn_amount,\n address _receiver\n ) external returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _burn_amount,\n int128 i,\n uint256 _min_received\n ) external returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _burn_amount,\n int128 i,\n uint256 _min_received,\n address _receiver\n ) external returns (uint256);\n\n function salt() external view returns (bytes32);\n\n function set_ma_exp_time(uint256 _ma_exp_time, uint256 _D_ma_time) external;\n\n function set_new_fee(uint256 _new_fee, uint256 _new_offpeg_fee_multiplier)\n external;\n\n function stop_ramp_A() external;\n\n function stored_rates() external view returns (uint256[] memory);\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function version() external view returns (string memory);\n\n function withdraw_admin_fees() external;\n}\n" + }, + "contracts/interfaces/ICurveXChainLiquidityGauge.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface ICurveXChainLiquidityGauge {\n event Approval(\n address indexed _owner,\n address indexed _spender,\n uint256 _value\n );\n event Deposit(address indexed provider, uint256 value);\n event SetGaugeManager(address _gauge_manager);\n event Transfer(address indexed _from, address indexed _to, uint256 _value);\n event UpdateLiquidityLimit(\n address indexed user,\n uint256 original_balance,\n uint256 original_supply,\n uint256 working_balance,\n uint256 working_supply\n );\n event Withdraw(address indexed provider, uint256 value);\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n function add_reward(address _reward_token, address _distributor) external;\n\n function allowance(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function balanceOf(address arg0) external view returns (uint256);\n\n function claim_rewards() external;\n\n function claim_rewards(address _addr) external;\n\n function claim_rewards(address _addr, address _receiver) external;\n\n function claimable_reward(address _user, address _reward_token)\n external\n view\n returns (uint256);\n\n function claimable_tokens(address addr) external returns (uint256);\n\n function claimed_reward(address _addr, address _token)\n external\n view\n returns (uint256);\n\n function decimals() external view returns (uint256);\n\n function decreaseAllowance(address _spender, uint256 _subtracted_value)\n external\n returns (bool);\n\n function deposit(uint256 _value) external;\n\n function deposit(uint256 _value, address _addr) external;\n\n function deposit(\n uint256 _value,\n address _addr,\n bool _claim_rewards\n ) external;\n\n function deposit_reward_token(address _reward_token, uint256 _amount)\n external;\n\n function deposit_reward_token(\n address _reward_token,\n uint256 _amount,\n uint256 _epoch\n ) external;\n\n function factory() external view returns (address);\n\n function increaseAllowance(address _spender, uint256 _added_value)\n external\n returns (bool);\n\n function inflation_rate(uint256 arg0) external view returns (uint256);\n\n function initialize(\n address _lp_token,\n address _root,\n address _manager\n ) external;\n\n function integrate_checkpoint() external view returns (uint256);\n\n function integrate_checkpoint_of(address arg0)\n external\n view\n returns (uint256);\n\n function integrate_fraction(address arg0) external view returns (uint256);\n\n function integrate_inv_supply(int128 arg0) external view returns (uint256);\n\n function integrate_inv_supply_of(address arg0)\n external\n view\n returns (uint256);\n\n function is_killed() external view returns (bool);\n\n function lp_token() external view returns (address);\n\n function manager() external view returns (address);\n\n function name() external view returns (string memory);\n\n function nonces(address arg0) external view returns (uint256);\n\n function period() external view returns (int128);\n\n function period_timestamp(int128 arg0) external view returns (uint256);\n\n function permit(\n address _owner,\n address _spender,\n uint256 _value,\n uint256 _deadline,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) external returns (bool);\n\n function recover_remaining(address _reward_token) external;\n\n function reward_count() external view returns (uint256);\n\n function reward_integral_for(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function reward_remaining(address arg0) external view returns (uint256);\n\n function reward_tokens(uint256 arg0) external view returns (address);\n\n function rewards_receiver(address arg0) external view returns (address);\n\n function root_gauge() external view returns (address);\n\n function set_gauge_manager(address _gauge_manager) external;\n\n function set_killed(bool _is_killed) external;\n\n function set_manager(address _gauge_manager) external;\n\n function set_reward_distributor(address _reward_token, address _distributor)\n external;\n\n function set_rewards_receiver(address _receiver) external;\n\n function set_root_gauge(address _root) external;\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function update_voting_escrow() external;\n\n function user_checkpoint(address addr) external returns (bool);\n\n function version() external view returns (string memory);\n\n function voting_escrow() external view returns (address);\n\n function withdraw(uint256 _value) external;\n\n function withdraw(uint256 _value, bool _claim_rewards) external;\n\n function withdraw(\n uint256 _value,\n bool _claim_rewards,\n address _receiver\n ) external;\n\n function working_balances(address arg0) external view returns (uint256);\n\n function working_supply() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IDepositContract.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IDepositContract {\n /// @notice A processed deposit event.\n event DepositEvent(\n bytes pubkey,\n bytes withdrawal_credentials,\n bytes amount,\n bytes signature,\n bytes index\n );\n\n /// @notice Submit a Phase 0 DepositData object.\n /// @param pubkey A BLS12-381 public key.\n /// @param withdrawal_credentials Commitment to a public key for withdrawals.\n /// @param signature A BLS12-381 signature.\n /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.\n /// Used as a protection against malformed input.\n function deposit(\n bytes calldata pubkey,\n bytes calldata withdrawal_credentials,\n bytes calldata signature,\n bytes32 deposit_data_root\n ) external payable;\n\n /// @notice Query the current deposit root hash.\n /// @return The deposit root hash.\n function get_deposit_root() external view returns (bytes32);\n\n /// @notice Query the current deposit count.\n /// @return The deposit count encoded as a little endian 64-bit number.\n function get_deposit_count() external view returns (bytes memory);\n}\n" + }, + "contracts/interfaces/IMerkl.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IDistributor {\n event Claimed(address indexed user, address indexed token, uint256 amount);\n\n function claim(\n address[] calldata users,\n address[] calldata tokens,\n uint256[] calldata amounts,\n bytes32[][] calldata proofs\n ) external;\n}\n" + }, + "contracts/interfaces/IMockVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IVault } from \"./IVault.sol\";\n\ninterface IMockVault is IVault {\n function outstandingWithdrawalsAmount() external view returns (uint256);\n\n function wethAvailable() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IOracle.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IOracle {\n /**\n * @dev returns the asset price in USD, in 8 decimal digits.\n *\n * The version of priceProvider deployed for OETH has 18 decimal digits\n */\n function price(address asset) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IOUSD.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IOUSD {\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n event GovernorshipTransferred(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n event PendingGovernorshipTransfer(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n event TotalSupplyUpdatedHighres(\n uint256 totalSupply,\n uint256 rebasingCredits,\n uint256 rebasingCreditsPerToken\n );\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n function _totalSupply() external view returns (uint256);\n\n function allowance(address _owner, address _spender)\n external\n view\n returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function balanceOf(address _account) external view returns (uint256);\n\n function burn(address account, uint256 amount) external;\n\n function changeSupply(uint256 _newTotalSupply) external;\n\n function claimGovernance() external;\n\n function creditsBalanceOf(address _account)\n external\n view\n returns (uint256, uint256);\n\n function creditsBalanceOfHighres(address _account)\n external\n view\n returns (\n uint256,\n uint256,\n bool\n );\n\n function decimals() external view returns (uint8);\n\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\n external\n returns (bool);\n\n function governor() external view returns (address);\n\n function increaseAllowance(address _spender, uint256 _addedValue)\n external\n returns (bool);\n\n function initialize(\n string memory _nameArg,\n string memory _symbolArg,\n address _vaultAddress\n ) external;\n\n function isGovernor() external view returns (bool);\n\n function isUpgraded(address) external view returns (uint256);\n\n function mint(address _account, uint256 _amount) external;\n\n function name() external view returns (string memory);\n\n function nonRebasingCreditsPerToken(address)\n external\n view\n returns (uint256);\n\n function nonRebasingSupply() external view returns (uint256);\n\n function rebaseOptIn() external;\n\n function rebaseOptOut() external;\n\n function rebaseState(address) external view returns (uint8);\n\n function rebasingCredits() external view returns (uint256);\n\n function rebasingCreditsHighres() external view returns (uint256);\n\n function rebasingCreditsPerToken() external view returns (uint256);\n\n function rebasingCreditsPerTokenHighres() external view returns (uint256);\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function transferGovernance(address _newGovernor) external;\n\n function vaultAddress() external view returns (address);\n}\n" + }, + "contracts/interfaces/ISafe.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface ISafe {\n function execTransactionFromModule(\n address,\n uint256,\n bytes memory,\n uint8\n ) external returns (bool);\n}\n" + }, + "contracts/interfaces/ISSVNetwork.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nstruct Cluster {\n uint32 validatorCount;\n uint64 networkFeeIndex;\n uint64 index;\n bool active;\n uint256 balance;\n}\n\ninterface ISSVNetwork {\n /**********/\n /* Errors */\n /**********/\n\n error CallerNotOwner(); // 0x5cd83192\n error CallerNotWhitelisted(); // 0x8c6e5d71\n error FeeTooLow(); // 0x732f9413\n error FeeExceedsIncreaseLimit(); // 0x958065d9\n error NoFeeDeclared(); // 0x1d226c30\n error ApprovalNotWithinTimeframe(); // 0x97e4b518\n error OperatorDoesNotExist(); // 0x961e3e8c\n error InsufficientBalance(); // 0xf4d678b8\n error ValidatorDoesNotExist(); // 0xe51315d2\n error ClusterNotLiquidatable(); // 0x60300a8d\n error InvalidPublicKeyLength(); // 0x637297a4\n error InvalidOperatorIdsLength(); // 0x38186224\n error ClusterAlreadyEnabled(); // 0x3babafd2\n error ClusterIsLiquidated(); // 0x95a0cf33\n error ClusterDoesNotExists(); // 0x185e2b16\n error IncorrectClusterState(); // 0x12e04c87\n error UnsortedOperatorsList(); // 0xdd020e25\n error NewBlockPeriodIsBelowMinimum(); // 0x6e6c9cac\n error ExceedValidatorLimit(); // 0x6df5ab76\n error TokenTransferFailed(); // 0x045c4b02\n error SameFeeChangeNotAllowed(); // 0xc81272f8\n error FeeIncreaseNotAllowed(); // 0x410a2b6c\n error NotAuthorized(); // 0xea8e4eb5\n error OperatorsListNotUnique(); // 0xa5a1ff5d\n error OperatorAlreadyExists(); // 0x289c9494\n error TargetModuleDoesNotExist(); // 0x8f9195fb\n error MaxValueExceeded(); // 0x91aa3017\n error FeeTooHigh(); // 0xcd4e6167\n error PublicKeysSharesLengthMismatch(); // 0x9ad467b8\n error IncorrectValidatorStateWithData(bytes publicKey); // 0x89307938\n error ValidatorAlreadyExistsWithData(bytes publicKey); // 0x388e7999\n error EmptyPublicKeysList(); // df83e679\n\n // legacy errors\n error ValidatorAlreadyExists(); // 0x8d09a73e\n error IncorrectValidatorState(); // 0x2feda3c1\n\n event AdminChanged(address previousAdmin, address newAdmin);\n event BeaconUpgraded(address indexed beacon);\n event ClusterDeposited(\n address indexed owner,\n uint64[] operatorIds,\n uint256 value,\n Cluster cluster\n );\n event ClusterLiquidated(\n address indexed owner,\n uint64[] operatorIds,\n Cluster cluster\n );\n event ClusterReactivated(\n address indexed owner,\n uint64[] operatorIds,\n Cluster cluster\n );\n event ClusterWithdrawn(\n address indexed owner,\n uint64[] operatorIds,\n uint256 value,\n Cluster cluster\n );\n event DeclareOperatorFeePeriodUpdated(uint64 value);\n event ExecuteOperatorFeePeriodUpdated(uint64 value);\n event FeeRecipientAddressUpdated(\n address indexed owner,\n address recipientAddress\n );\n event Initialized(uint8 version);\n event LiquidationThresholdPeriodUpdated(uint64 value);\n event MinimumLiquidationCollateralUpdated(uint256 value);\n event NetworkEarningsWithdrawn(uint256 value, address recipient);\n event NetworkFeeUpdated(uint256 oldFee, uint256 newFee);\n event OperatorAdded(\n uint64 indexed operatorId,\n address indexed owner,\n bytes publicKey,\n uint256 fee\n );\n event OperatorFeeDeclarationCancelled(\n address indexed owner,\n uint64 indexed operatorId\n );\n event OperatorFeeDeclared(\n address indexed owner,\n uint64 indexed operatorId,\n uint256 blockNumber,\n uint256 fee\n );\n event OperatorFeeExecuted(\n address indexed owner,\n uint64 indexed operatorId,\n uint256 blockNumber,\n uint256 fee\n );\n event OperatorFeeIncreaseLimitUpdated(uint64 value);\n event OperatorMaximumFeeUpdated(uint64 maxFee);\n event OperatorRemoved(uint64 indexed operatorId);\n event OperatorWhitelistUpdated(\n uint64 indexed operatorId,\n address whitelisted\n );\n event OperatorWithdrawn(\n address indexed owner,\n uint64 indexed operatorId,\n uint256 value\n );\n event OwnershipTransferStarted(\n address indexed previousOwner,\n address indexed newOwner\n );\n event OwnershipTransferred(\n address indexed previousOwner,\n address indexed newOwner\n );\n event Upgraded(address indexed implementation);\n event ValidatorAdded(\n address indexed owner,\n uint64[] operatorIds,\n bytes publicKey,\n bytes shares,\n Cluster cluster\n );\n event ValidatorExited(\n address indexed owner,\n uint64[] operatorIds,\n bytes publicKey\n );\n event ValidatorRemoved(\n address indexed owner,\n uint64[] operatorIds,\n bytes publicKey,\n Cluster cluster\n );\n\n fallback() external;\n\n function acceptOwnership() external;\n\n function cancelDeclaredOperatorFee(uint64 operatorId) external;\n\n function declareOperatorFee(uint64 operatorId, uint256 fee) external;\n\n function deposit(\n address clusterOwner,\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function executeOperatorFee(uint64 operatorId) external;\n\n function exitValidator(bytes memory publicKey, uint64[] memory operatorIds)\n external;\n\n function bulkExitValidator(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds\n ) external;\n\n function getVersion() external pure returns (string memory version);\n\n function initialize(\n address token_,\n address ssvOperators_,\n address ssvClusters_,\n address ssvDAO_,\n address ssvViews_,\n uint64 minimumBlocksBeforeLiquidation_,\n uint256 minimumLiquidationCollateral_,\n uint32 validatorsPerOperatorLimit_,\n uint64 declareOperatorFeePeriod_,\n uint64 executeOperatorFeePeriod_,\n uint64 operatorMaxFeeIncrease_\n ) external;\n\n function liquidate(\n address clusterOwner,\n uint64[] memory operatorIds,\n Cluster memory cluster\n ) external;\n\n function owner() external view returns (address);\n\n function pendingOwner() external view returns (address);\n\n function proxiableUUID() external view returns (bytes32);\n\n function reactivate(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function reduceOperatorFee(uint64 operatorId, uint256 fee) external;\n\n function registerOperator(bytes memory publicKey, uint256 fee)\n external\n returns (uint64 id);\n\n function registerValidator(\n bytes memory publicKey,\n uint64[] memory operatorIds,\n bytes memory sharesData,\n Cluster memory cluster\n ) external payable;\n\n function bulkRegisterValidator(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds,\n bytes[] calldata sharesData,\n Cluster memory cluster\n ) external payable;\n\n function migrateClusterToETH(\n uint64[] calldata operatorIds,\n Cluster memory cluster\n ) external payable;\n\n function removeOperator(uint64 operatorId) external;\n\n function removeValidator(\n bytes memory publicKey,\n uint64[] memory operatorIds,\n Cluster memory cluster\n ) external;\n\n function bulkRemoveValidator(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds,\n Cluster memory cluster\n ) external;\n\n function renounceOwnership() external;\n\n function setFeeRecipientAddress(address recipientAddress) external;\n\n function setOperatorWhitelist(uint64 operatorId, address whitelisted)\n external;\n\n function transferOwnership(address newOwner) external;\n\n function updateDeclareOperatorFeePeriod(uint64 timeInSeconds) external;\n\n function updateExecuteOperatorFeePeriod(uint64 timeInSeconds) external;\n\n function updateLiquidationThresholdPeriod(uint64 blocks) external;\n\n function updateMaximumOperatorFee(uint64 maxFee) external;\n\n function updateMinimumLiquidationCollateral(uint256 amount) external;\n\n function updateModule(uint8 moduleId, address moduleAddress) external;\n\n function updateNetworkFee(uint256 fee) external;\n\n function updateOperatorFeeIncreaseLimit(uint64 percentage) external;\n\n function upgradeTo(address newImplementation) external;\n\n function upgradeToAndCall(address newImplementation, bytes memory data)\n external\n payable;\n\n function withdraw(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function withdrawAllOperatorEarnings(uint64 operatorId) external;\n\n function withdrawNetworkEarnings(uint256 amount) external;\n\n function withdrawOperatorEarnings(uint64 operatorId, uint256 amount)\n external;\n}\n" + }, + "contracts/interfaces/IStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\n */\ninterface IStrategy {\n /**\n * @dev Deposit the given asset to platform\n * @param _asset asset address\n * @param _amount Amount to deposit\n */\n function deposit(address _asset, uint256 _amount) external;\n\n /**\n * @dev Deposit the entire balance of all supported assets in the Strategy\n * to the platform\n */\n function depositAll() external;\n\n /**\n * @dev Withdraw given asset from Lending platform\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external;\n\n /**\n * @dev Liquidate all assets in strategy and return them to Vault.\n */\n function withdrawAll() external;\n\n /**\n * @dev Returns the current balance of the given asset.\n */\n function checkBalance(address _asset)\n external\n view\n returns (uint256 balance);\n\n /**\n * @dev Returns bool indicating whether strategy supports asset.\n */\n function supportsAsset(address _asset) external view returns (bool);\n\n /**\n * @dev Collect reward tokens from the Strategy.\n */\n function collectRewardTokens() external;\n\n /**\n * @dev The address array of the reward tokens for the Strategy.\n */\n function getRewardTokenAddresses() external view returns (address[] memory);\n\n function harvesterAddress() external view returns (address);\n\n function transferToken(address token, uint256 amount) external;\n\n function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\n external;\n}\n" + }, + "contracts/interfaces/IVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultStorage } from \"../vault/VaultStorage.sol\";\n\ninterface IVault {\n // slither-disable-start constable-states\n\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\n event StrategyApproved(address _addr);\n event StrategyRemoved(address _addr);\n event Mint(address _addr, uint256 _value);\n event Redeem(address _addr, uint256 _value);\n event CapitalPaused();\n event CapitalUnpaused();\n event DefaultStrategyUpdated(address _strategy);\n event RebasePaused();\n event RebaseUnpaused();\n event VaultBufferUpdated(uint256 _vaultBuffer);\n event AllocateThresholdUpdated(uint256 _threshold);\n event StrategistUpdated(address _address);\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\n event TrusteeFeeBpsChanged(uint256 _basis);\n event TrusteeAddressChanged(address _address);\n event StrategyAddedToMintWhitelist(address indexed strategy);\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\n event DripDurationChanged(uint256 dripDuration);\n event WithdrawalRequested(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount,\n uint256 _queued\n );\n event WithdrawalClaimed(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount\n );\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\n\n // Governable.sol\n function transferGovernance(address _newGovernor) external;\n\n function claimGovernance() external;\n\n function governor() external view returns (address);\n\n // VaultAdmin.sol\n function setVaultBuffer(uint256 _vaultBuffer) external;\n\n function vaultBuffer() external view returns (uint256);\n\n function setAutoAllocateThreshold(uint256 _threshold) external;\n\n function autoAllocateThreshold() external view returns (uint256);\n\n function setStrategistAddr(address _address) external;\n\n function strategistAddr() external view returns (address);\n\n function setOperatorAddr(address _operator) external;\n\n function operatorAddr() external view returns (address);\n\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\n\n function maxSupplyDiff() external view returns (uint256);\n\n function setTrusteeAddress(address _address) external;\n\n function trusteeAddress() external view returns (address);\n\n function setTrusteeFeeBps(uint256 _basis) external;\n\n function trusteeFeeBps() external view returns (uint256);\n\n function approveStrategy(address _addr) external;\n\n function removeStrategy(address _addr) external;\n\n function setDefaultStrategy(address _strategy) external;\n\n function defaultStrategy() external view returns (address);\n\n function pauseRebase() external;\n\n function unpauseRebase() external;\n\n function rebasePaused() external view returns (bool);\n\n function pauseCapital() external;\n\n function unpauseCapital() external;\n\n function capitalPaused() external view returns (bool);\n\n function transferToken(address _asset, uint256 _amount) external;\n\n function withdrawAllFromStrategy(address _strategyAddr) external;\n\n function withdrawAllFromStrategies() external;\n\n function withdrawFromStrategy(\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external;\n\n function depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external;\n\n // VaultCore.sol\n function mint(uint256 _amount) external;\n\n function mintForStrategy(uint256 _amount) external;\n\n function burnForStrategy(uint256 _amount) external;\n\n function allocate() external;\n\n function rebase() external;\n\n function totalValue() external view returns (uint256 value);\n\n function checkBalance(address _asset) external view returns (uint256);\n\n function getAssetCount() external view returns (uint256);\n\n function getAllAssets() external view returns (address[] memory);\n\n function getStrategyCount() external view returns (uint256);\n\n function getAllStrategies() external view returns (address[] memory);\n\n function strategies(address _addr)\n external\n view\n returns (VaultStorage.Strategy memory);\n\n /// @notice Deprecated: use `asset()` instead.\n function isSupportedAsset(address _asset) external view returns (bool);\n\n function asset() external view returns (address);\n\n function oToken() external view returns (address);\n\n function initialize(address) external;\n\n function addWithdrawalQueueLiquidity() external;\n\n function requestWithdrawal(uint256 _amount)\n external\n returns (uint256 requestId, uint256 queued);\n\n function claimWithdrawal(uint256 requestId)\n external\n returns (uint256 amount);\n\n function claimWithdrawals(uint256[] memory requestIds)\n external\n returns (uint256[] memory amounts, uint256 totalAmount);\n\n function withdrawalQueueMetadata()\n external\n view\n returns (VaultStorage.WithdrawalQueueMetadata memory);\n\n function withdrawalRequests(uint256 requestId)\n external\n view\n returns (VaultStorage.WithdrawalRequest memory);\n\n function addStrategyToMintWhitelist(address strategyAddr) external;\n\n function removeStrategyFromMintWhitelist(address strategyAddr) external;\n\n function isMintWhitelistedStrategy(address strategyAddr)\n external\n view\n returns (bool);\n\n function withdrawalClaimDelay() external view returns (uint256);\n\n function setWithdrawalClaimDelay(uint256 newDelay) external;\n\n function lastRebase() external view returns (uint64);\n\n function dripDuration() external view returns (uint64);\n\n function setDripDuration(uint256 _dripDuration) external;\n\n function rebasePerSecondMax() external view returns (uint64);\n\n function setRebaseRateMax(uint256 yearlyApr) external;\n\n function rebasePerSecondTarget() external view returns (uint64);\n\n function previewYield() external view returns (uint256 yield);\n\n // slither-disable-end constable-states\n}\n" + }, + "contracts/interfaces/IWETH9.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IWETH9 {\n event Approval(address indexed src, address indexed guy, uint256 wad);\n event Deposit(address indexed dst, uint256 wad);\n event Transfer(address indexed src, address indexed dst, uint256 wad);\n event Withdrawal(address indexed src, uint256 wad);\n\n function allowance(address, address) external view returns (uint256);\n\n function approve(address guy, uint256 wad) external returns (bool);\n\n function balanceOf(address) external view returns (uint256);\n\n function decimals() external view returns (uint8);\n\n function deposit() external payable;\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address dst, uint256 wad) external returns (bool);\n\n function transferFrom(\n address src,\n address dst,\n uint256 wad\n ) external returns (bool);\n\n function withdraw(uint256 wad) external;\n}\n" + }, + "contracts/interfaces/morpho/IMorphoV2Adapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IMorphoV2Adapter {\n // address of the underlying vault\n function morphoVaultV1() external view returns (address);\n\n // address of the parent Morpho V2 vault\n function parentVault() external view returns (address);\n}\n" + }, + "contracts/interfaces/morpho/IVaultV2.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC4626 } from \"../../../lib/openzeppelin/interfaces/IERC4626.sol\";\n\ninterface IVaultV2 is IERC4626 {\n function liquidityAdapter() external view returns (address);\n}\n" + }, + "contracts/interfaces/sonic/ISFC.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\n\n/**\n * @title Special Fee Contract for Sonic network\n * @notice The SFC maintains a list of validators and delegators and distributes rewards to them.\n * @custom:security-contact security@fantom.foundation\n */\ninterface ISFC {\n error StakeIsFullySlashed();\n\n event CreatedValidator(\n uint256 indexed validatorID,\n address indexed auth,\n uint256 createdEpoch,\n uint256 createdTime\n );\n event Delegated(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 amount\n );\n event Undelegated(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 indexed wrID,\n uint256 amount\n );\n event Withdrawn(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 indexed wrID,\n uint256 amount,\n uint256 penalty\n );\n event ClaimedRewards(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 rewards\n );\n event RestakedRewards(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 rewards\n );\n event BurntFTM(uint256 amount);\n event UpdatedSlashingRefundRatio(\n uint256 indexed validatorID,\n uint256 refundRatio\n );\n event RefundedSlashedLegacyDelegation(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 amount\n );\n\n event DeactivatedValidator(\n uint256 indexed validatorID,\n uint256 deactivatedEpoch,\n uint256 deactivatedTime\n );\n event ChangedValidatorStatus(uint256 indexed validatorID, uint256 status);\n event AnnouncedRedirection(address indexed from, address indexed to);\n\n function currentSealedEpoch() external view returns (uint256);\n\n function getEpochSnapshot(uint256 epoch)\n external\n view\n returns (\n uint256 endTime,\n uint256 endBlock,\n uint256 epochFee,\n uint256 baseRewardPerSecond,\n uint256 totalStake,\n uint256 totalSupply\n );\n\n function getStake(address delegator, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function getValidator(uint256 validatorID)\n external\n view\n returns (\n uint256 status,\n uint256 receivedStake,\n address auth,\n uint256 createdEpoch,\n uint256 createdTime,\n uint256 deactivatedTime,\n uint256 deactivatedEpoch\n );\n\n function getValidatorID(address auth) external view returns (uint256);\n\n function getValidatorPubkey(uint256 validatorID)\n external\n view\n returns (bytes memory);\n\n function pubkeyAddressvalidatorID(address pubkeyAddress)\n external\n view\n returns (uint256);\n\n function getWithdrawalRequest(\n address delegator,\n uint256 validatorID,\n uint256 wrID\n )\n external\n view\n returns (\n uint256 epoch,\n uint256 time,\n uint256 amount\n );\n\n function isOwner() external view returns (bool);\n\n function lastValidatorID() external view returns (uint256);\n\n function minGasPrice() external view returns (uint256);\n\n function owner() external view returns (address);\n\n function renounceOwnership() external;\n\n function slashingRefundRatio(uint256 validatorID)\n external\n view\n returns (uint256);\n\n function stashedRewardsUntilEpoch(address delegator, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function totalActiveStake() external view returns (uint256);\n\n function totalStake() external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function transferOwnership(address newOwner) external;\n\n function treasuryAddress() external view returns (address);\n\n function version() external pure returns (bytes3);\n\n function currentEpoch() external view returns (uint256);\n\n function updateConstsAddress(address v) external;\n\n function constsAddress() external view returns (address);\n\n function getEpochValidatorIDs(uint256 epoch)\n external\n view\n returns (uint256[] memory);\n\n function getEpochReceivedStake(uint256 epoch, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function getEpochAccumulatedRewardPerToken(\n uint256 epoch,\n uint256 validatorID\n ) external view returns (uint256);\n\n function getEpochAccumulatedUptime(uint256 epoch, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function getEpochAverageUptime(uint256 epoch, uint256 validatorID)\n external\n view\n returns (uint32);\n\n function getEpochAccumulatedOriginatedTxsFee(\n uint256 epoch,\n uint256 validatorID\n ) external view returns (uint256);\n\n function getEpochOfflineTime(uint256 epoch, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function getEpochOfflineBlocks(uint256 epoch, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function getEpochEndBlock(uint256 epoch) external view returns (uint256);\n\n function rewardsStash(address delegator, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function createValidator(bytes calldata pubkey) external payable;\n\n function getSelfStake(uint256 validatorID) external view returns (uint256);\n\n function delegate(uint256 validatorID) external payable;\n\n function undelegate(\n uint256 validatorID,\n uint256 wrID,\n uint256 amount\n ) external;\n\n function isSlashed(uint256 validatorID) external view returns (bool);\n\n function withdraw(uint256 validatorID, uint256 wrID) external;\n\n function deactivateValidator(uint256 validatorID, uint256 status) external;\n\n function pendingRewards(address delegator, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function stashRewards(address delegator, uint256 validatorID) external;\n\n function claimRewards(uint256 validatorID) external;\n\n function restakeRewards(uint256 validatorID) external;\n\n function updateSlashingRefundRatio(uint256 validatorID, uint256 refundRatio)\n external;\n\n function updateTreasuryAddress(address v) external;\n\n function burnFTM(uint256 amount) external;\n\n function sealEpoch(\n uint256[] calldata offlineTime,\n uint256[] calldata offlineBlocks,\n uint256[] calldata uptimes,\n uint256[] calldata originatedTxsFee\n ) external;\n\n function sealEpochValidators(uint256[] calldata nextValidatorIDs) external;\n\n function initialize(\n uint256 sealedEpoch,\n uint256 _totalSupply,\n address nodeDriver,\n address consts,\n address _owner\n ) external;\n\n function setGenesisValidator(\n address auth,\n uint256 validatorID,\n bytes calldata pubkey,\n uint256 createdTime\n ) external;\n\n function setGenesisDelegation(\n address delegator,\n uint256 validatorID,\n uint256 stake\n ) external;\n\n function updateStakeSubscriberAddress(address v) external;\n\n function stakeSubscriberAddress() external view returns (address);\n\n function setRedirectionAuthorizer(address v) external;\n\n function announceRedirection(address to) external;\n\n function initiateRedirection(address from, address to) external;\n\n function redirect(address to) external;\n}\n" + }, + "contracts/interfaces/sonic/IWrappedSonic.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IWrappedSonic {\n event Deposit(address indexed account, uint256 value);\n event Withdrawal(address indexed account, uint256 value);\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n\n function allowance(address owner, address spender)\n external\n view\n returns (uint256);\n\n function approve(address spender, uint256 value) external returns (bool);\n\n function balanceOf(address account) external view returns (uint256);\n\n function decimals() external view returns (uint8);\n\n function deposit() external payable;\n\n function depositFor(address account) external payable returns (bool);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address to, uint256 value) external returns (bool);\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external returns (bool);\n\n function withdraw(uint256 value) external;\n\n function withdrawTo(address account, uint256 value) external returns (bool);\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV2Router02.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IUniswapV2Router {\n function WETH() external pure returns (address);\n\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n\n function addLiquidity(\n address tokenA,\n address tokenB,\n uint256 amountADesired,\n uint256 amountBDesired,\n uint256 amountAMin,\n uint256 amountBMin,\n address to,\n uint256 deadline\n )\n external\n returns (\n uint256 amountA,\n uint256 amountB,\n uint256 liquidity\n );\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV3Router.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// -- Solididy v0.5.x compatible interface\ninterface IUniswapV3Router {\n struct ExactInputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n }\n\n /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path\n /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata\n /// @return amountOut The amount of the received token\n function exactInput(ExactInputParams calldata params)\n external\n payable\n returns (uint256 amountOut);\n}\n" + }, + "contracts/mocks/crosschain/CCTPMessageTransmitterMock.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ICCTPMessageTransmitter } from \"../../interfaces/cctp/ICCTP.sol\";\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { BytesHelper } from \"../../utils/BytesHelper.sol\";\nimport { AbstractCCTPIntegrator } from \"../../strategies/crosschain/AbstractCCTPIntegrator.sol\";\n\n/**\n * @title Mock conctract simulating the functionality of the CCTPTokenMessenger contract\n * for the porposes of unit testing.\n * @author Origin Protocol Inc\n */\n\ncontract CCTPMessageTransmitterMock is ICCTPMessageTransmitter {\n using BytesHelper for bytes;\n\n IERC20 public usdc;\n uint256 public nonce = 0;\n // Sender index in the burn message v2\n // Ref: https://github.com/circlefin/evm-cctp-contracts/blob/master/src/messages/v2/BurnMessageV2.sol\n uint8 constant BURN_MESSAGE_V2_MESSAGE_SENDER_INDEX = 100;\n uint8 constant BURN_MESSAGE_V2_HOOK_DATA_INDEX = 228;\n\n uint16 public messageFinality = 2000;\n address public messageSender;\n uint32 public sourceDomain = 4294967295; // 0xFFFFFFFF\n\n // Full message with header\n struct Message {\n uint32 version;\n uint32 sourceDomain;\n uint32 destinationDomain;\n bytes32 recipient;\n bytes32 messageHeaderRecipient;\n bytes32 sender;\n bytes32 destinationCaller;\n uint32 minFinalityThreshold;\n bool isTokenTransfer;\n uint256 tokenAmount;\n bytes messageBody;\n }\n\n Message[] public messages;\n // map of encoded messages to the corresponding message structs\n mapping(bytes32 => Message) public encodedMessages;\n\n constructor(address _usdc) {\n usdc = IERC20(_usdc);\n }\n\n // @dev for the porposes of unit tests queues the message to be mock-sent using\n // the cctp bridge.\n function sendMessage(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n uint32 minFinalityThreshold,\n bytes memory messageBody\n ) external virtual override {\n bytes32 nonceHash = keccak256(abi.encodePacked(nonce));\n nonce++;\n\n // If destination is mainnet, source is base and vice versa\n uint32 sourceDomain = destinationDomain == 0 ? 6 : 0;\n\n Message memory message = Message({\n version: 1,\n sourceDomain: sourceDomain,\n destinationDomain: destinationDomain,\n recipient: recipient,\n messageHeaderRecipient: recipient,\n sender: bytes32(uint256(uint160(msg.sender))),\n destinationCaller: destinationCaller,\n minFinalityThreshold: minFinalityThreshold,\n isTokenTransfer: false,\n tokenAmount: 0,\n messageBody: messageBody\n });\n\n messages.push(message);\n }\n\n // @dev for the porposes of unit tests queues the USDC burn/mint to be executed\n // using the cctp bridge.\n function sendTokenTransferMessage(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n uint32 minFinalityThreshold,\n uint256 tokenAmount,\n bytes memory messageBody\n ) external {\n bytes32 nonceHash = keccak256(abi.encodePacked(nonce));\n nonce++;\n\n // If destination is mainnet, source is base and vice versa\n uint32 sourceDomain = destinationDomain == 0 ? 6 : 0;\n\n Message memory message = Message({\n version: 1,\n sourceDomain: sourceDomain,\n destinationDomain: destinationDomain,\n recipient: recipient,\n messageHeaderRecipient: recipient,\n sender: bytes32(uint256(uint160(msg.sender))),\n destinationCaller: destinationCaller,\n minFinalityThreshold: minFinalityThreshold,\n isTokenTransfer: true,\n tokenAmount: tokenAmount,\n messageBody: messageBody\n });\n\n messages.push(message);\n }\n\n function receiveMessage(bytes memory message, bytes memory attestation)\n public\n virtual\n override\n returns (bool)\n {\n Message memory storedMsg = encodedMessages[keccak256(message)];\n AbstractCCTPIntegrator recipient = AbstractCCTPIntegrator(\n address(uint160(uint256(storedMsg.recipient)))\n );\n\n bytes32 sender = storedMsg.sender;\n bytes memory messageBody = storedMsg.messageBody;\n\n // Credit USDC in this step as it is done in the live cctp contracts\n if (storedMsg.isTokenTransfer) {\n usdc.transfer(address(recipient), storedMsg.tokenAmount);\n // override the sender with the one stored in the Burn message as the sender int he\n // message header is the TokenMessenger.\n sender = bytes32(\n uint256(\n uint160(\n storedMsg.messageBody.extractAddress(\n BURN_MESSAGE_V2_MESSAGE_SENDER_INDEX\n )\n )\n )\n );\n messageBody = storedMsg.messageBody.extractSlice(\n BURN_MESSAGE_V2_HOOK_DATA_INDEX,\n storedMsg.messageBody.length\n );\n } else {\n bytes32 overrideSenderBytes = bytes32(\n uint256(uint160(messageSender))\n );\n if (messageFinality >= 2000) {\n recipient.handleReceiveFinalizedMessage(\n sourceDomain == 4294967295\n ? storedMsg.sourceDomain\n : sourceDomain,\n messageSender == address(0) ? sender : overrideSenderBytes,\n messageFinality,\n messageBody\n );\n } else {\n recipient.handleReceiveUnfinalizedMessage(\n sourceDomain == 4294967295\n ? storedMsg.sourceDomain\n : sourceDomain,\n messageSender == address(0) ? sender : overrideSenderBytes,\n messageFinality,\n messageBody\n );\n }\n }\n\n return true;\n }\n\n function addMessage(Message memory storedMsg) external {\n messages.push(storedMsg);\n }\n\n function _encodeMessageHeader(\n uint32 version,\n uint32 sourceDomain,\n bytes32 sender,\n bytes32 recipient,\n bytes memory messageBody\n ) internal pure returns (bytes memory) {\n bytes memory header = abi.encodePacked(\n version, // 0-3\n sourceDomain, // 4-7\n bytes32(0), // 8-39 destinationDomain\n bytes4(0), // 40-43 nonce\n sender, // 44-75 sender\n recipient, // 76-107 recipient\n bytes32(0), // other stuff\n bytes8(0) // other stuff\n );\n return abi.encodePacked(header, messageBody);\n }\n\n function _removeFront() internal returns (Message memory) {\n require(messages.length > 0, \"No messages\");\n Message memory removed = messages[0];\n // Shift array\n for (uint256 i = 0; i < messages.length - 1; i++) {\n messages[i] = messages[i + 1];\n }\n messages.pop();\n return removed;\n }\n\n function _processMessage(Message memory storedMsg) internal {\n bytes memory encodedMessage = _encodeMessageHeader(\n storedMsg.version,\n storedMsg.sourceDomain,\n storedMsg.sender,\n storedMsg.messageHeaderRecipient,\n storedMsg.messageBody\n );\n\n encodedMessages[keccak256(encodedMessage)] = storedMsg;\n\n address recipient = address(uint160(uint256(storedMsg.recipient)));\n\n AbstractCCTPIntegrator(recipient).relay(encodedMessage, bytes(\"\"));\n }\n\n function _removeBack() internal returns (Message memory) {\n require(messages.length > 0, \"No messages\");\n Message memory last = messages[messages.length - 1];\n messages.pop();\n return last;\n }\n\n function messagesInQueue() external view returns (uint256) {\n return messages.length;\n }\n\n function processFrontOverrideHeader(bytes4 customHeader) external {\n Message memory storedMsg = _removeFront();\n\n bytes memory modifiedBody = abi.encodePacked(\n customHeader,\n storedMsg.messageBody.extractSlice(4, storedMsg.messageBody.length)\n );\n\n storedMsg.messageBody = modifiedBody;\n\n _processMessage(storedMsg);\n }\n\n function processFrontOverrideVersion(uint32 customVersion) external {\n Message memory storedMsg = _removeFront();\n storedMsg.version = customVersion;\n _processMessage(storedMsg);\n }\n\n function processFrontOverrideSender(address customSender) external {\n Message memory storedMsg = _removeFront();\n storedMsg.sender = bytes32(uint256(uint160(customSender)));\n _processMessage(storedMsg);\n }\n\n function processFrontOverrideRecipient(address customRecipient) external {\n Message memory storedMsg = _removeFront();\n storedMsg.messageHeaderRecipient = bytes32(\n uint256(uint160(customRecipient))\n );\n _processMessage(storedMsg);\n }\n\n function processFrontOverrideMessageBody(bytes memory customMessageBody)\n external\n {\n Message memory storedMsg = _removeFront();\n storedMsg.messageBody = customMessageBody;\n _processMessage(storedMsg);\n }\n\n function processFront() external {\n Message memory storedMsg = _removeFront();\n _processMessage(storedMsg);\n }\n\n function processBack() external {\n Message memory storedMsg = _removeBack();\n _processMessage(storedMsg);\n }\n\n function getMessagesLength() external view returns (uint256) {\n return messages.length;\n }\n\n function overrideMessageFinality(uint16 _finality) external {\n messageFinality = _finality;\n }\n\n function overrideSender(address _sender) external {\n messageSender = _sender;\n }\n\n function overrideSourceDomain(uint32 _sourceDomain) external {\n sourceDomain = _sourceDomain;\n }\n}\n" + }, + "contracts/mocks/crosschain/CCTPMessageTransmitterMock2.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IMessageHandlerV2 } from \"../../interfaces/cctp/ICCTP.sol\";\nimport { BytesHelper } from \"../../utils/BytesHelper.sol\";\nimport { CCTPMessageTransmitterMock } from \"./CCTPMessageTransmitterMock.sol\";\n\nuint8 constant SOURCE_DOMAIN_INDEX = 4;\nuint8 constant RECIPIENT_INDEX = 76;\nuint8 constant SENDER_INDEX = 44;\nuint8 constant MESSAGE_BODY_INDEX = 148;\n\n/**\n * @title Mock conctract simulating the functionality of the CCTPTokenMessenger contract\n * for the porposes of unit testing.\n * @author Origin Protocol Inc\n */\n\ncontract CCTPMessageTransmitterMock2 is CCTPMessageTransmitterMock {\n using BytesHelper for bytes;\n\n address public cctpTokenMessenger;\n uint32 public peerDomainId;\n\n event MessageReceivedInMockTransmitter(bytes message);\n event MessageSent(bytes message);\n\n constructor(address _usdc, uint32 _peerDomainId)\n CCTPMessageTransmitterMock(_usdc)\n {\n peerDomainId = _peerDomainId;\n }\n\n function setCCTPTokenMessenger(address _cctpTokenMessenger) external {\n cctpTokenMessenger = _cctpTokenMessenger;\n }\n\n function setPeerDomainId(uint32 _peerDomainId) external {\n peerDomainId = _peerDomainId;\n }\n\n function sendMessage(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n uint32 minFinalityThreshold,\n bytes memory messageBody\n ) external virtual override {\n bytes memory message = abi.encodePacked(\n uint32(1), // version\n destinationDomain == 0 ? peerDomainId : 0, // source domain\n uint32(destinationDomain), // destination domain\n uint256(0),\n bytes32(uint256(uint160(msg.sender))), // sender\n recipient, // recipient\n destinationCaller, // destination caller\n minFinalityThreshold, // min finality threshold\n uint32(0),\n messageBody // message body\n );\n emit MessageSent(message);\n }\n\n function receiveMessage(bytes memory message, bytes memory attestation)\n public\n virtual\n override\n returns (bool)\n {\n uint32 sourceDomain = message.extractUint32(SOURCE_DOMAIN_INDEX);\n address recipient = message.extractAddress(RECIPIENT_INDEX);\n address sender = message.extractAddress(SENDER_INDEX);\n\n bytes memory messageBody = message.extractSlice(\n MESSAGE_BODY_INDEX,\n message.length\n );\n\n bool isBurnMessage = recipient == cctpTokenMessenger;\n\n if (isBurnMessage) {\n // recipient = messageBody.extractAddress(BURN_MESSAGE_V2_RECIPIENT_INDEX);\n // This step won't mint USDC, transfer it to the recipient address\n // in your tests\n } else {\n IMessageHandlerV2(recipient).handleReceiveFinalizedMessage(\n sourceDomain,\n bytes32(uint256(uint160(sender))),\n 2000,\n messageBody\n );\n }\n\n // This step won't mint USDC, transfer it to the recipient address\n // in your tests\n emit MessageReceivedInMockTransmitter(message);\n\n return true;\n }\n}\n" + }, + "contracts/mocks/crosschain/CCTPTokenMessengerMock.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ICCTPTokenMessenger } from \"../../interfaces/cctp/ICCTP.sol\";\nimport { CCTPMessageTransmitterMock } from \"./CCTPMessageTransmitterMock.sol\";\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\n\n/**\n * @title Mock conctract simulating the functionality of the CCTPTokenMessenger contract\n * for the porposes of unit testing.\n * @author Origin Protocol Inc\n */\n\ncontract CCTPTokenMessengerMock is ICCTPTokenMessenger {\n IERC20 public usdc;\n CCTPMessageTransmitterMock public cctpMessageTransmitterMock;\n\n constructor(address _usdc, address _cctpMessageTransmitterMock) {\n usdc = IERC20(_usdc);\n cctpMessageTransmitterMock = CCTPMessageTransmitterMock(\n _cctpMessageTransmitterMock\n );\n }\n\n function depositForBurn(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller,\n uint256 maxFee,\n uint32 minFinalityThreshold\n ) external override {\n revert(\"Not implemented\");\n }\n\n /**\n * @dev mocks the depositForBurnWithHook function by sending the USDC to the CCTPMessageTransmitterMock\n * called by the AbstractCCTPIntegrator contract.\n */\n function depositForBurnWithHook(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller,\n uint256 maxFee,\n uint32 minFinalityThreshold,\n bytes memory hookData\n ) external override {\n require(burnToken == address(usdc), \"Invalid burn token\");\n\n usdc.transferFrom(msg.sender, address(this), maxFee);\n uint256 destinationAmount = amount - maxFee;\n usdc.transferFrom(\n msg.sender,\n address(cctpMessageTransmitterMock),\n destinationAmount\n );\n\n bytes memory burnMessage = _encodeBurnMessageV2(\n mintRecipient,\n amount,\n msg.sender,\n maxFee,\n maxFee,\n hookData\n );\n\n cctpMessageTransmitterMock.sendTokenTransferMessage(\n destinationDomain,\n mintRecipient,\n destinationCaller,\n minFinalityThreshold,\n destinationAmount,\n burnMessage\n );\n }\n\n function _encodeBurnMessageV2(\n bytes32 mintRecipient,\n uint256 amount,\n address messageSender,\n uint256 maxFee,\n uint256 feeExecuted,\n bytes memory hookData\n ) internal view returns (bytes memory) {\n bytes32 burnTokenBytes32 = bytes32(\n abi.encodePacked(bytes12(0), bytes20(uint160(address(usdc))))\n );\n bytes32 messageSenderBytes32 = bytes32(\n abi.encodePacked(bytes12(0), bytes20(uint160(messageSender)))\n );\n bytes32 expirationBlock = bytes32(0);\n\n // Ref: https://developers.circle.com/cctp/technical-guide#message-body\n return\n abi.encodePacked(\n uint32(1), // 0-3: version\n burnTokenBytes32, // 4-35: burnToken (bytes32 left-padded address)\n mintRecipient, // 36-67: mintRecipient (bytes32 left-padded address)\n amount, // 68-99: uint256 amount\n messageSenderBytes32, // 100-131: messageSender (bytes32 left-padded address)\n maxFee, // 132-163: uint256 maxFee\n feeExecuted, // 164-195: uint256 feeExecuted\n expirationBlock, // 196-227: bytes32 expirationBlock\n hookData // 228+: dynamic hookData\n );\n }\n\n function getMinFeeAmount(uint256 amount)\n external\n view\n override\n returns (uint256)\n {\n return 0;\n }\n}\n" + }, + "contracts/mocks/MockAutoWithdrawalVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultStorage } from \"../vault/VaultStorage.sol\";\n\ncontract MockAutoWithdrawalVault {\n address public asset;\n\n VaultStorage.WithdrawalQueueMetadata public withdrawalQueueMetadata;\n\n uint256 private _totalValue;\n bool private _revertNextWithdraw;\n bool private _revertNextDeposit;\n\n event MockedWithdrawal(address strategy, address asset, uint256 amount);\n event MockedDeposit(address strategy, address asset, uint256 amount);\n\n constructor(address _asset) {\n asset = _asset;\n }\n\n function setWithdrawalQueueMetadata(uint256 queued, uint256 claimable)\n external\n {\n withdrawalQueueMetadata.queued = uint128(queued);\n withdrawalQueueMetadata.claimable = uint128(claimable);\n }\n\n function revertNextWithdraw() external {\n _revertNextWithdraw = true;\n }\n\n function revertNextDeposit() external {\n _revertNextDeposit = true;\n }\n\n function setTotalValue(uint256 val) external {\n _totalValue = val;\n }\n\n function totalValue() external view returns (uint256) {\n return _totalValue;\n }\n\n function addWithdrawalQueueLiquidity() external {\n // Do nothing\n }\n\n function withdrawFromStrategy(\n address strategy,\n address[] memory assets,\n uint256[] memory amounts\n ) external {\n if (_revertNextWithdraw) {\n _revertNextWithdraw = false;\n revert(\"Mocked withdrawal revert\");\n }\n emit MockedWithdrawal(strategy, assets[0], amounts[0]);\n }\n\n function depositToStrategy(\n address strategy,\n address[] memory assets,\n uint256[] memory amounts\n ) external {\n if (_revertNextDeposit) {\n _revertNextDeposit = false;\n revert(\"Mocked deposit revert\");\n }\n emit MockedDeposit(strategy, assets[0], amounts[0]);\n }\n}\n" + }, + "contracts/mocks/MockLimitedWrappedOusd.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { WrappedOusd } from \"../token/WrappedOusd.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockLimitedWrappedOusd is WrappedOusd {\n constructor(ERC20 underlying_) WrappedOusd(underlying_) {}\n\n function maxDeposit(address)\n public\n view\n virtual\n override\n returns (uint256)\n {\n return 1e18;\n }\n}\n" + }, + "contracts/mocks/MockNonRebasing.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nimport { OUSD } from \"../token/OUSD.sol\";\n\ncontract MockNonRebasing {\n OUSD oUSD;\n\n function setOUSD(address _oUSDAddress) public {\n oUSD = OUSD(_oUSDAddress);\n }\n\n function rebaseOptIn() public {\n oUSD.rebaseOptIn();\n }\n\n function rebaseOptOut() public {\n oUSD.rebaseOptOut();\n }\n\n function transfer(address _to, uint256 _value) public {\n oUSD.transfer(_to, _value);\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public {\n oUSD.transferFrom(_from, _to, _value);\n }\n\n function approve(address _spender, uint256 _addedValue) public {\n oUSD.approve(_spender, _addedValue);\n }\n\n function mintOusd(address _vaultContract, uint256 _amount) public {\n IVault(_vaultContract).mint(_amount);\n }\n\n function redeemOusd(address _vaultContract, uint256 _amount) public {\n IVault(_vaultContract).requestWithdrawal(_amount);\n }\n\n function approveFor(\n address _contract,\n address _spender,\n uint256 _addedValue\n ) public {\n IERC20(_contract).approve(_spender, _addedValue);\n }\n}\n" + }, + "contracts/mocks/MockRebornMinter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n// solhint-disable-next-line no-console\nimport \"hardhat/console.sol\";\n\ncontract Sanctum {\n address public asset;\n address public vault;\n address public reborner;\n bool public shouldAttack = false;\n // should selfdestruct in the constructor\n bool public shouldDestruct = false;\n uint256 public targetMethod;\n address public ousdContract;\n\n constructor(address _asset, address _vault) {\n asset = _asset;\n vault = _vault;\n }\n\n function deploy(uint256 salt, bytes memory bytecode)\n public\n returns (address addr)\n {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)\n }\n require(addr != address(0), \"Create2: Failed on deploy\");\n }\n\n function computeAddress(uint256 salt, bytes memory bytecode)\n public\n view\n returns (address)\n {\n bytes32 bytecodeHashHash = keccak256(bytecode);\n bytes32 _data = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n bytecodeHashHash\n )\n );\n return address(bytes20(_data << 96));\n }\n\n function setShouldAttack(bool _shouldAttack) public {\n shouldAttack = _shouldAttack;\n }\n\n // should call selfdestruct in the constructor\n function setShouldDesctruct(bool _shouldDestruct) public {\n shouldDestruct = _shouldDestruct;\n }\n\n function setTargetMethod(uint256 target) public {\n targetMethod = target;\n }\n\n function setOUSDAddress(address _ousdContract) public {\n ousdContract = _ousdContract;\n }\n}\n\ncontract Reborner {\n Sanctum sanctum;\n bool logging = false;\n\n constructor(address _sanctum) {\n log(\"We are created...\");\n sanctum = Sanctum(_sanctum);\n if (sanctum.shouldAttack()) {\n log(\"We are attacking now...\");\n\n uint256 target = sanctum.targetMethod();\n\n if (target == 1) {\n redeem();\n } else if (target == 2) {\n transfer();\n } else {\n mint();\n }\n }\n\n if (sanctum.shouldDestruct()) {\n bye();\n }\n }\n\n function mint() public {\n log(\"We are attempting to mint..\");\n address asset = sanctum.asset();\n address vault = sanctum.vault();\n IERC20(asset).approve(vault, 1e6);\n IVault(vault).mint(1e6);\n log(\"We are now minting..\");\n }\n\n function redeem() public {\n log(\"We are attempting to request withdrawal..\");\n address vault = sanctum.vault();\n IVault(vault).requestWithdrawal(1e18);\n log(\"We are now requesting withdrawal..\");\n }\n\n function transfer() public {\n log(\"We are attempting to transfer..\");\n address ousd = sanctum.ousdContract();\n require(IERC20(ousd).transfer(address(1), 1e18), \"transfer failed\");\n log(\"We are now transfering..\");\n }\n\n function bye() public {\n log(\"We are now destructing..\");\n selfdestruct(payable(msg.sender));\n }\n\n function log(string memory message) internal view {\n if (logging) {\n // solhint-disable-next-line no-console\n console.log(message);\n }\n }\n}\n" + }, + "contracts/mocks/MockVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"../vault/VaultAdmin.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport \"../utils/Helpers.sol\";\n\ncontract MockVault is VaultAdmin {\n using StableMath for uint256;\n\n uint256 storedTotalValue;\n\n constructor(address _asset) VaultAdmin(_asset) {}\n\n function setTotalValue(uint256 _value) public {\n storedTotalValue = _value;\n }\n\n function totalValue() external view override returns (uint256) {\n return storedTotalValue;\n }\n\n function _totalValue() internal view override returns (uint256) {\n return storedTotalValue;\n }\n\n function _checkBalance(address _asset)\n internal\n view\n override\n returns (uint256 balance)\n {\n // Avoids rounding errors by returning the total value\n // in a single currency\n if (asset == _asset) {\n uint256 decimals = Helpers.getDecimals(_asset);\n return storedTotalValue.scaleBy(decimals, 18);\n } else {\n return 0;\n }\n }\n}\n" + }, + "contracts/mocks/MockVaultCoreInstantRebase.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultCore } from \"../vault/VaultCore.sol\";\n\ncontract MockVaultCoreInstantRebase is VaultCore {\n constructor(address _asset) VaultCore(_asset) {}\n\n function _nextYield(uint256 supply, uint256 vaultValue)\n internal\n view\n override\n returns (uint256 yield, uint256 targetRate)\n {\n if (vaultValue <= supply) {\n return (0, 0);\n }\n yield = vaultValue - supply;\n return (yield, 0);\n }\n}\n" + }, + "contracts/mocks/TestUpgradedOUSD.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../token/OUSD.sol\";\n\n// used to alter internal state of OUSD contract\ncontract TestUpgradedOUSD is OUSD {\n constructor() OUSD() {}\n\n function overwriteCreditBalances(address _account, uint256 _creditBalance)\n public\n {\n creditBalances[_account] = _creditBalance;\n }\n\n function overwriteAlternativeCPT(address _account, uint256 _acpt) public {\n alternativeCreditsPerToken[_account] = _acpt;\n }\n\n function overwriteRebaseState(address _account, RebaseOptions _rebaseOption)\n public\n {\n rebaseState[_account] = _rebaseOption;\n }\n}\n" + }, + "contracts/strategies/aerodrome/AerodromeAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Aerodrome AMO strategy\n * @author Origin Protocol Inc\n */\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\n\nimport { ISugarHelper } from \"../../interfaces/aerodrome/ISugarHelper.sol\";\nimport { INonfungiblePositionManager } from \"../../interfaces/aerodrome/INonfungiblePositionManager.sol\";\nimport { ISwapRouter } from \"../../interfaces/aerodrome/ISwapRouter.sol\";\nimport { ICLPool } from \"../../interfaces/aerodrome/ICLPool.sol\";\nimport { ICLGauge } from \"../../interfaces/aerodrome/ICLGauge.sol\";\nimport { IVault } from \"../../interfaces/IVault.sol\";\n\ncontract AerodromeAMOStrategy is InitializableAbstractStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n using SafeCast for uint256;\n\n /************************************************\n Important (!) setup configuration\n *************************************************/\n\n /**\n * In order to be able to remove a reasonable amount of complexity from the contract one of the\n * preconditions for this contract to function correctly is to have an outside account mint a small\n * amount of liquidity in the tick space where the contract will deploy's its liquidity and then send\n * that NFT LP position to a dead address (transfer to zero address not allowed.) See example of such\n * NFT LP token:\n * https://basescan.org/token/0x827922686190790b37229fd06084350e74485b72?a=413296#inventory\n */\n\n /***************************************\n Storage slot members\n ****************************************/\n\n /// @notice tokenId of the liquidity position\n uint256 public tokenId;\n /// @dev Minimum amount of tokens the strategy would be able to withdraw from the pool.\n /// minimum amount of tokens are withdrawn at a 1:1 price\n uint256 public underlyingAssets;\n /// @notice Marks the start of the interval that defines the allowed range of WETH share in\n /// the pre-configured pool's liquidity ticker\n uint256 public allowedWethShareStart;\n /// @notice Marks the end of the interval that defines the allowed range of WETH share in\n /// the pre-configured pool's liquidity ticker\n uint256 public allowedWethShareEnd;\n /// @dev reserved for inheritance\n int256[46] private __reserved;\n\n /***************************************\n Constants, structs and events\n ****************************************/\n\n /// @notice The address of the Wrapped ETH (WETH) token contract\n address public immutable WETH;\n /// @notice The address of the OETHb token contract\n address public immutable OETHb;\n /// @notice lower tick set to -1 representing the price of 1.0001 of WETH for 1 OETHb.\n int24 public immutable lowerTick;\n /// @notice lower tick set to 0 representing the price of 1.0000 of WETH for 1 OETHb.\n int24 public immutable upperTick;\n /// @notice tick spacing of the pool (set to 1)\n int24 public immutable tickSpacing;\n /// @notice the swapRouter for performing swaps\n ISwapRouter public immutable swapRouter;\n /// @notice the underlying AMO Slipstream pool\n ICLPool public immutable clPool;\n /// @notice the gauge for the corresponding Slipstream pool (clPool)\n /// @dev can become an immutable once the gauge is created on the base main-net\n ICLGauge public immutable clGauge;\n /// @notice the Position manager contract that is used to manage the pool's position\n INonfungiblePositionManager public immutable positionManager;\n /// @notice helper contract for liquidity and ticker math\n ISugarHelper public immutable helper;\n /// @notice sqrtRatioX96TickLower\n /// @dev tick lower has value -1 and represents the lowest price of WETH priced in OETHb. Meaning the pool\n /// offers less than 1 OETHb for 1 WETH. In other terms to get 1 OETHB the swap needs to offer 1.0001 WETH\n /// this is where purchasing OETHb with WETH within the liquidity position is most expensive\n uint160 public immutable sqrtRatioX96TickLower;\n /// @notice sqrtRatioX96TickHigher\n /// @dev tick higher has value 0 and represents 1:1 price parity of WETH to OETHb\n uint160 public immutable sqrtRatioX96TickHigher;\n /// @dev tick closest to 1:1 price parity\n /// Correctly assessing which tick is closer to 1:1 price parity is important since it affects\n /// the way we calculate the underlying assets in check Balance. The underlying aerodrome pool\n /// orders the tokens depending on the values of their addresses. If OETH token is token0 in the pool\n /// then sqrtRatioX96TickClosestToParity=sqrtRatioX96TickLower. If it is token1 in the pool then\n /// sqrtRatioX96TickClosestToParity=sqrtRatioX96TickHigher\n uint160 public immutable sqrtRatioX96TickClosestToParity;\n\n /// @dev a threshold under which the contract no longer allows for the protocol to rebalance. Guarding\n /// against a strategist / guardian being taken over and with multiple transactions draining the\n /// protocol funds.\n uint256 public constant SOLVENCY_THRESHOLD = 0.998 ether;\n\n error NotEnoughWethForSwap(uint256 wethBalance, uint256 requiredWeth); // 0x989e5ca8\n error NotEnoughWethLiquidity(uint256 wethBalance, uint256 requiredWeth); // 0xa6737d87\n error PoolRebalanceOutOfBounds(\n uint256 currentPoolWethShare,\n uint256 allowedWethShareStart,\n uint256 allowedWethShareEnd\n ); // 0x3681e8e0\n error OutsideExpectedTickRange(int24 currentTick); // 0x5a2eba75\n\n event PoolRebalanced(uint256 currentPoolWethShare);\n\n event PoolWethShareIntervalUpdated(\n uint256 allowedWethShareStart,\n uint256 allowedWethShareEnd\n );\n\n event LiquidityRemoved(\n uint256 withdrawLiquidityShare,\n uint256 removedWETHAmount,\n uint256 removedOETHbAmount,\n uint256 wethAmountCollected,\n uint256 oethbAmountCollected,\n uint256 underlyingAssets\n );\n\n event LiquidityAdded(\n uint256 wethAmountDesired,\n uint256 oethbAmountDesired,\n uint256 wethAmountSupplied,\n uint256 oethbAmountSupplied,\n uint256 tokenId,\n uint256 underlyingAssets\n );\n\n event UnderlyingAssetsUpdated(uint256 underlyingAssets);\n\n /**\n * @dev Un-stakes the token from the gauge for the execution duration of\n * the function and after that re-stakes it back in.\n *\n * It is important that the token is unstaked and owned by the strategy contract\n * during any liquidity altering operations and that it is re-staked back into the\n * gauge after liquidity changes. If the token fails to re-stake back to the\n * gauge it is not earning incentives.\n */\n // all functions using this modifier are used by functions with reentrancy check\n // slither-disable-start reentrancy-no-eth\n modifier gaugeUnstakeAndRestake() {\n // because of solidity short-circuit _isLpTokenStakedInGauge doesn't get called\n // when tokenId == 0\n if (tokenId != 0 && _isLpTokenStakedInGauge()) {\n clGauge.withdraw(tokenId);\n }\n _;\n // because of solidity short-circuit _isLpTokenStakedInGauge doesn't get called\n // when tokenId == 0\n if (tokenId != 0 && !_isLpTokenStakedInGauge()) {\n /**\n * It can happen that a withdrawal (or a full withdrawal) transactions would\n * remove all of the liquidity from the token with a NFT token still existing.\n * In that case the token can not be staked into the gauge, as some liquidity\n * needs to be added to it first.\n */\n if (_getLiquidity() > 0) {\n // if token liquidity changes the positionManager requires re-approval.\n // to any contract pre-approved to handle the token.\n positionManager.approve(address(clGauge), tokenId);\n clGauge.deposit(tokenId);\n }\n }\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice the constructor\n /// @dev This contract is intended to be used as a proxy. To prevent the\n /// potential confusion of having a functional implementation contract\n /// the constructor has the `initializer` modifier. This way the\n /// `initialize` function can not be called on the implementation contract.\n /// For the same reason the implementation contract also has the governor\n /// set to a zero address.\n /// @param _stratConfig the basic strategy configuration\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _oethbAddress Address of the Erc20 OETHb Token contract\n /// @param _swapRouter Address of the Aerodrome Universal Swap Router\n /// @param _nonfungiblePositionManager Address of position manager to add/remove\n /// the liquidity\n /// @param _clPool Address of the Aerodrome concentrated liquidity pool\n /// @param _clGauge Address of the Aerodrome slipstream pool gauge\n /// @param _sugarHelper Address of the Aerodrome Sugar helper contract\n /// @param _lowerBoundingTick Smaller bounding tick of our liquidity position\n /// @param _upperBoundingTick Larger bounding tick of our liquidity position\n /// @param _tickClosestToParity Tick that is closer to 1:1 price parity\n constructor(\n BaseStrategyConfig memory _stratConfig,\n address _wethAddress,\n address _oethbAddress,\n address _swapRouter,\n address _nonfungiblePositionManager,\n address _clPool,\n address _clGauge,\n address _sugarHelper,\n int24 _lowerBoundingTick,\n int24 _upperBoundingTick,\n int24 _tickClosestToParity\n ) initializer InitializableAbstractStrategy(_stratConfig) {\n require(\n _lowerBoundingTick == _tickClosestToParity ||\n _upperBoundingTick == _tickClosestToParity,\n \"Misconfigured tickClosestToParity\"\n );\n require(\n ICLPool(_clPool).token0() == _wethAddress,\n \"Only WETH supported as token0\"\n );\n require(\n ICLPool(_clPool).token1() == _oethbAddress,\n \"Only OETHb supported as token1\"\n );\n int24 _tickSpacing = ICLPool(_clPool).tickSpacing();\n // when we generalize AMO we might support other tick spacings\n require(_tickSpacing == 1, \"Unsupported tickSpacing\");\n\n WETH = _wethAddress;\n OETHb = _oethbAddress;\n swapRouter = ISwapRouter(_swapRouter);\n positionManager = INonfungiblePositionManager(\n _nonfungiblePositionManager\n );\n clPool = ICLPool(_clPool);\n clGauge = ICLGauge(_clGauge);\n helper = ISugarHelper(_sugarHelper);\n sqrtRatioX96TickLower = ISugarHelper(_sugarHelper).getSqrtRatioAtTick(\n _lowerBoundingTick\n );\n sqrtRatioX96TickHigher = ISugarHelper(_sugarHelper).getSqrtRatioAtTick(\n _upperBoundingTick\n );\n sqrtRatioX96TickClosestToParity = ISugarHelper(_sugarHelper)\n .getSqrtRatioAtTick(_tickClosestToParity);\n\n lowerTick = _lowerBoundingTick;\n upperTick = _upperBoundingTick;\n tickSpacing = _tickSpacing;\n\n // prevent implementation contract to be governed\n _setGovernor(address(0));\n }\n\n /**\n * @notice initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n */\n function initialize(address[] memory _rewardTokenAddresses)\n external\n onlyGovernor\n initializer\n {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n new address[](0),\n new address[](0)\n );\n }\n\n /***************************************\n Configuration \n ****************************************/\n\n /**\n * @notice Set allowed pool weth share interval. After the rebalance happens\n * the share of WETH token in the ticker needs to be withing the specifications\n * of the interval.\n *\n * @param _allowedWethShareStart Start of WETH share interval expressed as 18 decimal amount\n * @param _allowedWethShareEnd End of WETH share interval expressed as 18 decimal amount\n */\n function setAllowedPoolWethShareInterval(\n uint256 _allowedWethShareStart,\n uint256 _allowedWethShareEnd\n ) external onlyGovernor {\n require(\n _allowedWethShareStart < _allowedWethShareEnd,\n \"Invalid interval\"\n );\n // can not go below 1% weth share\n require(_allowedWethShareStart > 0.01 ether, \"Invalid interval start\");\n // can not go above 95% weth share\n require(_allowedWethShareEnd < 0.95 ether, \"Invalid interval end\");\n\n allowedWethShareStart = _allowedWethShareStart;\n allowedWethShareEnd = _allowedWethShareEnd;\n emit PoolWethShareIntervalUpdated(\n allowedWethShareStart,\n allowedWethShareEnd\n );\n }\n\n /***************************************\n Periphery utils\n ****************************************/\n\n function _isLpTokenStakedInGauge() internal view returns (bool) {\n require(tokenId != 0, \"Missing NFT LP token\");\n\n address owner = positionManager.ownerOf(tokenId);\n require(\n owner == address(clGauge) || owner == address(this),\n \"Unexpected token owner\"\n );\n return owner == address(clGauge);\n }\n\n /***************************************\n Strategy overrides \n ****************************************/\n\n /**\n * @notice Deposit an amount of assets into the strategy contract. Calling deposit doesn't\n * automatically deposit funds into the underlying Aerodrome pool\n * @param _asset Address for the asset\n * @param _amount Units of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /**\n * @notice Deposit WETH to the strategy contract. This function does not add liquidity to the\n * underlying Aerodrome pool.\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 _wethBalance = IERC20(WETH).balanceOf(address(this));\n if (_wethBalance > 1e12) {\n _deposit(WETH, _wethBalance);\n }\n }\n\n /**\n * @dev Deposit WETH to the contract. This function doesn't deposit the liquidity to the\n * pool, that is done via the rebalance call.\n * @param _asset Address of the asset to deposit\n * @param _amount Amount of assets to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal {\n require(_asset == WETH, \"Unsupported asset\");\n require(_amount > 0, \"Must deposit something\");\n emit Deposit(_asset, address(0), _amount);\n\n // if the pool price is not within the expected interval leave the WETH on the contract\n // as to not break the mints\n (bool _isExpectedRange, ) = _checkForExpectedPoolPrice(false);\n if (_isExpectedRange) {\n // deposit funds into the underlying pool\n _rebalance(0, false, 0);\n }\n }\n\n /**\n * @notice Rebalance the pool to the desired token split and Deposit any WETH on the contract to the\n * underlying aerodrome pool. Print the required amount of corresponding OETHb. After the rebalancing is\n * done burn any potentially remaining OETHb tokens still on the strategy contract.\n *\n * This function has a slightly different behaviour depending on the status of the underlying Aerodrome\n * slipstream pool. The function consists of the following 3 steps:\n * 1. withdrawPartialLiquidity -> so that moving the activeTrading price via a swap is cheaper\n * 2. swapToDesiredPosition -> move active trading price in the pool to be able to deposit WETH & OETHb\n * tokens with the desired pre-configured shares\n * 3. addLiquidity -> add liquidity into the pool respecting share split configuration\n *\n * Scenario 1: When there is no liquidity in the pool from the strategy but there is from other LPs then\n * only step 1 is skipped. (It is important to note that liquidity needs to exist in the configured\n * strategy tick ranges in order for the swap to be possible) Step 3 mints new liquidity position\n * instead of adding to an existing one.\n * Scenario 2: When there is strategy's liquidity in the pool all 3 steps are taken\n *\n *\n * Exact _amountToSwap, _swapWeth & _minTokenReceived parameters shall be determined by simulating the\n * transaction off-chain. The strategy checks that after the swap the share of the tokens is in the\n * expected ranges.\n *\n * @param _amountToSwap The amount of the token to swap\n * @param _swapWeth Swap using WETH when true, use OETHb when false\n * @param _minTokenReceived Slippage check -> minimum amount of token expected in return\n */\n function rebalance(\n uint256 _amountToSwap,\n bool _swapWeth,\n uint256 _minTokenReceived\n ) external nonReentrant onlyGovernorOrStrategist {\n _rebalance(_amountToSwap, _swapWeth, _minTokenReceived);\n }\n\n function _rebalance(\n uint256 _amountToSwap,\n bool _swapWeth,\n uint256 _minTokenReceived\n ) internal {\n /**\n * Would be nice to check if there is any total liquidity in the pool before performing this swap\n * but there is no easy way to do that in UniswapV3:\n * - clPool.liquidity() -> only liquidity in the active tick\n * - asset[1&2].balanceOf(address(clPool)) -> will include uncollected tokens of LP providers\n * after their liquidity position has been decreased\n */\n\n /**\n * When rebalance is called for the first time there is no strategy\n * liquidity in the pool yet. The liquidity removal is thus skipped.\n * Also execute this function when WETH is required for the swap.\n */\n if (tokenId != 0 && _swapWeth && _amountToSwap > 0) {\n _ensureWETHBalance(_amountToSwap);\n }\n\n // in some cases we will just want to add liquidity and not issue a swap to move the\n // active trading position within the pool\n if (_amountToSwap > 0) {\n _swapToDesiredPosition(_amountToSwap, _swapWeth, _minTokenReceived);\n }\n // calling check liquidity early so we don't get unexpected errors when adding liquidity\n // in the later stages of this function\n _checkForExpectedPoolPrice(true);\n\n _addLiquidity();\n\n // this call shouldn't be necessary, since adding liquidity shouldn't affect the active\n // trading price. It is a defensive programming measure.\n (, uint256 _wethSharePct) = _checkForExpectedPoolPrice(true);\n\n // revert if protocol insolvent\n _solvencyAssert();\n\n emit PoolRebalanced(_wethSharePct);\n }\n\n /**\n * Checks that the protocol is solvent, protecting from a rogue Strategist / Guardian that can\n * keep rebalancing the pool in both directions making the protocol lose a tiny amount of\n * funds each time.\n *\n * Protocol must be at least SOLVENCY_THRESHOLD (99,8 %) backed in order for the rebalances to\n * function.\n */\n function _solvencyAssert() internal view {\n uint256 _totalVaultValue = IVault(vaultAddress).totalValue();\n uint256 _totalOethbSupply = IERC20(OETHb).totalSupply();\n\n if (\n _totalVaultValue.divPrecisely(_totalOethbSupply) <\n SOLVENCY_THRESHOLD\n ) {\n revert(\"Protocol insolvent\");\n }\n }\n\n /**\n * @dev Decrease partial or all liquidity from the pool.\n * @param _liquidityToDecrease The amount of liquidity to remove expressed in 18 decimal point\n */\n function _removeLiquidity(uint256 _liquidityToDecrease)\n internal\n gaugeUnstakeAndRestake\n {\n require(_liquidityToDecrease > 0, \"Must remove some liquidity\");\n\n uint128 _liquidity = _getLiquidity();\n // need to convert to uint256 since intermittent result is to big for uint128 to handle\n uint128 _liquidityToRemove = uint256(_liquidity)\n .mulTruncate(_liquidityToDecrease)\n .toUint128();\n\n /**\n * There is no liquidity to remove -> exit function early. This can happen after a\n * withdraw/withdrawAll removes all of the liquidity while retaining the NFT token.\n */\n if (_liquidity == 0 || _liquidityToRemove == 0) {\n return;\n }\n\n (uint256 _amountWeth, uint256 _amountOethb) = positionManager\n .decreaseLiquidity(\n // Both expected amounts can be 0 since we don't really care if any swaps\n // happen just before the liquidity removal.\n INonfungiblePositionManager.DecreaseLiquidityParams({\n tokenId: tokenId,\n liquidity: _liquidityToRemove,\n amount0Min: 0,\n amount1Min: 0,\n deadline: block.timestamp\n })\n );\n\n (\n uint256 _amountWethCollected,\n uint256 _amountOethbCollected\n ) = positionManager.collect(\n INonfungiblePositionManager.CollectParams({\n tokenId: tokenId,\n recipient: address(this),\n amount0Max: type(uint128).max, // defaults to all tokens owed\n amount1Max: type(uint128).max // defaults to all tokens owed\n })\n );\n\n _updateUnderlyingAssets();\n\n emit LiquidityRemoved(\n _liquidityToDecrease,\n _amountWeth, //removedWethAmount\n _amountOethb, //removedOethbAmount\n _amountWethCollected,\n _amountOethbCollected,\n underlyingAssets\n );\n\n _burnOethbOnTheContract();\n }\n\n /**\n * @dev Perform a swap so that after the swap the ticker has the desired WETH to OETHb token share.\n */\n function _swapToDesiredPosition(\n uint256 _amountToSwap,\n bool _swapWeth,\n uint256 _minTokenReceived\n ) internal {\n IERC20 _tokenToSwap = IERC20(_swapWeth ? WETH : OETHb);\n uint256 _balance = _tokenToSwap.balanceOf(address(this));\n\n if (_balance < _amountToSwap) {\n // This should never trigger since _ensureWETHBalance will already\n // throw an error if there is not enough WETH\n if (_swapWeth) {\n revert NotEnoughWethForSwap(_balance, _amountToSwap);\n }\n // if swapping OETHb\n uint256 mintForSwap = _amountToSwap - _balance;\n IVault(vaultAddress).mintForStrategy(mintForSwap);\n }\n\n // approve the specific amount of WETH required\n if (_swapWeth) {\n IERC20(WETH).approve(address(swapRouter), _amountToSwap);\n }\n\n // Swap it\n swapRouter.exactInputSingle(\n // sqrtPriceLimitX96 is just a rough sanity check that we are within 0 -> 1 tick\n // a more fine check is performed in _checkForExpectedPoolPrice\n // Note: this needs further work if we want to generalize this approach\n ISwapRouter.ExactInputSingleParams({\n tokenIn: address(_tokenToSwap),\n tokenOut: _swapWeth ? OETHb : WETH,\n tickSpacing: tickSpacing, // set to 1\n recipient: address(this),\n deadline: block.timestamp,\n amountIn: _amountToSwap,\n amountOutMinimum: _minTokenReceived, // slippage check\n sqrtPriceLimitX96: _swapWeth\n ? sqrtRatioX96TickLower\n : sqrtRatioX96TickHigher\n })\n );\n\n /**\n * In the interest of each function in _rebalance to leave the contract state as\n * clean as possible the OETHb tokens here are burned. This decreases the\n * dependence where `_swapToDesiredPosition` function relies on later functions\n * (`addLiquidity`) to burn the OETHb. Reducing the risk of error introduction.\n */\n _burnOethbOnTheContract();\n }\n\n /**\n * @dev Add liquidity into the pool in the pre-configured WETH to OETHb share ratios\n * defined by the allowedPoolWethShareStart|End interval. This function will respect\n * liquidity ratios when there is no liquidity yet in the pool. If liquidity is already\n * present then it relies on the `_swapToDesiredPosition` function in a step before\n * to already move the trading price to desired position (with some tolerance).\n */\n // rebalance already has re-entrency checks\n // slither-disable-start reentrancy-no-eth\n function _addLiquidity() internal gaugeUnstakeAndRestake {\n uint256 _wethBalance = IERC20(WETH).balanceOf(address(this));\n uint256 _oethbBalance = IERC20(OETHb).balanceOf(address(this));\n // don't deposit small liquidity amounts\n if (_wethBalance <= 1e12) {\n return;\n }\n\n uint160 _currentPrice = getPoolX96Price();\n /**\n * Sanity check active trading price is positioned within our desired tick.\n *\n * We revert when price is equal to the lower tick even though that is still\n * a valid amount in regards to ticker position by Sugar.estimateAmount call.\n * Current price equaling tick bound at the 1:1 price parity results in\n * uint overfow when calculating the OETHb balance to deposit.\n */\n if (\n _currentPrice <= sqrtRatioX96TickLower ||\n _currentPrice >= sqrtRatioX96TickHigher\n ) {\n revert OutsideExpectedTickRange(getCurrentTradingTick());\n }\n\n /**\n * If estimateAmount1 call fails it could be due to _currentPrice being really\n * close to a tick and amount1 is a larger number than the sugar helper is able\n * to compute.\n *\n * If token addresses were reversed estimateAmount0 would be required here\n */\n uint256 _oethbRequired = helper.estimateAmount1(\n _wethBalance,\n address(0), // no need to pass pool address when current price is specified\n _currentPrice,\n lowerTick,\n upperTick\n );\n\n if (_oethbRequired > _oethbBalance) {\n IVault(vaultAddress).mintForStrategy(\n _oethbRequired - _oethbBalance\n );\n }\n\n // approve the specific amount of WETH required\n IERC20(WETH).approve(address(positionManager), _wethBalance);\n\n uint256 _wethAmountSupplied;\n uint256 _oethbAmountSupplied;\n if (tokenId == 0) {\n (\n tokenId,\n ,\n _wethAmountSupplied,\n _oethbAmountSupplied\n ) = positionManager.mint(\n /** amount0Min & amount1Min are left at 0 because slippage protection is ensured by the\n * _checkForExpectedPoolPrice\n *›\n * Also sqrtPriceX96 is 0 because the pool is already created\n * non zero amount attempts to create a new instance of the pool\n */\n INonfungiblePositionManager.MintParams({\n token0: WETH,\n token1: OETHb,\n tickSpacing: tickSpacing,\n tickLower: lowerTick,\n tickUpper: upperTick,\n amount0Desired: _wethBalance,\n amount1Desired: _oethbRequired,\n amount0Min: 0,\n amount1Min: 0,\n recipient: address(this),\n deadline: block.timestamp,\n sqrtPriceX96: 0\n })\n );\n } else {\n (, _wethAmountSupplied, _oethbAmountSupplied) = positionManager\n .increaseLiquidity(\n /** amount0Min & amount1Min are left at 0 because slippage protection is ensured by the\n * _checkForExpectedPoolPrice\n */\n INonfungiblePositionManager.IncreaseLiquidityParams({\n tokenId: tokenId,\n amount0Desired: _wethBalance,\n amount1Desired: _oethbRequired,\n amount0Min: 0,\n amount1Min: 0,\n deadline: block.timestamp\n })\n );\n }\n\n _updateUnderlyingAssets();\n emit LiquidityAdded(\n _wethBalance, // wethAmountDesired\n _oethbRequired, // oethbAmountDesired\n _wethAmountSupplied, // wethAmountSupplied\n _oethbAmountSupplied, // oethbAmountSupplied\n tokenId, // tokenId\n underlyingAssets\n );\n\n // burn remaining OETHb\n _burnOethbOnTheContract();\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /**\n * @dev Check that the Aerodrome pool price is within the expected\n * parameters.\n * This function works whether the strategy contract has liquidity\n * position in the pool or not. The function returns _wethSharePct\n * as a gas optimization measure.\n * @param throwException when set to true the function throws an exception\n * when pool's price is not within expected range.\n * @return _isExpectedRange Bool expressing price is within expected range\n * @return _wethSharePct Share of WETH owned by this strategy contract in the\n * configured ticker.\n */\n function _checkForExpectedPoolPrice(bool throwException)\n internal\n view\n returns (bool _isExpectedRange, uint256 _wethSharePct)\n {\n require(\n allowedWethShareStart != 0 && allowedWethShareEnd != 0,\n \"Weth share interval not set\"\n );\n\n uint160 _currentPrice = getPoolX96Price();\n\n /**\n * First check we are in expected tick range\n *\n * We revert even though price being equal to the lower tick would still\n * count being within lower tick for the purpose of Sugar.estimateAmount calls\n */\n if (\n _currentPrice <= sqrtRatioX96TickLower ||\n _currentPrice >= sqrtRatioX96TickHigher\n ) {\n if (throwException) {\n revert OutsideExpectedTickRange(getCurrentTradingTick());\n }\n return (false, 0);\n }\n\n // 18 decimal number expressed WETH tick share\n _wethSharePct = _getWethShare(_currentPrice);\n\n if (\n _wethSharePct < allowedWethShareStart ||\n _wethSharePct > allowedWethShareEnd\n ) {\n if (throwException) {\n revert PoolRebalanceOutOfBounds(\n _wethSharePct,\n allowedWethShareStart,\n allowedWethShareEnd\n );\n }\n return (false, _wethSharePct);\n }\n\n return (true, _wethSharePct);\n }\n\n /**\n * Burns any OETHb tokens remaining on the strategy contract\n */\n function _burnOethbOnTheContract() internal {\n uint256 _oethbBalance = IERC20(OETHb).balanceOf(address(this));\n if (_oethbBalance > 1e12) {\n IVault(vaultAddress).burnForStrategy(_oethbBalance);\n }\n }\n\n /// @dev This function assumes there are no uncollected tokens in the clPool owned by the strategy contract.\n /// For that reason any liquidity withdrawals must also collect the tokens.\n function _updateUnderlyingAssets() internal {\n if (tokenId == 0) {\n underlyingAssets = 0;\n emit UnderlyingAssetsUpdated(underlyingAssets);\n return;\n }\n\n uint128 _liquidity = _getLiquidity();\n\n /**\n * Our net value represent the smallest amount of tokens we are able to extract from the position\n * given our liquidity.\n *\n * The least amount of tokens extraditable from the position is where the active trading price is\n * at the ticker 0 meaning the pool is offering 1:1 trades between WETH & OETHb. At that moment the pool\n * consists completely of OETHb and no WETH.\n *\n * The more swaps from WETH -> OETHb happen on the pool the more the price starts to move towards the -1\n * ticker making OETHb (priced in WETH) more expensive.\n *\n * An additional note: when liquidity is 0 then the helper returns 0 for both token amounts. And the\n * function set underlying assets to 0.\n */\n (uint256 _wethAmount, uint256 _oethbAmount) = helper\n .getAmountsForLiquidity(\n sqrtRatioX96TickClosestToParity, // sqrtRatioX96\n sqrtRatioX96TickLower, // sqrtRatioAX96\n sqrtRatioX96TickHigher, // sqrtRatioBX96\n _liquidity\n );\n\n require(_wethAmount == 0, \"Non zero wethAmount\");\n underlyingAssets = _oethbAmount;\n emit UnderlyingAssetsUpdated(underlyingAssets);\n }\n\n /**\n * @dev This function removes the appropriate amount of liquidity to assure that the required\n * amount of WETH is available on the contract\n *\n * @param _amount WETH balance required on the contract\n */\n function _ensureWETHBalance(uint256 _amount) internal {\n uint256 _wethBalance = IERC20(WETH).balanceOf(address(this));\n if (_wethBalance >= _amount) {\n return;\n }\n\n require(tokenId != 0, \"No liquidity available\");\n uint256 _additionalWethRequired = _amount - _wethBalance;\n (uint256 _wethInThePool, ) = getPositionPrincipal();\n\n if (_wethInThePool < _additionalWethRequired) {\n revert NotEnoughWethLiquidity(\n _wethInThePool,\n _additionalWethRequired\n );\n }\n\n uint256 shareOfWethToRemove = Math.min(\n _additionalWethRequired.divPrecisely(_wethInThePool) + 1,\n 1e18\n );\n _removeLiquidity(shareOfWethToRemove);\n }\n\n /**\n * @notice Withdraw an `amount` of assets from the platform and\n * send to the `_recipient`.\n * @param _recipient Address to which the asset should be sent\n * @param _asset WETH address\n * @param _amount Amount of WETH to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_asset == WETH, \"Unsupported asset\");\n require(_recipient == vaultAddress, \"Only withdraw to vault allowed\");\n\n _ensureWETHBalance(_amount);\n\n _withdraw(_recipient, _amount);\n }\n\n /**\n * @notice Withdraw WETH and sends it to the Vault.\n */\n function withdrawAll() external override onlyVault nonReentrant {\n if (tokenId != 0) {\n _removeLiquidity(1e18);\n }\n\n uint256 _balance = IERC20(WETH).balanceOf(address(this));\n if (_balance > 0) {\n _withdraw(vaultAddress, _balance);\n }\n }\n\n function _withdraw(address _recipient, uint256 _amount) internal {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient == vaultAddress, \"Only withdraw to vault allowed\");\n\n IERC20(WETH).safeTransfer(_recipient, _amount);\n emit Withdrawal(WETH, address(0), _amount);\n }\n\n /**\n * @dev Collect the AERO token from the gauge\n */\n function _collectRewardTokens() internal override {\n if (tokenId != 0 && _isLpTokenStakedInGauge()) {\n clGauge.getReward(tokenId);\n }\n super._collectRewardTokens();\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == WETH;\n }\n\n /**\n * @dev Approve the spending of all assets\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n // to add liquidity to the clPool\n IERC20(OETHb).approve(address(positionManager), type(uint256).max);\n // to be able to rebalance using the swapRouter\n IERC20(OETHb).approve(address(swapRouter), type(uint256).max);\n\n /* the behaviour of this strategy has slightly changed and WETH could be\n * present on the contract between the transactions. For that reason we are\n * un-approving WETH to the swapRouter & positionManager and only approving\n * the required amount before a transaction\n */\n IERC20(WETH).approve(address(swapRouter), 0);\n IERC20(WETH).approve(address(positionManager), 0);\n }\n\n /***************************************\n Balances and Fees\n ****************************************/\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256)\n {\n require(_asset == WETH, \"Only WETH supported\");\n\n // we could in theory deposit to the strategy and forget to call rebalance in the same\n // governance transaction batch. In that case the WETH that is on the strategy contract\n // also needs to be accounted for.\n uint256 _wethBalance = IERC20(WETH).balanceOf(address(this));\n // just paranoia check, in case there is OETHb in the strategy that for some reason hasn't\n // been burned yet.\n uint256 _oethbBalance = IERC20(OETHb).balanceOf(address(this));\n return underlyingAssets + _wethBalance + _oethbBalance;\n }\n\n /**\n * @dev Returns the balance of both tokens in a given position (excluding fees)\n * @return _amountWeth Amount of WETH in position\n * @return _amountOethb Amount of OETHb in position\n */\n function getPositionPrincipal()\n public\n view\n returns (uint256 _amountWeth, uint256 _amountOethb)\n {\n if (tokenId == 0) {\n return (0, 0);\n }\n\n uint160 _sqrtRatioX96 = getPoolX96Price();\n (_amountWeth, _amountOethb) = helper.principal(\n positionManager,\n tokenId,\n _sqrtRatioX96\n );\n }\n\n /**\n * @notice Returns the current pool price in X96 format\n * @return _sqrtRatioX96 Pool price\n */\n function getPoolX96Price() public view returns (uint160 _sqrtRatioX96) {\n (_sqrtRatioX96, , , , , ) = clPool.slot0();\n }\n\n /**\n * @notice Returns the current active trading tick of the underlying pool\n * @return _currentTick Current pool trading tick\n */\n function getCurrentTradingTick() public view returns (int24 _currentTick) {\n (, _currentTick, , , , ) = clPool.slot0();\n }\n\n /**\n * @notice Returns the percentage of WETH liquidity in the configured ticker\n * owned by this strategy contract.\n * @return uint256 1e18 denominated percentage expressing the share\n */\n function getWETHShare() external view returns (uint256) {\n uint160 _currentPrice = getPoolX96Price();\n return _getWethShare(_currentPrice);\n }\n\n /**\n * @notice Returns the amount of liquidity in the contract's LP position\n * @return _liquidity Amount of liquidity in the position\n */\n function _getLiquidity() internal view returns (uint128 _liquidity) {\n if (tokenId == 0) {\n revert(\"No LP position\");\n }\n\n (, , , , , , , _liquidity, , , , ) = positionManager.positions(tokenId);\n }\n\n function _getWethShare(uint160 _currentPrice)\n internal\n view\n returns (uint256)\n {\n /**\n * If estimateAmount1 call fails it could be due to _currentPrice being really\n * close to a tick and amount1 too big to compute.\n *\n * If token addresses were reversed estimateAmount0 would be required here\n */\n uint256 _normalizedWethAmount = 1 ether;\n uint256 _correspondingOethAmount = helper.estimateAmount1(\n _normalizedWethAmount,\n address(0), // no need to pass pool address when current price is specified\n _currentPrice,\n lowerTick,\n upperTick\n );\n\n // 18 decimal number expressed weth tick share\n return\n _normalizedWethAmount.divPrecisely(\n _normalizedWethAmount + _correspondingOethAmount\n );\n }\n\n /***************************************\n Hidden functions\n ****************************************/\n /// @inheritdoc InitializableAbstractStrategy\n function setPTokenAddress(address, address) external override {\n // The pool tokens can never change.\n revert(\"Unsupported method\");\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function removePToken(uint256) external override {\n // The pool tokens can never change.\n revert(\"Unsupported method\");\n }\n\n /**\n * @dev Not supported\n */\n function _abstractSetPToken(address, address) internal override {\n // the deployer shall call safeApproveAllTokens() to set necessary approvals\n revert(\"Unsupported method\");\n }\n\n /***************************************\n ERC721 management\n ****************************************/\n\n /// @notice Callback function for whenever a NFT is transferred to this contract\n // solhint-disable-next-line max-line-length\n /// Ref: https://docs.openzeppelin.com/contracts/3.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-\n function onERC721Received(\n address,\n address,\n uint256,\n bytes calldata\n ) external returns (bytes4) {\n return this.onERC721Received.selector;\n }\n}\n" + }, + "contracts/strategies/algebra/OETHSupernovaAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Supernova OETH Algorithmic Market Maker (AMO) Strategy\n * @notice AMO strategy for the Supernova OETH/WETH stable pool\n * @author Origin Protocol Inc\n */\nimport { StableSwapAMMStrategy } from \"./StableSwapAMMStrategy.sol\";\nimport { IGauge } from \"../../interfaces/algebra/IAlgebraGauge.sol\";\n\ncontract OETHSupernovaAMOStrategy is StableSwapAMMStrategy {\n /**\n * @param _baseConfig The `platformAddress` is the address of the Supernova OETH/WETH pool.\n * The `vaultAddress` is the address of the OETH Vault.\n * @param _gauge Address of the Supernova gauge for the pool.\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _gauge)\n StableSwapAMMStrategy(_baseConfig, _gauge, IGauge(_gauge).TOKEN())\n {}\n}\n" + }, + "contracts/strategies/algebra/StableSwapAMMStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Algebra Algorithmic Market Maker (AMO) Strategy\n * @notice AMO strategy for the Algebra stable swap pool\n * @author Origin Protocol Inc\n */\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\nimport { sqrt } from \"../../utils/PRBMath.sol\";\nimport { IBasicToken } from \"../../interfaces/IBasicToken.sol\";\nimport { IPair } from \"../../interfaces/algebra/IAlgebraPair.sol\";\nimport { IGauge } from \"../../interfaces/algebra/IAlgebraGauge.sol\";\nimport { IVault } from \"../../interfaces/IVault.sol\";\n\ncontract StableSwapAMMStrategy is InitializableAbstractStrategy {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n using SafeCast for uint256;\n\n /**\n * @notice a threshold under which the contract no longer allows for the protocol to manually rebalance.\n * Guarding against a strategist / guardian being taken over and with multiple transactions\n * draining the protocol funds.\n */\n uint256 public constant SOLVENCY_THRESHOLD = 0.998 ether;\n\n /// @notice Precision for the Algebra Stable AMM (sAMM) invariant k.\n uint256 public constant PRECISION = 1e18;\n\n /// @notice Address of the asset (non OToken) token contract\n address public immutable asset;\n\n /// @notice Address of the OToken token contract.\n address public immutable oToken;\n\n /// @notice Address of the Algebra Stable pool contract.\n address public immutable pool;\n\n /// @notice Address of the Algebra Gauge contract.\n address public immutable gauge;\n\n /// @notice Index of the OToken in the Algebra pool.\n uint256 public immutable oTokenPoolIndex;\n\n /// @notice The max amount the OToken/asset price can deviate from peg (1e18)\n /// before deposits are reverted scaled to 18 decimals.\n /// eg 0.01e18 or 1e16 is 1% which is 100 basis points.\n /// This is the amount below and above peg so a 50 basis point deviation (0.005e18)\n /// allows a price range from 0.995 to 1.005.\n uint256 public maxDepeg;\n\n event SwapOTokensToPool(\n uint256 oTokenMinted,\n uint256 assetDepositAmount,\n uint256 oTokenDepositAmount,\n uint256 lpTokens\n );\n event SwapAssetsToPool(\n uint256 assetSwapped,\n uint256 lpTokens,\n uint256 oTokenBurnt\n );\n event MaxDepegUpdated(uint256 maxDepeg);\n\n /**\n * @dev Verifies that the caller is the Strategist of the Vault.\n */\n modifier onlyStrategist() {\n require(\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n _;\n }\n\n /**\n * @dev Skim the Algebra pool in case any extra asset or OToken tokens were added\n */\n modifier skimPool() {\n IPair(pool).skim(address(this));\n _;\n }\n\n /**\n * @dev Checks the pool is balanced enough to allow deposits.\n */\n modifier nearBalancedPool() {\n // OToken/asset price = asset / OToken\n // Get the OToken/asset price for selling 1 OToken for asset\n // As OToken is 1, the asset amount is the OToken/asset price\n uint256 sellPrice = IPair(pool).getAmountOut(1e18, oToken);\n\n // Get the amount of OToken received from selling 1 asset. This is buying OToken.\n uint256 oTokenAmount = IPair(pool).getAmountOut(1e18, asset);\n\n // If the pool is degenerate, then the pool is not valid and we can't deposit.\n require(oTokenAmount > 0, \"Pool degenerate\");\n\n // Convert to a OToken/asset price = asset / OToken\n uint256 buyPrice = 1e36 / oTokenAmount;\n\n uint256 pegPrice = 1e18;\n\n require(\n sellPrice >= pegPrice - maxDepeg && buyPrice <= pegPrice + maxDepeg,\n \"price out of range\"\n );\n _;\n }\n\n /**\n * @dev Checks the pool's balances have improved and the balances\n * have not tipped to the other side.\n * This modifier is only applied to functions that do swaps against the pool.\n * Deposits and withdrawals are proportional to the pool's balances hence don't need this check.\n */\n modifier improvePoolBalance() {\n // Get the asset and OToken balances in the pool\n (\n uint256 assetReserveBefore,\n uint256 oTokenReserveBefore\n ) = _getPoolReserves();\n // diff = asset balance - OToken balance\n int256 diffBefore = assetReserveBefore.toInt256() -\n oTokenReserveBefore.toInt256();\n\n _;\n\n // Get the asset and OToken balances in the pool\n (\n uint256 assetReserveAfter,\n uint256 oTokenReserveAfter\n ) = _getPoolReserves();\n // diff = asset balance - OToken balance\n int256 diffAfter = assetReserveAfter.toInt256() -\n oTokenReserveAfter.toInt256();\n\n if (diffBefore == 0) {\n require(diffAfter == 0, \"Position balance is worsened\");\n } else if (diffBefore < 0) {\n // If the pool was originally imbalanced in favor of OToken, then\n // we want to check that the pool is now more balanced\n require(diffAfter <= 0, \"Assets overshot peg\");\n require(diffBefore < diffAfter, \"OTokens balance worse\");\n } else if (diffBefore > 0) {\n // If the pool was originally imbalanced in favor of asset, then\n // we want to check that the pool is now more balanced\n require(diffAfter >= 0, \"OTokens overshot peg\");\n require(diffAfter < diffBefore, \"Assets balance worse\");\n }\n }\n\n /**\n * @param _baseConfig The `platformAddress` is the address of the Algebra pool.\n * The `vaultAddress` is the address of the Origin Vault.\n * @param _gauge Address of the Algebra gauge for the pool.\n * @param _gaugeStakeToken The pool LP token address as reported by the\n * gauge. The inheriting contract is expected to resolve this via\n * whichever getter its gauge exposes (e.g. `IGauge.TOKEN()` for\n * legacy GaugeV2 ≤ v2.4 or `IHydrexGauge.stakeToken()` for\n * Hydrex GaugeV2 ≥ v2.5) and pass the result here. The constructor\n * verifies it matches `_baseConfig.platformAddress`.\n */\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _gauge,\n address _gaugeStakeToken\n ) InitializableAbstractStrategy(_baseConfig) {\n // Read the oToken address from the Vault\n address oTokenMem = IVault(_baseConfig.vaultAddress).oToken();\n address assetMem = IVault(_baseConfig.vaultAddress).asset();\n\n // Checked both tokens are to 18 decimals\n require(\n IBasicToken(assetMem).decimals() == 18 &&\n IBasicToken(oTokenMem).decimals() == 18,\n \"Incorrect token decimals\"\n );\n // Check the Algebra pool is a Stable AMM (sAMM)\n require(\n IPair(_baseConfig.platformAddress).isStable() == true,\n \"Pool not stable\"\n );\n // Check the gauge is wired to the expected pool LP token. The\n // inheriting contract is responsible for fetching `_gaugeStakeToken`\n // from whichever getter the underlying gauge variant exposes.\n require(\n _gaugeStakeToken == _baseConfig.platformAddress,\n \"Incorrect gauge\"\n );\n oTokenPoolIndex = IPair(_baseConfig.platformAddress).token0() ==\n oTokenMem\n ? 0\n : 1;\n // Check the pool tokens are correct\n require(\n IPair(_baseConfig.platformAddress).token0() ==\n (oTokenPoolIndex == 0 ? oTokenMem : assetMem) &&\n IPair(_baseConfig.platformAddress).token1() ==\n (oTokenPoolIndex == 0 ? assetMem : oTokenMem),\n \"Incorrect pool tokens\"\n );\n\n // Set the immutable variables\n oToken = oTokenMem;\n asset = assetMem;\n pool = _baseConfig.platformAddress;\n gauge = _gauge;\n\n // This is an implementation contract. The governor is set in the proxy contract.\n _setGovernor(address(0));\n }\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Algebra strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Array containing SWPx token address\n * @param _maxDepeg The max amount the OToken/asset price can deviate from peg (1e18) before deposits are reverted.\n */\n function initialize(\n address[] calldata _rewardTokenAddresses,\n uint256 _maxDepeg\n ) external onlyGovernor initializer {\n address[] memory pTokens = new address[](1);\n pTokens[0] = pool;\n\n address[] memory _assets = new address[](1);\n _assets[0] = asset;\n\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n pTokens\n );\n\n maxDepeg = _maxDepeg;\n\n _approveBase();\n }\n\n /***************************************\n Deposit\n ****************************************/\n\n /**\n * @notice Deposit an amount of asset into the Algebra pool.\n * Mint OToken in proportion to the pool's asset and OToken reserves,\n * transfer asset and OToken to the pool,\n * mint the pool's LP token and deposit in the gauge.\n * @dev This tx must be wrapped by the VaultValueChecker.\n * To minimize loses, the pool should be rebalanced before depositing.\n * The pool's oToken/asset price must be within the maxDepeg range.\n * @param _asset Address of asset token.\n * @param _assetAmount Amount of asset tokens to deposit.\n */\n function deposit(address _asset, uint256 _assetAmount)\n external\n override\n onlyVault\n nonReentrant\n skimPool\n nearBalancedPool\n {\n require(_asset == asset, \"Unsupported asset\");\n require(_assetAmount > 0, \"Must deposit something\");\n\n (uint256 oTokenDepositAmount, ) = _deposit(_assetAmount);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n // Emit event for the deposited asset tokens\n emit Deposit(asset, pool, _assetAmount);\n // Emit event for the minted OToken tokens\n emit Deposit(oToken, pool, oTokenDepositAmount);\n }\n\n /**\n * @notice Deposit all the strategy's asset tokens into the Algebra pool.\n * Mint OToken in proportion to the pool's asset and OToken reserves,\n * transfer asset and OToken to the pool,\n * mint the pool's LP token and deposit in the gauge.\n * @dev This tx must be wrapped by the VaultValueChecker.\n * To minimize loses, the pool should be rebalanced before depositing.\n * The pool's oToken/asset price must be within the maxDepeg range.\n */\n function depositAll()\n external\n override\n onlyVault\n nonReentrant\n skimPool\n nearBalancedPool\n {\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\n if (assetBalance > 0) {\n (uint256 oTokenDepositAmount, ) = _deposit(assetBalance);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n // Emit event for the deposited asset tokens\n emit Deposit(asset, pool, assetBalance);\n // Emit event for the minted OToken tokens\n emit Deposit(oToken, pool, oTokenDepositAmount);\n }\n }\n\n /**\n * @dev Mint OToken in proportion to the pool's asset and OToken reserves,\n * transfer asset and OToken to the pool,\n * mint the pool's LP token and deposit in the gauge.\n * @param _assetAmount Amount of asset tokens to deposit.\n * @return oTokenDepositAmount Amount of OToken tokens minted and deposited into the pool.\n * @return lpTokens Amount of Algebra pool LP tokens minted and deposited into the gauge.\n */\n function _deposit(uint256 _assetAmount)\n internal\n returns (uint256 oTokenDepositAmount, uint256 lpTokens)\n {\n // Calculate the required amount of OToken to mint based on the asset amount.\n oTokenDepositAmount = _calcTokensToMint(_assetAmount);\n\n // Mint the required OToken tokens to this strategy\n IVault(vaultAddress).mintForStrategy(oTokenDepositAmount);\n\n // Add asset and OToken liquidity to the pool and stake in gauge\n lpTokens = _depositToPoolAndGauge(_assetAmount, oTokenDepositAmount);\n }\n\n /***************************************\n Withdraw\n ****************************************/\n\n /**\n * @notice Withdraw asset and OToken from the Algebra pool, burn the OToken,\n * and transfer the asset to the recipient.\n * @param _recipient Address of the Vault.\n * @param _asset Address of the asset token.\n * @param _assetAmount Amount of asset tokens to withdraw.\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _assetAmount\n ) external override onlyVault nonReentrant skimPool {\n require(_assetAmount > 0, \"Must withdraw something\");\n require(_asset == asset, \"Unsupported asset\");\n // This strategy can't be set as a default strategy for asset in the Vault.\n // This means the recipient must always be the Vault.\n require(_recipient == vaultAddress, \"Only withdraw to vault allowed\");\n\n // Calculate how much pool LP tokens to burn to get the required amount of asset tokens back\n uint256 lpTokens = _calcTokensToBurn(_assetAmount);\n\n // Withdraw pool LP tokens from the gauge and remove assets from from the pool\n _withdrawFromGaugeAndPool(lpTokens);\n\n // Burn all the removed OToken and any that was left in the strategy\n uint256 oTokenToBurn = IERC20(oToken).balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oTokenToBurn);\n\n // Transfer asset to the recipient\n // Note there can be a dust amount of asset left in the strategy as\n // the burn of the pool's LP tokens is rounded up\n require(\n IERC20(asset).balanceOf(address(this)) >= _assetAmount,\n \"Not enough asset removed\"\n );\n IERC20(asset).safeTransfer(_recipient, _assetAmount);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n // Emit event for the withdrawn asset tokens\n emit Withdrawal(asset, pool, _assetAmount);\n // Emit event for the burnt OToken tokens\n emit Withdrawal(oToken, pool, oTokenToBurn);\n }\n\n /**\n * @notice Withdraw all pool LP tokens from the gauge,\n * remove all asset and OToken from the Algebra pool,\n * burn all the OToken,\n * and transfer all the asset to the Vault contract.\n * @dev There is no solvency check here as withdrawAll can be called to\n * quickly secure assets to the Vault in emergencies.\n */\n function withdrawAll()\n external\n override\n onlyVaultOrGovernor\n nonReentrant\n skimPool\n {\n // Get all the pool LP tokens the strategy has staked in the gauge\n uint256 lpTokens = IGauge(gauge).balanceOf(address(this));\n // Can not withdraw zero LP tokens from the gauge\n if (lpTokens == 0) return;\n\n if (IGauge(gauge).emergency()) {\n // The gauge is in emergency mode\n _emergencyWithdrawFromGaugeAndPool();\n } else {\n // Withdraw pool LP tokens from the gauge and remove assets from from the pool\n _withdrawFromGaugeAndPool(lpTokens);\n }\n\n // Burn all OToken in this strategy contract\n uint256 oTokenToBurn = IERC20(oToken).balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oTokenToBurn);\n\n // Get the strategy contract's asset balance.\n // This includes all that was removed from the Algebra pool and\n // any that was sitting in the strategy contract before the removal.\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\n IERC20(asset).safeTransfer(vaultAddress, assetBalance);\n\n // Emit event for the withdrawn asset tokens\n emit Withdrawal(asset, pool, assetBalance);\n // Emit event for the burnt OToken tokens\n emit Withdrawal(oToken, pool, oTokenToBurn);\n }\n\n /***************************************\n Pool Rebalancing\n ****************************************/\n\n /** @notice Used when there is more OToken than asset in the pool.\n * asset and OToken is removed from the pool, the received asset is swapped for OToken\n * and the left over OToken in the strategy is burnt.\n * The OToken/asset price is < 1.0 so OToken is being bought at a discount.\n * @param _assetAmount Amount of asset tokens to swap into the pool.\n */\n function swapAssetsToPool(uint256 _assetAmount)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n skimPool\n {\n require(_assetAmount > 0, \"Must swap something\");\n\n // 1. Partially remove liquidity so there’s enough asset for the swap\n\n // Calculate how much pool LP tokens to burn to get the required amount of asset tokens back\n uint256 lpTokens = _calcTokensToBurn(_assetAmount);\n require(lpTokens > 0, \"No LP tokens to burn\");\n\n _withdrawFromGaugeAndPool(lpTokens);\n\n // 2. Swap asset for OToken against the pool\n // Swap exact amount of asset for OToken against the pool\n // There can be a dust amount of asset left in the strategy as the burn of the pool's LP tokens is rounded up\n _swapExactTokensForTokens(_assetAmount, asset, oToken);\n\n // 3. Burn all the OToken left in the strategy from the remove liquidity and swap\n uint256 oTokenToBurn = IERC20(oToken).balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oTokenToBurn);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n // Emit event for the burnt OToken tokens\n emit Withdrawal(oToken, pool, oTokenToBurn);\n // Emit event for the swap\n emit SwapAssetsToPool(_assetAmount, lpTokens, oTokenToBurn);\n }\n\n /**\n * @notice Used when there is more asset than OToken in the pool.\n * OToken is minted and swapped for asset against the pool,\n * more OToken is minted and added back into the pool with the swapped out asset.\n * The OToken/asset price is > 1.0 so OToken is being sold at a premium.\n * @param _oTokenAmount Amount of OToken to swap into the pool.\n */\n function swapOTokensToPool(uint256 _oTokenAmount)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n skimPool\n {\n require(_oTokenAmount > 0, \"Must swap something\");\n\n // 1. Mint OToken so it can be swapped into the pool\n\n // There can be OToken in the strategy from skimming the pool\n uint256 oTokenInStrategy = IERC20(oToken).balanceOf(address(this));\n require(\n _oTokenAmount >= oTokenInStrategy,\n \"Too much OToken in strategy\"\n );\n uint256 oTokenToMint = _oTokenAmount - oTokenInStrategy;\n\n // Mint the required OToken tokens to this strategy\n IVault(vaultAddress).mintForStrategy(oTokenToMint);\n\n // 2. Swap OToken for asset against the pool\n _swapExactTokensForTokens(_oTokenAmount, oToken, asset);\n\n // The asset is from the swap and any asset that was sitting in the strategy\n uint256 assetDepositAmount = IERC20(asset).balanceOf(address(this));\n\n // 3. Add asset and OToken back to the pool in proportion to the pool's reserves\n (uint256 oTokenDepositAmount, uint256 lpTokens) = _deposit(\n assetDepositAmount\n );\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n // Emit event for the minted OToken tokens\n emit Deposit(oToken, pool, oTokenToMint + oTokenDepositAmount);\n // Emit event for the swap\n emit SwapOTokensToPool(\n oTokenToMint,\n assetDepositAmount,\n oTokenDepositAmount,\n lpTokens\n );\n }\n\n /***************************************\n Assets and Rewards\n ****************************************/\n\n /**\n * @notice Get the asset value of assets in the strategy and Algebra pool.\n * The value of the assets in the pool is calculated assuming the pool is balanced.\n * This way the value can not be manipulated by changing the pool's token balances.\n * @param _asset Address of the asset token\n * @return balance Total value in asset.\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == asset, \"Unsupported asset\");\n\n // asset balance needed here for the balance check that happens from vault during depositing.\n balance = IERC20(asset).balanceOf(address(this));\n\n // This assumes 1 gauge LP token = 1 pool LP token\n uint256 lpTokens = IGauge(gauge).balanceOf(address(this));\n if (lpTokens == 0) return balance;\n\n // Add the strategy’s share of the asset and OToken tokens in the Algebra pool if the pool was balanced.\n balance += _lpValue(lpTokens);\n }\n\n /**\n * @notice Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == asset;\n }\n\n /**\n * @notice Collect accumulated SWPx (and other) rewards and send to the Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvesterOrStrategist\n nonReentrant\n {\n // Collect SWPx rewards from the gauge\n IGauge(gauge).getReward();\n\n _collectRewardTokens();\n }\n\n /***************************************\n Internal Algebra Pool and Gauge Functions\n ****************************************/\n\n /**\n * @dev Calculate the required amount of OToken to mint based on the asset amount.\n * This ensures the proportion of OToken tokens being added to the pool matches the proportion of asset tokens.\n * For example, if the added asset tokens is 10% of existing asset tokens in the pool,\n * then the OToken tokens being added should also be 10% of the OToken tokens in the pool.\n * @param _assetAmount Amount of asset tokens to be added to the pool.\n * @return oTokenAmount Amount of OToken tokens to be minted and added to the pool.\n */\n function _calcTokensToMint(uint256 _assetAmount)\n internal\n view\n returns (uint256 oTokenAmount)\n {\n (uint256 assetReserves, uint256 oTokenReserves) = _getPoolReserves();\n require(assetReserves > 0, \"Empty pool\");\n\n // OToken to add = (asset being added * OToken in pool) / asset in pool\n oTokenAmount = (_assetAmount * oTokenReserves) / assetReserves;\n }\n\n /**\n * @dev Calculate how much pool LP tokens to burn to get the required amount of asset tokens back\n * from the pool.\n * @param _assetAmount Amount of asset tokens to be removed from the pool.\n * @return lpTokens Amount of Algebra pool LP tokens to burn.\n */\n function _calcTokensToBurn(uint256 _assetAmount)\n internal\n view\n returns (uint256 lpTokens)\n {\n /* The Algebra pool proportionally returns the reserve tokens when removing liquidity.\n * First, calculate the proportion of required asset tokens against the pools asset reserves.\n * That same proportion is used to calculate the required amount of pool LP tokens.\n * For example, if the required asset tokens is 10% of the pool's asset reserves,\n * then 10% of the pool's LP supply needs to be burned.\n *\n * Because we are doing balanced removal we should be making profit when removing liquidity in a\n * pool tilted to either side.\n *\n * Important: A downside is that the Strategist / Governor needs to be\n * cognizant of not removing too much liquidity. And while the proposal to remove liquidity\n * is being voted on, the pool tilt might change so much that the proposal that has been valid while\n * created is no longer valid.\n */\n\n (uint256 assetReserves, ) = _getPoolReserves();\n require(assetReserves > 0, \"Empty pool\");\n\n lpTokens = (_assetAmount * IPair(pool).totalSupply()) / assetReserves;\n lpTokens += 1; // Add 1 to ensure we get enough LP tokens with rounding\n }\n\n /**\n * @dev Deposit asset and OToken liquidity to the Algebra pool\n * and stake the pool's LP token in the gauge.\n * @param _assetAmount Amount of asset to deposit.\n * @param _oTokenAmount Amount of OToken to deposit.\n * @return lpTokens Amount of Algebra pool LP tokens minted.\n */\n function _depositToPoolAndGauge(uint256 _assetAmount, uint256 _oTokenAmount)\n internal\n returns (uint256 lpTokens)\n {\n // Transfer asset to the pool\n IERC20(asset).safeTransfer(pool, _assetAmount);\n // Transfer OToken to the pool\n IERC20(oToken).safeTransfer(pool, _oTokenAmount);\n\n // Mint LP tokens from the pool\n lpTokens = IPair(pool).mint(address(this));\n\n // Deposit the pool's LP tokens into the gauge\n IGauge(gauge).deposit(lpTokens);\n }\n\n /**\n * @dev Withdraw pool LP tokens from the gauge and remove asset and OToken from the pool.\n * @param _lpTokens Amount of Algebra pool LP tokens to withdraw from the gauge\n */\n function _withdrawFromGaugeAndPool(uint256 _lpTokens) internal {\n require(\n IGauge(gauge).balanceOf(address(this)) >= _lpTokens,\n \"Not enough LP tokens in gauge\"\n );\n\n // Withdraw pool LP tokens from the gauge\n IGauge(gauge).withdraw(_lpTokens);\n\n // Transfer the pool LP tokens to the pool\n IERC20(pool).safeTransfer(pool, _lpTokens);\n\n // Burn the LP tokens and transfer the asset and OToken back to the strategy\n IPair(pool).burn(address(this));\n }\n\n /**\n * @dev Withdraw all pool LP tokens from the gauge when it's in emergency mode\n * and remove asset and OToken from the pool.\n */\n function _emergencyWithdrawFromGaugeAndPool() internal {\n // Withdraw all pool LP tokens from the gauge\n IGauge(gauge).emergencyWithdraw();\n\n // Get the pool LP tokens in strategy\n uint256 _lpTokens = IERC20(pool).balanceOf(address(this));\n\n // Transfer the pool LP tokens to the pool\n IERC20(pool).safeTransfer(pool, _lpTokens);\n\n // Burn the LP tokens and transfer the asset and OToken back to the strategy\n IPair(pool).burn(address(this));\n }\n\n /**\n * @dev Swap exact amount of tokens for another token against the pool.\n * @param _amountIn Amount of tokens to swap into the pool.\n * @param _tokenIn Address of the token going into the pool.\n * @param _tokenOut Address of the token being swapped out of the pool.\n */\n function _swapExactTokensForTokens(\n uint256 _amountIn,\n address _tokenIn,\n address _tokenOut\n ) internal {\n // Calculate how much out tokens we get from the swap\n uint256 amountOut = IPair(pool).getAmountOut(_amountIn, _tokenIn);\n\n // Transfer in tokens to the pool after the amountOut calculation has been mde.\n // This way we don't have to worry about sending tokens to pool confusing the pool's reserves.\n IERC20(_tokenIn).safeTransfer(pool, _amountIn);\n\n // Safety check that we are dealing with the correct pool tokens\n require(\n (_tokenIn == asset && _tokenOut == oToken) ||\n (_tokenIn == oToken && _tokenOut == asset),\n \"Unsupported swap\"\n );\n\n uint256 amount0;\n uint256 amount1;\n\n // Work out the correct order of the amounts for the pool\n if (_tokenIn == asset) {\n if (oTokenPoolIndex == 0) {\n amount0 = amountOut;\n amount1 = 0;\n } else {\n amount0 = 0;\n amount1 = amountOut;\n }\n } else {\n if (oTokenPoolIndex == 0) {\n amount0 = 0;\n amount1 = amountOut;\n } else {\n amount0 = amountOut;\n amount1 = 0;\n }\n }\n\n // Perform the swap on the pool\n IPair(pool).swap(amount0, amount1, address(this), new bytes(0));\n\n // The slippage protection against the amount out is indirectly done\n // via the improvePoolBalance\n }\n\n /// @dev Calculate the value of a LP position in a Algebra stable pool\n /// if the pool was balanced.\n /// @param _lpTokens Amount of LP tokens in the Algebra pool\n /// @return value The asset value of the LP tokens when the pool is balanced\n function _lpValue(uint256 _lpTokens) internal view returns (uint256 value) {\n // Get total supply of LP tokens\n uint256 totalSupply = IPair(pool).totalSupply();\n if (totalSupply == 0) return 0;\n\n // Get the current reserves of the pool\n (uint256 assetReserves, uint256 oTokenReserves) = _getPoolReserves();\n\n // Calculate the invariant of the pool assuming both tokens have 18 decimals.\n // k is scaled to 18 decimals.\n uint256 k = _invariant(assetReserves, oTokenReserves);\n\n // If x = y, let’s denote x = y = z (where z is the common reserve value)\n // Substitute z into the invariant:\n // k = z^3 * z + z * z^3\n // k = 2 * z^4\n // Going back the other way to calculate the common reserve value z\n // z = (k / 2) ^ (1/4)\n // the total value of the pool when x = y is 2 * z, which is 2 * (k / 2) ^ (1/4)\n uint256 zSquared = sqrt((k * 1e18) / 2); // 18 + 18 = 36 decimals becomes 18 decimals after sqrt\n uint256 z = sqrt(zSquared * 1e18); // 18 + 18 = 36 decimals becomes 18 decimals after sqrt\n uint256 totalValueOfPool = 2 * z;\n\n // lp value = lp tokens * value of pool / total supply\n value = (_lpTokens * totalValueOfPool) / totalSupply;\n }\n\n /**\n * @dev Compute the invariant for a Algebra stable pool.\n * This assumed both x and y tokens are to 18 decimals which is checked in the constructor.\n * invariant: k = x^3 * y + x * y^3\n * @dev This implementation is copied from Algebra's Pair contract.\n * @param _x The amount of asset tokens in the pool\n * @param _y The amount of the OToken tokens in the pool\n * @return k The invariant of the Algebra stable pool\n */\n function _invariant(uint256 _x, uint256 _y)\n internal\n pure\n returns (uint256 k)\n {\n uint256 _a = (_x * _y) / PRECISION;\n uint256 _b = ((_x * _x) / PRECISION + (_y * _y) / PRECISION);\n // slither-disable-next-line divide-before-multiply\n k = (_a * _b) / PRECISION;\n }\n\n /**\n * @dev Checks that the protocol is solvent, protecting from a rogue Strategist / Guardian that can\n * keep rebalancing the pool in both directions making the protocol lose a tiny amount of\n * funds each time.\n *\n * Protocol must be at least SOLVENCY_THRESHOLD (99,8 %) backed in order for the rebalances to\n * function.\n */\n function _solvencyAssert() internal view {\n uint256 _totalVaultValue = IVault(vaultAddress).totalValue();\n uint256 _totalSupply = IERC20(oToken).totalSupply();\n\n if (\n _totalSupply > 0 &&\n _totalVaultValue.divPrecisely(_totalSupply) < SOLVENCY_THRESHOLD\n ) {\n revert(\"Protocol insolvent\");\n }\n }\n\n /**\n * @dev Get the reserves of the pool no matter the order of tokens in the underlying\n * Algebra pool.\n * @return assetReserves The reserves of the asset token in the pool.\n * @return oTokenReserves The reserves of the OToken token in the pool.\n */\n function _getPoolReserves()\n internal\n view\n returns (uint256 assetReserves, uint256 oTokenReserves)\n {\n (uint256 reserve0, uint256 reserve1, ) = IPair(pool).getReserves();\n assetReserves = oTokenPoolIndex == 0 ? reserve1 : reserve0;\n oTokenReserves = oTokenPoolIndex == 0 ? reserve0 : reserve1;\n }\n\n /***************************************\n Setters\n ****************************************/\n\n /**\n * @notice Set the maximum deviation from the OToken/asset peg (1e18) before deposits are reverted.\n * @param _maxDepeg the OToken/asset price from peg (1e18) in 18 decimals.\n * eg 0.01e18 or 1e16 is 1% which is 100 basis points.\n */\n function setMaxDepeg(uint256 _maxDepeg) external onlyGovernor {\n require(\n _maxDepeg >= 0.001 ether && _maxDepeg <= 0.1 ether,\n \"Invalid max depeg range\"\n );\n maxDepeg = _maxDepeg;\n\n emit MaxDepegUpdated(_maxDepeg);\n }\n\n /***************************************\n Approvals\n ****************************************/\n\n /**\n * @notice Approve the spending of all assets by their corresponding pool tokens,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n _approveBase();\n }\n\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {}\n\n function _approveBase() internal {\n // Approve Algebra gauge contract to transfer Algebra pool LP tokens\n // This is needed for deposits of Algebra pool LP tokens into the gauge.\n // slither-disable-next-line unused-return\n IPair(pool).approve(address(gauge), type(uint256).max);\n }\n}\n" + }, + "contracts/strategies/BaseCurveAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Curve Automated Market Maker (AMO) Strategy\n * @notice AMO strategy for the Curve OETH/WETH pool\n * @author Origin Protocol Inc\n */\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { ICurveStableSwapNG } from \"../interfaces/ICurveStableSwapNG.sol\";\nimport { ICurveXChainLiquidityGauge } from \"../interfaces/ICurveXChainLiquidityGauge.sol\";\nimport { IChildLiquidityGaugeFactory } from \"../interfaces/IChildLiquidityGaugeFactory.sol\";\n\ncontract BaseCurveAMOStrategy is InitializableAbstractStrategy {\n using StableMath for uint256;\n using SafeCast for uint256;\n\n /**\n * @dev a threshold under which the contract no longer allows for the protocol to manually rebalance.\n * Guarding against a strategist / guardian being taken over and with multiple transactions\n * draining the protocol funds.\n */\n uint256 public constant SOLVENCY_THRESHOLD = 0.998 ether;\n\n // New immutable variables that must be set in the constructor\n /**\n * @notice Address of the Wrapped ETH (WETH) contract.\n */\n IWETH9 public immutable weth;\n\n /**\n * @notice Address of the OETH token contract.\n */\n IERC20 public immutable oeth;\n\n /**\n * @notice Address of the LP (Liquidity Provider) token contract.\n */\n IERC20 public immutable lpToken;\n\n /**\n * @notice Address of the Curve StableSwap NG pool contract.\n */\n ICurveStableSwapNG public immutable curvePool;\n\n /**\n * @notice Address of the Curve X-Chain Liquidity Gauge contract.\n */\n ICurveXChainLiquidityGauge public immutable gauge;\n\n /**\n * @notice Address of the Child Liquidity Gauge Factory contract.\n */\n IChildLiquidityGaugeFactory public immutable gaugeFactory;\n\n // Ordered list of pool assets\n uint128 public immutable oethCoinIndex;\n uint128 public immutable wethCoinIndex;\n\n /**\n * @notice Maximum slippage allowed for adding/removing liquidity from the Curve pool.\n */\n uint256 public maxSlippage;\n\n event MaxSlippageUpdated(uint256 newMaxSlippage);\n\n /**\n * @dev Verifies that the caller is the Strategist.\n */\n modifier onlyStrategist() {\n require(\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n _;\n }\n\n /**\n * @dev Checks the Curve pool's balances have improved and the balances\n * have not tipped to the other side.\n * This modifier is only applied to functions that do a single sided add or remove.\n * The standard deposit function adds to both sides of the pool in a way that\n * the pool's balance is not worsened.\n * Withdrawals are proportional so doesn't change the pools asset balance.\n */\n modifier improvePoolBalance() {\n // Get the asset and OToken balances in the Curve pool\n uint256[] memory balancesBefore = curvePool.get_balances();\n // diff = ETH balance - OETH balance\n int256 diffBefore = balancesBefore[wethCoinIndex].toInt256() -\n balancesBefore[oethCoinIndex].toInt256();\n\n _;\n\n // Get the asset and OToken balances in the Curve pool\n uint256[] memory balancesAfter = curvePool.get_balances();\n // diff = ETH balance - OETH balance\n int256 diffAfter = balancesAfter[wethCoinIndex].toInt256() -\n balancesAfter[oethCoinIndex].toInt256();\n\n if (diffBefore == 0) {\n require(diffAfter == 0, \"Position balance is worsened\");\n } else if (diffBefore < 0) {\n // If the pool was originally imbalanced in favor of OETH, then\n // we want to check that the pool is now more balanced\n require(diffAfter <= 0, \"OTokens overshot peg\");\n require(diffBefore < diffAfter, \"OTokens balance worse\");\n } else if (diffBefore > 0) {\n // If the pool was originally imbalanced in favor of ETH, then\n // we want to check that the pool is now more balanced\n require(diffAfter >= 0, \"Assets overshot peg\");\n require(diffAfter < diffBefore, \"Assets balance worse\");\n }\n }\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _oeth,\n address _weth,\n address _gauge,\n address _gaugeFactory,\n uint128 _oethCoinIndex,\n uint128 _wethCoinIndex\n ) InitializableAbstractStrategy(_baseConfig) {\n oethCoinIndex = _oethCoinIndex;\n wethCoinIndex = _wethCoinIndex;\n\n lpToken = IERC20(_baseConfig.platformAddress);\n curvePool = ICurveStableSwapNG(_baseConfig.platformAddress);\n\n oeth = IERC20(_oeth);\n weth = IWETH9(_weth);\n gauge = ICurveXChainLiquidityGauge(_gauge);\n gaugeFactory = IChildLiquidityGaugeFactory(_gaugeFactory);\n\n _setGovernor(address(0));\n }\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Curve strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Address of CRV\n * @param _maxSlippage Maximum slippage allowed for adding/removing liquidity from the Curve pool.\n */\n function initialize(\n address[] calldata _rewardTokenAddresses, // CRV\n uint256 _maxSlippage\n ) external onlyGovernor initializer {\n address[] memory pTokens = new address[](1);\n pTokens[0] = address(curvePool);\n\n address[] memory _assets = new address[](1);\n _assets[0] = address(weth);\n\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n pTokens\n );\n\n _approveBase();\n _setMaxSlippage(_maxSlippage);\n }\n\n /***************************************\n Deposit\n ****************************************/\n\n /**\n * @notice Deposit WETH into the Curve pool\n * @param _weth Address of Wrapped ETH (WETH) contract.\n * @param _amount Amount of WETH to deposit.\n */\n function deposit(address _weth, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_weth, _amount);\n }\n\n function _deposit(address _weth, uint256 _wethAmount) internal {\n require(_wethAmount > 0, \"Must deposit something\");\n require(_weth == address(weth), \"Can only deposit WETH\");\n\n emit Deposit(_weth, address(lpToken), _wethAmount);\n\n // Get the asset and OToken balances in the Curve pool\n uint256[] memory balances = curvePool.get_balances();\n // safe to cast since min value is at least 0\n uint256 oethToAdd = uint256(\n _max(\n 0,\n balances[wethCoinIndex].toInt256() +\n _wethAmount.toInt256() -\n balances[oethCoinIndex].toInt256()\n )\n );\n\n /* Add so much OETH so that the pool ends up being balanced. And at minimum\n * add as much OETH as WETH and at maximum twice as much OETH.\n */\n oethToAdd = Math.max(oethToAdd, _wethAmount);\n oethToAdd = Math.min(oethToAdd, _wethAmount * 2);\n\n /* Mint OETH with a strategy that attempts to contribute to stability of OETH/WETH pool. Try\n * to mint so much OETH that after deployment of liquidity pool ends up being balanced.\n *\n * To manage unpredictability minimal OETH minted will always be at least equal or greater\n * to WETH amount deployed. And never larger than twice the WETH amount deployed even if\n * it would have a further beneficial effect on pool stability.\n */\n IVault(vaultAddress).mintForStrategy(oethToAdd);\n\n emit Deposit(address(oeth), address(lpToken), oethToAdd);\n\n uint256[] memory _amounts = new uint256[](2);\n _amounts[wethCoinIndex] = _wethAmount;\n _amounts[oethCoinIndex] = oethToAdd;\n\n uint256 valueInLpTokens = (_wethAmount + oethToAdd).divPrecisely(\n curvePool.get_virtual_price()\n );\n uint256 minMintAmount = valueInLpTokens.mulTruncate(\n uint256(1e18) - maxSlippage\n );\n\n // Do the deposit to the Curve pool\n uint256 lpDeposited = curvePool.add_liquidity(_amounts, minMintAmount);\n require(lpDeposited >= minMintAmount, \"Min LP amount error\");\n\n // Deposit the Curve pool's LP tokens into the Curve gauge\n gauge.deposit(lpDeposited);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n }\n\n /**\n * @notice Deposit the strategy's entire balance of WETH into the Curve pool\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 balance = weth.balanceOf(address(this));\n if (balance > 0) {\n _deposit(address(weth), balance);\n }\n }\n\n /***************************************\n Withdraw\n ****************************************/\n\n /**\n * @notice Withdraw ETH and OETH from the Curve pool, burn the OETH,\n * convert the ETH to WETH and transfer to the recipient.\n * @param _recipient Address to receive withdrawn asset which is normally the Vault.\n * @param _weth Address of the Wrapped ETH (WETH) contract.\n * @param _amount Amount of WETH to withdraw.\n */\n function withdraw(\n address _recipient,\n address _weth,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(_weth == address(weth), \"Can only withdraw WETH\");\n\n emit Withdrawal(_weth, address(lpToken), _amount);\n\n uint256 requiredLpTokens = calcTokenToBurn(_amount);\n\n _lpWithdraw(requiredLpTokens);\n\n /* math in requiredLpTokens should correctly calculate the amount of LP to remove\n * in that the strategy receives enough WETH on balanced removal\n */\n uint256[] memory _minWithdrawalAmounts = new uint256[](2);\n _minWithdrawalAmounts[wethCoinIndex] = _amount;\n // slither-disable-next-line unused-return\n curvePool.remove_liquidity(requiredLpTokens, _minWithdrawalAmounts);\n\n // Burn all the removed OETH and any that was left in the strategy\n uint256 oethToBurn = oeth.balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n\n emit Withdrawal(address(oeth), address(lpToken), oethToBurn);\n\n // Transfer WETH to the recipient\n require(\n weth.transfer(_recipient, _amount),\n \"Transfer of WETH not successful\"\n );\n\n // Ensure solvency of the vault\n _solvencyAssert();\n }\n\n function calcTokenToBurn(uint256 _wethAmount)\n internal\n view\n returns (uint256 lpToBurn)\n {\n /* The rate between coins in the pool determines the rate at which pool returns\n * tokens when doing balanced removal (remove_liquidity call). And by knowing how much WETH\n * we want we can determine how much of OETH we receive by removing liquidity.\n *\n * Because we are doing balanced removal we should be making profit when removing liquidity in a\n * pool tilted to either side.\n *\n * Important: A downside is that the Strategist / Governor needs to be\n * cognisant of not removing too much liquidity. And while the proposal to remove liquidity\n * is being voted on the pool tilt might change so much that the proposal that has been valid while\n * created is no longer valid.\n */\n\n uint256 poolWETHBalance = curvePool.balances(wethCoinIndex);\n /* K is multiplied by 1e36 which is used for higher precision calculation of required\n * pool LP tokens. Without it the end value can have rounding errors up to precision of\n * 10 digits. This way we move the decimal point by 36 places when doing the calculation\n * and again by 36 places when we are done with it.\n */\n uint256 k = (1e36 * lpToken.totalSupply()) / poolWETHBalance;\n // prettier-ignore\n // slither-disable-next-line divide-before-multiply\n uint256 diff = (_wethAmount + 1) * k;\n lpToBurn = diff / 1e36;\n }\n\n /**\n * @notice Remove all ETH and OETH from the Curve pool, burn the OETH,\n * convert the ETH to WETH and transfer to the Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 gaugeTokens = gauge.balanceOf(address(this));\n // Can not withdraw zero LP tokens from the gauge\n if (gaugeTokens == 0) return;\n _lpWithdraw(gaugeTokens);\n\n // Withdraws are proportional to assets held by 3Pool\n uint256[] memory minWithdrawAmounts = new uint256[](2);\n\n // Remove liquidity\n // slither-disable-next-line unused-return\n curvePool.remove_liquidity(\n lpToken.balanceOf(address(this)),\n minWithdrawAmounts\n );\n\n // Burn all OETH\n uint256 oethToBurn = oeth.balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n\n // Get the strategy contract's WETH balance.\n // This includes all that was removed from the Curve pool and\n // any ether that was sitting in the strategy contract before the removal.\n uint256 ethBalance = weth.balanceOf(address(this));\n require(\n weth.transfer(vaultAddress, ethBalance),\n \"Transfer of WETH not successful\"\n );\n\n emit Withdrawal(address(weth), address(lpToken), ethBalance);\n emit Withdrawal(address(oeth), address(lpToken), oethToBurn);\n }\n\n /***************************************\n Curve pool Rebalancing\n ****************************************/\n\n /**\n * @notice Mint OTokens and one-sided add to the Curve pool.\n * This is used when the Curve pool does not have enough OTokens and too many ETH.\n * The OToken/Asset, eg OETH/ETH, price with increase.\n * The amount of assets in the vault is unchanged.\n * The total supply of OTokens is increased.\n * The asset value of the strategy and vault is increased.\n * @param _oTokens The amount of OTokens to be minted and added to the pool.\n */\n function mintAndAddOTokens(uint256 _oTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n IVault(vaultAddress).mintForStrategy(_oTokens);\n\n uint256[] memory amounts = new uint256[](2);\n amounts[oethCoinIndex] = _oTokens;\n\n // Convert OETH to Curve pool LP tokens\n uint256 valueInLpTokens = (_oTokens).divPrecisely(\n curvePool.get_virtual_price()\n );\n // Apply slippage to LP tokens\n uint256 minMintAmount = valueInLpTokens.mulTruncate(\n uint256(1e18) - maxSlippage\n );\n\n // Add the minted OTokens to the Curve pool\n uint256 lpDeposited = curvePool.add_liquidity(amounts, minMintAmount);\n require(lpDeposited >= minMintAmount, \"Min LP amount error\");\n\n // Deposit the Curve pool LP tokens to the Curve gauge\n gauge.deposit(lpDeposited);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Deposit(address(oeth), address(lpToken), _oTokens);\n }\n\n /**\n * @notice One-sided remove of OTokens from the Curve pool which are then burned.\n * This is used when the Curve pool has too many OTokens and not enough ETH.\n * The amount of assets in the vault is unchanged.\n * The total supply of OTokens is reduced.\n * The asset value of the strategy and vault is reduced.\n * @param _lpTokens The amount of Curve pool LP tokens to be burned for OTokens.\n */\n function removeAndBurnOTokens(uint256 _lpTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n // Withdraw Curve pool LP tokens from Convex and remove OTokens from the Curve pool\n uint256 oethToBurn = _withdrawAndRemoveFromPool(\n _lpTokens,\n oethCoinIndex\n );\n\n // The vault burns the OTokens from this strategy\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Withdrawal(address(oeth), address(lpToken), oethToBurn);\n }\n\n /**\n * @notice One-sided remove of ETH from the Curve pool, convert to WETH\n * and transfer to the vault.\n * This is used when the Curve pool does not have enough OTokens and too many ETH.\n * The OToken/Asset, eg OETH/ETH, price with decrease.\n * The amount of assets in the vault increases.\n * The total supply of OTokens does not change.\n * The asset value of the strategy reduces.\n * The asset value of the vault should be close to the same.\n * @param _lpTokens The amount of Curve pool LP tokens to be burned for ETH.\n * @dev Curve pool LP tokens is used rather than WETH assets as Curve does not\n * have a way to accurately calculate the amount of LP tokens for a required\n * amount of ETH. Curve's `calc_token_amount` functioun does not include fees.\n * A 3rd party libary can be used that takes into account the fees, but this\n * is a gas intensive process. It's easier for the trusted strategist to\n * caclulate the amount of Curve pool LP tokens required off-chain.\n */\n function removeOnlyAssets(uint256 _lpTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n // Withdraw Curve pool LP tokens from Curve gauge and remove ETH from the Curve pool\n uint256 ethAmount = _withdrawAndRemoveFromPool(\n _lpTokens,\n wethCoinIndex\n );\n\n // Transfer WETH to the vault\n require(\n weth.transfer(vaultAddress, ethAmount),\n \"Transfer of WETH not successful\"\n );\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Withdrawal(address(weth), address(lpToken), ethAmount);\n }\n\n /**\n * @dev Remove Curve pool LP tokens from the Convex pool and\n * do a one-sided remove of ETH or OETH from the Curve pool.\n * @param _lpTokens The amount of Curve pool LP tokens to be removed from the Convex pool.\n * @param coinIndex The index of the coin to be removed from the Curve pool. 0 = ETH, 1 = OETH.\n * @return coinsRemoved The amount of ETH or OETH removed from the Curve pool.\n */\n function _withdrawAndRemoveFromPool(uint256 _lpTokens, uint128 coinIndex)\n internal\n returns (uint256 coinsRemoved)\n {\n // Withdraw Curve pool LP tokens from Curve gauge\n _lpWithdraw(_lpTokens);\n\n // Convert Curve pool LP tokens to ETH value\n uint256 valueInEth = _lpTokens.mulTruncate(\n curvePool.get_virtual_price()\n );\n // Apply slippage to ETH value\n uint256 minAmount = valueInEth.mulTruncate(uint256(1e18) - maxSlippage);\n\n // Remove just the ETH from the Curve pool\n coinsRemoved = curvePool.remove_liquidity_one_coin(\n _lpTokens,\n int128(coinIndex),\n minAmount,\n address(this)\n );\n }\n\n /**\n * Checks that the protocol is solvent, protecting from a rogue Strategist / Guardian that can\n * keep rebalancing the pool in both directions making the protocol lose a tiny amount of\n * funds each time.\n *\n * Protocol must be at least SOLVENCY_THRESHOLD (99,8 %) backed in order for the rebalances to\n * function.\n */\n function _solvencyAssert() internal view {\n uint256 _totalVaultValue = IVault(vaultAddress).totalValue();\n uint256 _totalOethbSupply = oeth.totalSupply();\n\n if (\n _totalVaultValue.divPrecisely(_totalOethbSupply) <\n SOLVENCY_THRESHOLD\n ) {\n revert(\"Protocol insolvent\");\n }\n }\n\n /***************************************\n Assets and Rewards\n ****************************************/\n\n /**\n * @notice Collect accumulated CRV (and other) rewards and send to the Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvesterOrStrategist\n nonReentrant\n {\n // CRV rewards flow.\n //---\n // CRV inflation:\n // Gauge receive CRV rewards from inflation.\n // Each checkpoint on the gauge send this CRV inflation to gauge factory.\n // This strategy should call mint on the gauge factory to collect the CRV rewards.\n // ---\n // Extra rewards:\n // Calling claim_rewards on the gauge will only claim extra rewards (outside of CRV).\n // ---\n\n // Mint CRV on Child Liquidity gauge factory\n gaugeFactory.mint(address(gauge));\n // Collect extra gauge rewards (outside of CRV)\n gauge.claim_rewards();\n\n _collectRewardTokens();\n }\n\n function _lpWithdraw(uint256 _lpAmount) internal {\n // withdraw lp tokens from the gauge without claiming rewards\n gauge.withdraw(_lpAmount);\n }\n\n /**\n * @notice Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == address(weth), \"Unsupported asset\");\n\n // WETH balance needed here for the balance check that happens from vault during depositing.\n balance = weth.balanceOf(address(this));\n uint256 lpTokens = gauge.balanceOf(address(this));\n if (lpTokens > 0) {\n balance += (lpTokens * curvePool.get_virtual_price()) / 1e18;\n }\n }\n\n /**\n * @notice Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == address(weth);\n }\n\n /***************************************\n Approvals\n ****************************************/\n\n /**\n * @notice Sets the maximum slippage allowed for any swap/liquidity operation\n * @param _maxSlippage Maximum slippage allowed, 1e18 = 100%.\n */\n function setMaxSlippage(uint256 _maxSlippage) external onlyGovernor {\n _setMaxSlippage(_maxSlippage);\n }\n\n function _setMaxSlippage(uint256 _maxSlippage) internal {\n require(_maxSlippage <= 5e16, \"Slippage must be less than 100%\");\n maxSlippage = _maxSlippage;\n emit MaxSlippageUpdated(_maxSlippage);\n }\n\n /**\n * @notice Approve the spending of all assets by their corresponding pool tokens,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n _approveBase();\n }\n\n /**\n * @dev Since we are unwrapping WETH before depositing it to Curve\n * there is no need to set an approval for WETH on the Curve\n * pool\n * @param _asset Address of the asset\n * @param _pToken Address of the Curve LP token\n */\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {}\n\n function _approveBase() internal {\n // Approve Curve pool for OETH (required for adding liquidity)\n // slither-disable-next-line unused-return\n oeth.approve(platformAddress, type(uint256).max);\n\n // Approve Curve pool for WETH (required for adding liquidity)\n // slither-disable-next-line unused-return\n weth.approve(platformAddress, type(uint256).max);\n\n // Approve Curve gauge contract to transfer Curve pool LP tokens\n // This is needed for deposits if Curve pool LP tokens into the Curve gauge.\n // slither-disable-next-line unused-return\n lpToken.approve(address(gauge), type(uint256).max);\n }\n\n /**\n * @dev Returns the largest of two numbers int256 version\n */\n function _max(int256 a, int256 b) internal pure returns (int256) {\n return a >= b ? a : b;\n }\n}\n" + }, + "contracts/strategies/BridgedWOETHStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20, SafeERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { AggregatorV3Interface } from \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\n\ncontract BridgedWOETHStrategy is InitializableAbstractStrategy {\n using StableMath for uint256;\n using StableMath for uint128;\n using SafeCast for uint256;\n using SafeERC20 for IERC20;\n\n event MaxPriceDiffBpsUpdated(uint128 oldValue, uint128 newValue);\n event WOETHPriceUpdated(uint128 oldValue, uint128 newValue);\n\n IWETH9 public immutable weth;\n IERC20 public immutable bridgedWOETH;\n IERC20 public immutable oethb;\n IOracle public immutable oracle;\n\n uint128 public lastOraclePrice;\n uint128 public maxPriceDiffBps;\n\n constructor(\n BaseStrategyConfig memory _stratConfig,\n address _weth,\n address _bridgedWOETH,\n address _oethb,\n address _oracle\n ) InitializableAbstractStrategy(_stratConfig) {\n weth = IWETH9(_weth);\n bridgedWOETH = IERC20(_bridgedWOETH);\n oethb = IERC20(_oethb);\n oracle = IOracle(_oracle);\n }\n\n function initialize(uint128 _maxPriceDiffBps)\n external\n onlyGovernor\n initializer\n {\n InitializableAbstractStrategy._initialize(\n new address[](0), // No reward tokens\n new address[](0), // No assets\n new address[](0) // No pTokens\n );\n\n _setMaxPriceDiffBps(_maxPriceDiffBps);\n }\n\n /**\n * @dev Sets the max price diff bps for the wOETH value appreciation\n * @param _maxPriceDiffBps Bps value, 10k == 100%\n */\n function setMaxPriceDiffBps(uint128 _maxPriceDiffBps)\n external\n onlyGovernor\n {\n _setMaxPriceDiffBps(_maxPriceDiffBps);\n }\n\n /**\n * @dev Sets the max price diff bps for the wOETH value appreciation\n * @param _maxPriceDiffBps Bps value, 10k == 100%\n */\n function _setMaxPriceDiffBps(uint128 _maxPriceDiffBps) internal {\n require(\n _maxPriceDiffBps > 0 && _maxPriceDiffBps <= 10000,\n \"Invalid bps value\"\n );\n\n emit MaxPriceDiffBpsUpdated(maxPriceDiffBps, _maxPriceDiffBps);\n\n maxPriceDiffBps = _maxPriceDiffBps;\n }\n\n /**\n * @dev Wrapper for _updateWOETHOraclePrice with nonReentrant flag\n * @return The latest price of wOETH from Oracle\n */\n function updateWOETHOraclePrice() external nonReentrant returns (uint256) {\n return _updateWOETHOraclePrice();\n }\n\n /**\n * @dev Finds the value of bridged wOETH from the Oracle.\n * Ensures that it's within the bounds and reasonable.\n * And stores it.\n *\n * NOTE: Intentionally not caching `Vault.priceProvider` here,\n * since doing so would mean that we also have to update this\n * strategy every time there's a change in oracle router.\n * Besides on L2, the gas is considerably cheaper than mainnet.\n *\n * @return Latest price from oracle\n */\n function _updateWOETHOraclePrice() internal returns (uint256) {\n // WETH price per unit of bridged wOETH\n uint256 oraclePrice = oracle.price(address(bridgedWOETH));\n\n // 1 wOETH > 1 WETH, always\n require(oraclePrice > 1 ether, \"Invalid wOETH value\");\n\n uint128 oraclePrice128 = oraclePrice.toUint128();\n\n // Do some checks\n if (lastOraclePrice > 0) {\n // Make sure the value only goes up\n require(oraclePrice128 >= lastOraclePrice, \"Negative wOETH yield\");\n\n // lastOraclePrice * (1 + maxPriceDiffBps)\n uint256 maxPrice = (lastOraclePrice * (1e4 + maxPriceDiffBps)) /\n 1e4;\n\n // And that it's within the bounds.\n require(oraclePrice128 <= maxPrice, \"Price diff beyond threshold\");\n }\n\n emit WOETHPriceUpdated(lastOraclePrice, oraclePrice128);\n\n // Store the price\n lastOraclePrice = oraclePrice128;\n\n return oraclePrice;\n }\n\n /**\n * @dev Computes & returns the value of given wOETH in WETH\n * @param woethAmount Amount of wOETH\n * @return Value of wOETH in WETH (using the last stored oracle price)\n */\n function getBridgedWOETHValue(uint256 woethAmount)\n public\n view\n returns (uint256)\n {\n return (woethAmount * lastOraclePrice) / 1 ether;\n }\n\n /**\n * @dev Takes in bridged wOETH and mints & returns\n * equivalent amount of OETHb.\n * @param woethAmount Amount of bridged wOETH to transfer in\n */\n function depositBridgedWOETH(uint256 woethAmount)\n external\n onlyGovernorOrStrategist\n nonReentrant\n {\n // Update wOETH price\n uint256 oraclePrice = _updateWOETHOraclePrice();\n\n // Figure out how much they are worth\n uint256 oethToMint = (woethAmount * oraclePrice) / 1 ether;\n\n require(oethToMint > 0, \"Invalid deposit amount\");\n\n // There's no pToken, however, it just uses WOETH address in the event\n emit Deposit(address(weth), address(bridgedWOETH), oethToMint);\n\n // Mint OETHb tokens and transfer it to the caller\n IVault(vaultAddress).mintForStrategy(oethToMint);\n\n // Transfer out minted OETHb\n // slither-disable-next-line unchecked-transfer unused-return\n oethb.transfer(msg.sender, oethToMint);\n\n // Transfer in all bridged wOETH tokens\n // slither-disable-next-line unchecked-transfer unused-return\n bridgedWOETH.transferFrom(msg.sender, address(this), woethAmount);\n }\n\n /**\n * @dev Takes in OETHb and burns it and returns\n * equivalent amount of bridged wOETH.\n * @param oethToBurn Amount of OETHb to burn\n */\n function withdrawBridgedWOETH(uint256 oethToBurn)\n external\n onlyGovernorOrStrategist\n nonReentrant\n {\n // Update wOETH price\n uint256 oraclePrice = _updateWOETHOraclePrice();\n\n // Figure out how much they are worth\n uint256 woethAmount = (oethToBurn * 1 ether) / oraclePrice;\n\n require(woethAmount > 0, \"Invalid withdraw amount\");\n\n // There's no pToken, however, it just uses WOETH address in the event\n emit Withdrawal(address(weth), address(bridgedWOETH), oethToBurn);\n\n // Transfer WOETH back\n // slither-disable-next-line unchecked-transfer unused-return\n bridgedWOETH.transfer(msg.sender, woethAmount);\n\n // Transfer in OETHb\n // slither-disable-next-line unchecked-transfer unused-return\n oethb.transferFrom(msg.sender, address(this), oethToBurn);\n\n // Burn OETHb\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n }\n\n /**\n * @notice Returns the amount of backing WETH the strategy holds\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == address(weth), \"Unsupported asset\");\n\n // Figure out how much wOETH is worth at the time.\n // Always uses the last stored oracle price.\n // Call updateWOETHOraclePrice manually to pull in latest yields.\n\n // NOTE: If the contract has been deployed but the call to\n // `updateWOETHOraclePrice()` has never been made, then this\n // will return zero. It should be fine because the strategy\n // should update the price whenever a deposit/withdraw happens.\n\n // If `updateWOETHOraclePrice()` hasn't been called in a while,\n // the strategy will underreport its holdings but never overreport it.\n\n balance =\n (bridgedWOETH.balanceOf(address(this)) * lastOraclePrice) /\n 1 ether;\n }\n\n /**\n * @notice Check if an asset is supported.\n * @param _asset Address of the asset\n * @return bool Whether asset is supported\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n // Strategist deposits bridged wOETH but the contract only\n // reports the balance in WETH. As far as Vault is concerned,\n // it isn't aware of bridged wOETH token\n return _asset == address(weth);\n }\n\n /***************************************\n Overridden methods\n ****************************************/\n /**\n * @inheritdoc InitializableAbstractStrategy\n */\n function transferToken(address _asset, uint256 _amount)\n public\n override\n onlyGovernor\n {\n require(\n _asset != address(bridgedWOETH) && _asset != address(weth),\n \"Cannot transfer supported asset\"\n );\n // Use SafeERC20 only for rescuing unknown assets; core tokens are standard.\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /**\n * @notice deposit() function not used for this strategy\n */\n function deposit(address, uint256)\n external\n override\n onlyVault\n nonReentrant\n {\n // Use depositBridgedWOETH() instead\n require(false, \"Deposit disabled\");\n }\n\n /**\n * @notice depositAll() function not used for this strategy\n */\n function depositAll() external override onlyVault nonReentrant {\n // Use depositBridgedWOETH() instead\n require(false, \"Deposit disabled\");\n }\n\n /**\n * @notice withdraw() function not used for this strategy\n */\n function withdraw(\n // solhint-disable-next-line no-unused-vars\n address _recipient,\n // solhint-disable-next-line no-unused-vars\n address _asset,\n // solhint-disable-next-line no-unused-vars\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(false, \"Withdrawal disabled\");\n }\n\n /**\n * @notice withdrawAll() function not used for this strategy\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n // Withdrawal disabled\n }\n\n function _abstractSetPToken(address, address) internal override {\n revert(\"No pTokens are used\");\n }\n\n function safeApproveAllTokens() external override {}\n\n /**\n * @inheritdoc InitializableAbstractStrategy\n */\n function removePToken(uint256) external override {\n revert(\"No pTokens are used\");\n }\n\n /**\n * @inheritdoc InitializableAbstractStrategy\n */\n function collectRewardTokens() external override {}\n}\n" + }, + "contracts/strategies/crosschain/AbstractCCTPIntegrator.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title AbstractCCTPIntegrator\n * @author Origin Protocol Inc\n *\n * @dev Abstract contract that contains all the logic used to integrate with CCTP.\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\n\nimport { ICCTPTokenMessenger, ICCTPMessageTransmitter, IMessageHandlerV2 } from \"../../interfaces/cctp/ICCTP.sol\";\n\nimport { CrossChainStrategyHelper } from \"./CrossChainStrategyHelper.sol\";\nimport { Governable } from \"../../governance/Governable.sol\";\nimport { BytesHelper } from \"../../utils/BytesHelper.sol\";\nimport \"../../utils/Helpers.sol\";\n\nabstract contract AbstractCCTPIntegrator is Governable, IMessageHandlerV2 {\n using SafeERC20 for IERC20;\n\n using BytesHelper for bytes;\n using CrossChainStrategyHelper for bytes;\n\n event LastTransferNonceUpdated(uint64 lastTransferNonce);\n event NonceProcessed(uint64 nonce);\n\n event CCTPMinFinalityThresholdSet(uint16 minFinalityThreshold);\n event CCTPFeePremiumBpsSet(uint16 feePremiumBps);\n event OperatorChanged(address operator);\n event TokensBridged(\n uint32 destinationDomain,\n address peerStrategy,\n address tokenAddress,\n uint256 tokenAmount,\n uint256 maxFee,\n uint32 minFinalityThreshold,\n bytes hookData\n );\n event MessageTransmitted(\n uint32 destinationDomain,\n address peerStrategy,\n uint32 minFinalityThreshold,\n bytes message\n );\n\n // Message body V2 fields\n // Ref: https://developers.circle.com/cctp/technical-guide#message-body\n // Ref: https://github.com/circlefin/evm-cctp-contracts/blob/master/src/messages/v2/BurnMessageV2.sol\n uint8 private constant BURN_MESSAGE_V2_VERSION_INDEX = 0;\n uint8 private constant BURN_MESSAGE_V2_BURN_TOKEN_INDEX = 4;\n uint8 private constant BURN_MESSAGE_V2_RECIPIENT_INDEX = 36;\n uint8 private constant BURN_MESSAGE_V2_AMOUNT_INDEX = 68;\n uint8 private constant BURN_MESSAGE_V2_MESSAGE_SENDER_INDEX = 100;\n uint8 private constant BURN_MESSAGE_V2_FEE_EXECUTED_INDEX = 164;\n uint8 private constant BURN_MESSAGE_V2_HOOK_DATA_INDEX = 228;\n\n /**\n * @notice Max transfer threshold imposed by the CCTP\n * Ref: https://developers.circle.com/cctp/evm-smart-contracts#depositforburn\n * @dev 10M USDC limit applies to both standard and fast transfer modes. The fast transfer mode has\n * an additional limitation that is not present on-chain and Circle may alter that amount off-chain\n * at their preference. The amount available for fast transfer can be queried here:\n * https://iris-api.circle.com/v2/fastBurn/USDC/allowance .\n * If a fast transfer token transaction has been issued and there is not enough allowance for it\n * the off-chain Iris component will re-attempt the transaction and if it fails it will fallback\n * to a standard transfer. Reference section 4.3 in the whitepaper:\n * https://6778953.fs1.hubspotusercontent-na1.net/hubfs/6778953/PDFs/Whitepapers/CCTPV2_White_Paper.pdf\n */\n uint256 public constant MAX_TRANSFER_AMOUNT = 10_000_000 * 10**6; // 10M USDC\n\n /// @notice Minimum transfer amount to avoid zero or dust transfers\n uint256 public constant MIN_TRANSFER_AMOUNT = 10**6;\n\n // CCTP contracts\n // This implementation assumes that remote and local chains have these contracts\n // deployed on the same addresses.\n /// @notice CCTP message transmitter contract\n ICCTPMessageTransmitter public immutable cctpMessageTransmitter;\n /// @notice CCTP token messenger contract\n ICCTPTokenMessenger public immutable cctpTokenMessenger;\n\n /// @notice USDC address on local chain\n address public immutable usdcToken;\n\n /// @notice USDC address on remote chain\n address public immutable peerUsdcToken;\n\n /// @notice Domain ID of the chain from which messages are accepted\n uint32 public immutable peerDomainID;\n\n /// @notice Strategy address on other chain\n address public immutable peerStrategy;\n\n /**\n * @notice Minimum finality threshold\n * Can be 1000 (safe, after 1 epoch) or 2000 (finalized, after 2 epochs).\n * Ref: https://developers.circle.com/cctp/technical-guide#finality-thresholds\n * @dev When configuring the contract for fast transfer we should check the available\n * allowance of USDC that can be bridged using fast mode:\n * wget https://iris-api.circle.com/v2/fastBurn/USDC/allowance\n */\n uint16 public minFinalityThreshold;\n\n /// @notice Fee premium in basis points\n uint16 public feePremiumBps;\n\n /// @notice Nonce of the last known deposit or withdrawal\n uint64 public lastTransferNonce;\n\n /// @notice Operator address: Can relay CCTP messages\n address public operator;\n\n /// @notice Mapping of processed nonces\n mapping(uint64 => bool) private nonceProcessed;\n\n // For future use\n uint256[48] private __gap;\n\n modifier onlyCCTPMessageTransmitter() {\n require(\n msg.sender == address(cctpMessageTransmitter),\n \"Caller is not CCTP transmitter\"\n );\n _;\n }\n\n modifier onlyOperator() {\n require(msg.sender == operator, \"Caller is not the Operator\");\n _;\n }\n\n /**\n * @notice Configuration for CCTP integration\n * @param cctpTokenMessenger Address of the CCTP token messenger contract\n * @param cctpMessageTransmitter Address of the CCTP message transmitter contract\n * @param peerDomainID Domain ID of the chain from which messages are accepted.\n * 0 for Ethereum, 6 for Base, etc.\n * Ref: https://developers.circle.com/cctp/cctp-supported-blockchains\n * @param peerStrategy Address of the master or remote strategy on the other chain\n * @param usdcToken USDC address on local chain\n */\n struct CCTPIntegrationConfig {\n address cctpTokenMessenger;\n address cctpMessageTransmitter;\n uint32 peerDomainID;\n address peerStrategy;\n address usdcToken;\n address peerUsdcToken;\n }\n\n constructor(CCTPIntegrationConfig memory _config) {\n require(_config.usdcToken != address(0), \"Invalid USDC address\");\n require(\n _config.peerUsdcToken != address(0),\n \"Invalid peer USDC address\"\n );\n require(\n _config.cctpTokenMessenger != address(0),\n \"Invalid CCTP config\"\n );\n require(\n _config.cctpMessageTransmitter != address(0),\n \"Invalid CCTP config\"\n );\n require(\n _config.peerStrategy != address(0),\n \"Invalid peer strategy address\"\n );\n\n cctpMessageTransmitter = ICCTPMessageTransmitter(\n _config.cctpMessageTransmitter\n );\n cctpTokenMessenger = ICCTPTokenMessenger(_config.cctpTokenMessenger);\n\n // Domain ID of the chain from which messages are accepted\n peerDomainID = _config.peerDomainID;\n\n // Strategy address on other chain, should\n // always be same as the proxy of this strategy\n peerStrategy = _config.peerStrategy;\n\n // USDC address on local chain\n usdcToken = _config.usdcToken;\n\n // Just a sanity check to ensure the base token is USDC\n uint256 _usdcTokenDecimals = Helpers.getDecimals(_config.usdcToken);\n string memory _usdcTokenSymbol = Helpers.getSymbol(_config.usdcToken);\n require(_usdcTokenDecimals == 6, \"Base token decimals must be 6\");\n require(\n keccak256(abi.encodePacked(_usdcTokenSymbol)) ==\n keccak256(abi.encodePacked(\"USDC\")),\n \"Token symbol must be USDC\"\n );\n\n // USDC address on remote chain\n peerUsdcToken = _config.peerUsdcToken;\n }\n\n /**\n * @dev Initialize the implementation contract\n * @param _operator Operator address\n * @param _minFinalityThreshold Minimum finality threshold\n * @param _feePremiumBps Fee premium in basis points\n */\n function _initialize(\n address _operator,\n uint16 _minFinalityThreshold,\n uint16 _feePremiumBps\n ) internal {\n _setOperator(_operator);\n _setMinFinalityThreshold(_minFinalityThreshold);\n _setFeePremiumBps(_feePremiumBps);\n\n // Nonce starts at 1, so assume nonce 0 as processed.\n // NOTE: This will cause the deposit/withdraw to fail if the\n // strategy is not initialized properly (which is expected).\n nonceProcessed[0] = true;\n }\n\n /***************************************\n Settings\n ****************************************/\n /**\n * @dev Set the operator address\n * @param _operator Operator address\n */\n function setOperator(address _operator) external onlyGovernor {\n _setOperator(_operator);\n }\n\n /**\n * @dev Set the operator address\n * @param _operator Operator address\n */\n function _setOperator(address _operator) internal {\n operator = _operator;\n emit OperatorChanged(_operator);\n }\n\n /**\n * @dev Set the minimum finality threshold at which\n * the message is considered to be finalized to relay.\n * Only accepts a value of 1000 (Safe, after 1 epoch) or\n * 2000 (Finalized, after 2 epochs).\n * @param _minFinalityThreshold Minimum finality threshold\n */\n function setMinFinalityThreshold(uint16 _minFinalityThreshold)\n external\n onlyGovernor\n {\n _setMinFinalityThreshold(_minFinalityThreshold);\n }\n\n /**\n * @dev Set the minimum finality threshold\n * @param _minFinalityThreshold Minimum finality threshold\n */\n function _setMinFinalityThreshold(uint16 _minFinalityThreshold) internal {\n // 1000 for fast transfer and 2000 for standard transfer\n require(\n _minFinalityThreshold == 1000 || _minFinalityThreshold == 2000,\n \"Invalid threshold\"\n );\n\n minFinalityThreshold = _minFinalityThreshold;\n emit CCTPMinFinalityThresholdSet(_minFinalityThreshold);\n }\n\n /**\n * @dev Set the fee premium in basis points.\n * Cannot be higher than 30% (3000 basis points).\n * @param _feePremiumBps Fee premium in basis points\n */\n function setFeePremiumBps(uint16 _feePremiumBps) external onlyGovernor {\n _setFeePremiumBps(_feePremiumBps);\n }\n\n /**\n * @dev Set the fee premium in basis points\n * Cannot be higher than 30% (3000 basis points).\n * Ref: https://developers.circle.com/cctp/technical-guide#fees\n * @param _feePremiumBps Fee premium in basis points\n */\n function _setFeePremiumBps(uint16 _feePremiumBps) internal {\n require(_feePremiumBps <= 3000, \"Fee premium too high\"); // 30%\n\n feePremiumBps = _feePremiumBps;\n emit CCTPFeePremiumBpsSet(_feePremiumBps);\n }\n\n /***************************************\n CCTP message handling\n ****************************************/\n\n /**\n * @dev Handles a finalized CCTP message\n * @param sourceDomain Source domain of the message\n * @param sender Sender of the message\n * @param finalityThresholdExecuted Fidelity threshold executed\n * @param messageBody Message body\n */\n function handleReceiveFinalizedMessage(\n uint32 sourceDomain,\n bytes32 sender,\n uint32 finalityThresholdExecuted,\n bytes memory messageBody\n ) external override onlyCCTPMessageTransmitter returns (bool) {\n // Make sure the finality threshold at execution is at least 2000\n require(\n finalityThresholdExecuted >= 2000,\n \"Finality threshold too low\"\n );\n\n return _handleReceivedMessage(sourceDomain, sender, messageBody);\n }\n\n /**\n * @dev Handles an unfinalized but safe CCTP message\n * @param sourceDomain Source domain of the message\n * @param sender Sender of the message\n * @param finalityThresholdExecuted Fidelity threshold executed\n * @param messageBody Message body\n */\n function handleReceiveUnfinalizedMessage(\n uint32 sourceDomain,\n bytes32 sender,\n uint32 finalityThresholdExecuted,\n bytes memory messageBody\n ) external override onlyCCTPMessageTransmitter returns (bool) {\n // Make sure the contract is configured to handle unfinalized messages\n require(\n minFinalityThreshold == 1000,\n \"Unfinalized messages are not supported\"\n );\n // Make sure the finality threshold at execution is at least 1000\n require(\n finalityThresholdExecuted >= 1000,\n \"Finality threshold too low\"\n );\n\n return _handleReceivedMessage(sourceDomain, sender, messageBody);\n }\n\n /**\n * @dev Handles a CCTP message\n * @param sourceDomain Source domain of the message\n * @param sender Sender of the message\n * @param messageBody Message body\n */\n function _handleReceivedMessage(\n uint32 sourceDomain,\n bytes32 sender,\n bytes memory messageBody\n ) internal returns (bool) {\n require(sourceDomain == peerDomainID, \"Unknown Source Domain\");\n\n // Extract address from bytes32 (CCTP stores addresses as right-padded bytes32)\n address senderAddress = address(uint160(uint256(sender)));\n require(senderAddress == peerStrategy, \"Unknown Sender\");\n\n _onMessageReceived(messageBody);\n\n return true;\n }\n\n /**\n * @dev Sends tokens to the peer strategy using CCTP Token Messenger\n * @param tokenAmount Amount of tokens to send\n * @param hookData Hook data\n */\n function _sendTokens(uint256 tokenAmount, bytes memory hookData)\n internal\n virtual\n {\n // CCTP has a maximum transfer amount of 10M USDC per tx\n require(tokenAmount <= MAX_TRANSFER_AMOUNT, \"Token amount too high\");\n\n // Approve only what needs to be transferred\n IERC20(usdcToken).safeApprove(address(cctpTokenMessenger), tokenAmount);\n\n // Compute the max fee to be paid.\n // Ref: https://developers.circle.com/cctp/evm-smart-contracts#getminfeeamount\n // The right way to compute fees would be to use CCTP's getMinFeeAmount function.\n // The issue is that the getMinFeeAmount is not present on v2.0 contracts, but is on\n // v2.1. Some of CCTP's deployed contracts are v2.0, some are v2.1.\n // We will only be using standard transfers and fee on those is 0 for now. If they\n // ever start implementing fee for standard transfers or if we decide to use fast\n // trasnfer, we can use feePremiumBps as a workaround.\n uint256 maxFee = feePremiumBps > 0\n ? (tokenAmount * feePremiumBps) / 10000\n : 0;\n\n // Send tokens to the peer strategy using CCTP Token Messenger\n cctpTokenMessenger.depositForBurnWithHook(\n tokenAmount,\n peerDomainID,\n bytes32(uint256(uint160(peerStrategy))),\n address(usdcToken),\n bytes32(uint256(uint160(peerStrategy))),\n maxFee,\n uint32(minFinalityThreshold),\n hookData\n );\n\n emit TokensBridged(\n peerDomainID,\n peerStrategy,\n usdcToken,\n tokenAmount,\n maxFee,\n uint32(minFinalityThreshold),\n hookData\n );\n }\n\n /**\n * @dev Sends a message to the peer strategy using CCTP Message Transmitter\n * @param message Payload of the message to send\n */\n function _sendMessage(bytes memory message) internal virtual {\n cctpMessageTransmitter.sendMessage(\n peerDomainID,\n bytes32(uint256(uint160(peerStrategy))),\n bytes32(uint256(uint160(peerStrategy))),\n uint32(minFinalityThreshold),\n message\n );\n\n emit MessageTransmitted(\n peerDomainID,\n peerStrategy,\n uint32(minFinalityThreshold),\n message\n );\n }\n\n /**\n * @dev Receives a message from the peer strategy on the other chain,\n * does some basic checks and relays it to the local MessageTransmitterV2.\n * If the message is a burn message, it will also handle the hook data\n * and call the _onTokenReceived function.\n * @param message Payload of the message to send\n * @param attestation Attestation of the message\n */\n function relay(bytes memory message, bytes memory attestation)\n external\n onlyOperator\n {\n (\n uint32 version,\n uint32 sourceDomainID,\n address sender,\n address recipient,\n bytes memory messageBody\n ) = message.decodeMessageHeader();\n\n // Ensure that it's a CCTP message\n require(\n version == CrossChainStrategyHelper.CCTP_MESSAGE_VERSION,\n \"Invalid CCTP message version\"\n );\n\n // Ensure that the source domain is the peer domain\n require(sourceDomainID == peerDomainID, \"Unknown Source Domain\");\n\n // Ensure message body version\n version = messageBody.extractUint32(BURN_MESSAGE_V2_VERSION_INDEX);\n\n // NOTE: There's a possibility that the CCTP Token Messenger might\n // send other types of messages in future, not just the burn message.\n // If it ever comes to that, this shouldn't cause us any problems\n // because it has to still go through the followign checks:\n // - version check\n // - message body length check\n // - sender and recipient (which should be in the same slots and same as address(this))\n // - hook data handling (which will revert even if all the above checks pass)\n bool isBurnMessageV1 = sender == address(cctpTokenMessenger);\n\n if (isBurnMessageV1) {\n // Handle burn message\n require(\n version == 1 &&\n messageBody.length >= BURN_MESSAGE_V2_HOOK_DATA_INDEX,\n \"Invalid burn message\"\n );\n\n // Ensure the burn token is USDC\n address burnToken = messageBody.extractAddress(\n BURN_MESSAGE_V2_BURN_TOKEN_INDEX\n );\n require(burnToken == peerUsdcToken, \"Invalid burn token\");\n\n // Address of caller of depositForBurn (or depositForBurnWithCaller) on source domain\n sender = messageBody.extractAddress(\n BURN_MESSAGE_V2_MESSAGE_SENDER_INDEX\n );\n\n recipient = messageBody.extractAddress(\n BURN_MESSAGE_V2_RECIPIENT_INDEX\n );\n } else {\n // We handle only Burn message or our custom messagee\n require(\n version == CrossChainStrategyHelper.ORIGIN_MESSAGE_VERSION,\n \"Unsupported message version\"\n );\n }\n\n // Ensure the recipient is this contract\n // Both sender and recipient should be deployed to same address on both chains.\n require(address(this) == recipient, \"Unexpected recipient address\");\n require(sender == peerStrategy, \"Incorrect sender/recipient address\");\n\n // Relay the message\n // This step also mints USDC and transfers it to the recipient wallet\n bool relaySuccess = cctpMessageTransmitter.receiveMessage(\n message,\n attestation\n );\n require(relaySuccess, \"Receive message failed\");\n\n if (isBurnMessageV1) {\n // Extract the hook data from the message body\n bytes memory hookData = messageBody.extractSlice(\n BURN_MESSAGE_V2_HOOK_DATA_INDEX,\n messageBody.length\n );\n\n // Extract the token amount from the message body\n uint256 tokenAmount = messageBody.extractUint256(\n BURN_MESSAGE_V2_AMOUNT_INDEX\n );\n\n // Extract the fee executed from the message body\n uint256 feeExecuted = messageBody.extractUint256(\n BURN_MESSAGE_V2_FEE_EXECUTED_INDEX\n );\n\n // Call the _onTokenReceived function\n _onTokenReceived(tokenAmount - feeExecuted, feeExecuted, hookData);\n }\n }\n\n /***************************************\n Message utils\n ****************************************/\n\n /***************************************\n Nonce Handling\n ****************************************/\n /**\n * @dev Checks if the last known transfer is pending.\n * Nonce starts at 1, so 0 is disregarded.\n * @return True if a transfer is pending, false otherwise\n */\n function isTransferPending() public view returns (bool) {\n return !nonceProcessed[lastTransferNonce];\n }\n\n /**\n * @dev Checks if a given nonce is processed.\n * Nonce starts at 1, so 0 is disregarded.\n * @param nonce Nonce to check\n * @return True if the nonce is processed, false otherwise\n */\n function isNonceProcessed(uint64 nonce) public view returns (bool) {\n return nonceProcessed[nonce];\n }\n\n /**\n * @dev Marks a given nonce as processed.\n * Can only mark nonce as processed once. New nonce should\n * always be greater than the last known nonce. Also updates\n * the last known nonce.\n * @param nonce Nonce to mark as processed\n */\n function _markNonceAsProcessed(uint64 nonce) internal {\n uint64 lastNonce = lastTransferNonce;\n\n // Can only mark latest nonce as processed\n // Master strategy when receiving a message from the remote strategy\n // will have lastNone == nonce, as the nonce is increase at the start\n // of deposit / withdrawal flow.\n // Remote strategy will have lastNonce < nonce, as a new nonce initiated\n // from master will be greater than the last one.\n require(nonce >= lastNonce, \"Nonce too low\");\n // Can only mark nonce as processed once\n require(!nonceProcessed[nonce], \"Nonce already processed\");\n\n nonceProcessed[nonce] = true;\n emit NonceProcessed(nonce);\n\n if (nonce != lastNonce) {\n // Update last known nonce\n lastTransferNonce = nonce;\n emit LastTransferNonceUpdated(nonce);\n }\n }\n\n /**\n * @dev Gets the next nonce to use.\n * Nonce starts at 1, so 0 is disregarded.\n * Reverts if last nonce hasn't been processed yet.\n * @return Next nonce\n */\n function _getNextNonce() internal returns (uint64) {\n uint64 nonce = lastTransferNonce;\n\n require(nonceProcessed[nonce], \"Pending token transfer\");\n\n nonce = nonce + 1;\n lastTransferNonce = nonce;\n emit LastTransferNonceUpdated(nonce);\n\n return nonce;\n }\n\n /***************************************\n Inheritence overrides\n ****************************************/\n\n /**\n * @dev Called when the USDC is received from the CCTP\n * @param tokenAmount The actual amount of USDC received (amount sent - fee executed)\n * @param feeExecuted The fee executed\n * @param payload The payload of the message (hook data)\n */\n function _onTokenReceived(\n uint256 tokenAmount,\n uint256 feeExecuted,\n bytes memory payload\n ) internal virtual;\n\n /**\n * @dev Called when the message is received\n * @param payload The payload of the message\n */\n function _onMessageReceived(bytes memory payload) internal virtual;\n}\n" + }, + "contracts/strategies/crosschain/CrossChainMasterStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Yearn V3 Master Strategy - the Mainnet part\n * @author Origin Protocol Inc\n *\n * @dev This strategy can only perform 1 deposit or withdrawal at a time. For that\n * reason it shouldn't be configured as an asset default strategy.\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { AbstractCCTPIntegrator } from \"./AbstractCCTPIntegrator.sol\";\nimport { CrossChainStrategyHelper } from \"./CrossChainStrategyHelper.sol\";\n\ncontract CrossChainMasterStrategy is\n AbstractCCTPIntegrator,\n InitializableAbstractStrategy\n{\n using SafeERC20 for IERC20;\n using CrossChainStrategyHelper for bytes;\n\n /**\n * @notice Remote strategy balance\n * @dev The remote balance is cached and might not reflect the actual\n * real-time balance of the remote strategy.\n */\n uint256 public remoteStrategyBalance;\n\n /// @notice Amount that's bridged due to a pending Deposit process\n /// but with no acknowledgement from the remote strategy yet\n uint256 public pendingAmount;\n\n uint256 internal constant MAX_BALANCE_CHECK_AGE = 1 days;\n\n event RemoteStrategyBalanceUpdated(uint256 balance);\n event WithdrawRequested(address indexed asset, uint256 amount);\n event WithdrawAllSkipped();\n event BalanceCheckIgnored(uint64 nonce, uint256 timestamp, bool isTooOld);\n\n /**\n * @param _stratConfig The platform and OToken vault addresses\n */\n constructor(\n BaseStrategyConfig memory _stratConfig,\n CCTPIntegrationConfig memory _cctpConfig\n )\n InitializableAbstractStrategy(_stratConfig)\n AbstractCCTPIntegrator(_cctpConfig)\n {\n require(\n _stratConfig.platformAddress == address(0),\n \"Invalid platform address\"\n );\n require(\n _stratConfig.vaultAddress != address(0),\n \"Invalid Vault address\"\n );\n }\n\n /**\n * @dev Initialize the strategy implementation\n * @param _operator Address of the operator\n * @param _minFinalityThreshold Minimum finality threshold\n * @param _feePremiumBps Fee premium in basis points\n */\n function initialize(\n address _operator,\n uint16 _minFinalityThreshold,\n uint16 _feePremiumBps\n ) external virtual onlyGovernor initializer {\n _initialize(_operator, _minFinalityThreshold, _feePremiumBps);\n\n address[] memory rewardTokens = new address[](0);\n address[] memory assets = new address[](0);\n address[] memory pTokens = new address[](0);\n\n InitializableAbstractStrategy._initialize(\n rewardTokens,\n assets,\n pTokens\n );\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function depositAll() external override onlyVault nonReentrant {\n uint256 balance = IERC20(usdcToken).balanceOf(address(this));\n // Deposit if balance is greater than 1 USDC\n if (balance >= MIN_TRANSFER_AMOUNT) {\n _deposit(usdcToken, balance);\n }\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_recipient == vaultAddress, \"Only Vault can withdraw\");\n _withdraw(_asset, _amount);\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n if (isTransferPending()) {\n // Do nothing if there is a pending transfer\n // Note: We never want withdrawAll to fail, so\n // emit an event to indicate that the withdrawal was skipped\n emit WithdrawAllSkipped();\n return;\n }\n\n // Withdraw everything in Remote strategy\n uint256 _remoteBalance = remoteStrategyBalance;\n if (_remoteBalance < MIN_TRANSFER_AMOUNT) {\n // Do nothing if there is less than 1 USDC in the Remote strategy\n return;\n }\n\n _withdraw(\n usdcToken,\n _remoteBalance > MAX_TRANSFER_AMOUNT\n ? MAX_TRANSFER_AMOUNT\n : _remoteBalance\n );\n }\n\n /**\n * @notice Check the balance of the strategy that includes\n * the balance of the asset on this contract,\n * the amount of the asset being bridged,\n * and the balance reported by the Remote strategy.\n * @param _asset Address of the asset to check\n * @return balance Total balance of the asset\n */\n function checkBalance(address _asset)\n public\n view\n override\n returns (uint256 balance)\n {\n require(_asset == usdcToken, \"Unsupported asset\");\n\n // USDC balance on this contract\n // + USDC being bridged\n // + USDC cached in the corresponding Remote part of this contract\n return\n IERC20(usdcToken).balanceOf(address(this)) +\n pendingAmount +\n remoteStrategyBalance;\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == usdcToken;\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {}\n\n /// @inheritdoc InitializableAbstractStrategy\n function _abstractSetPToken(address, address) internal override {}\n\n /// @inheritdoc InitializableAbstractStrategy\n function collectRewardTokens()\n external\n override\n onlyHarvesterOrStrategist\n nonReentrant\n {}\n\n /// @inheritdoc AbstractCCTPIntegrator\n function _onMessageReceived(bytes memory payload) internal override {\n if (\n payload.getMessageType() ==\n CrossChainStrategyHelper.BALANCE_CHECK_MESSAGE\n ) {\n // Received when Remote strategy checks the balance\n _processBalanceCheckMessage(payload);\n return;\n }\n\n revert(\"Unknown message type\");\n }\n\n /// @inheritdoc AbstractCCTPIntegrator\n function _onTokenReceived(\n uint256 tokenAmount,\n // solhint-disable-next-line no-unused-vars\n uint256 feeExecuted,\n bytes memory payload\n ) internal override {\n uint64 _nonce = lastTransferNonce;\n\n // Should be expecting an acknowledgement\n require(!isNonceProcessed(_nonce), \"Nonce already processed\");\n\n // Now relay to the regular flow\n // NOTE: Calling _onMessageReceived would mean that we are bypassing a\n // few checks that the regular flow does (like sourceDomainID check\n // and sender check in `handleReceiveFinalizedMessage`). However,\n // CCTPMessageRelayer relays the message first (which will go through\n // all the checks) and not update balance and then finally calls this\n // `_onTokenReceived` which will update the balance.\n // So, if any of the checks fail during the first no-balance-update flow,\n // this won't happen either, since the tx would revert.\n _onMessageReceived(payload);\n\n // Send any tokens in the contract to the Vault\n uint256 usdcBalance = IERC20(usdcToken).balanceOf(address(this));\n // Should always have enough tokens\n require(usdcBalance >= tokenAmount, \"Insufficient balance\");\n // Transfer all tokens to the Vault to not leave any dust\n IERC20(usdcToken).safeTransfer(vaultAddress, usdcBalance);\n\n // Emit withdrawal amount\n emit Withdrawal(usdcToken, usdcToken, usdcBalance);\n }\n\n /**\n * @dev Bridge and deposit asset into the remote strategy\n * @param _asset Address of the asset to deposit\n * @param depositAmount Amount of the asset to deposit\n */\n function _deposit(address _asset, uint256 depositAmount) internal virtual {\n require(_asset == usdcToken, \"Unsupported asset\");\n require(pendingAmount == 0, \"Unexpected pending amount\");\n // Deposit at least 1 USDC\n require(\n depositAmount >= MIN_TRANSFER_AMOUNT,\n \"Deposit amount too small\"\n );\n require(\n depositAmount <= MAX_TRANSFER_AMOUNT,\n \"Deposit amount too high\"\n );\n\n // Get the next nonce\n // Note: reverts if a transfer is pending\n uint64 nonce = _getNextNonce();\n\n // Set pending amount\n pendingAmount = depositAmount;\n\n // Build deposit message payload\n bytes memory message = CrossChainStrategyHelper.encodeDepositMessage(\n nonce,\n depositAmount\n );\n\n // Send deposit message to the remote strategy\n _sendTokens(depositAmount, message);\n\n // Emit deposit event\n emit Deposit(_asset, _asset, depositAmount);\n }\n\n /**\n * @dev Send a withdraw request to the remote strategy\n * @param _asset Address of the asset to withdraw\n * @param _amount Amount of the asset to withdraw\n */\n function _withdraw(address _asset, uint256 _amount) internal virtual {\n require(_asset == usdcToken, \"Unsupported asset\");\n // Withdraw at least 1 USDC\n require(_amount >= MIN_TRANSFER_AMOUNT, \"Withdraw amount too small\");\n require(\n _amount <= remoteStrategyBalance,\n \"Withdraw amount exceeds remote strategy balance\"\n );\n require(\n _amount <= MAX_TRANSFER_AMOUNT,\n \"Withdraw amount exceeds max transfer amount\"\n );\n\n // Get the next nonce\n // Note: reverts if a transfer is pending\n uint64 nonce = _getNextNonce();\n\n // Build and send withdrawal message with payload\n bytes memory message = CrossChainStrategyHelper.encodeWithdrawMessage(\n nonce,\n _amount\n );\n _sendMessage(message);\n\n // Emit WithdrawRequested event here,\n // Withdraw will be emitted in _onTokenReceived\n emit WithdrawRequested(usdcToken, _amount);\n }\n\n /**\n * @dev Process balance check:\n * - Confirms a deposit to the remote strategy\n * - Skips balance update if there's a pending withdrawal\n * - Updates the remote strategy balance\n * @param message The message containing the nonce and balance\n */\n function _processBalanceCheckMessage(bytes memory message)\n internal\n virtual\n {\n // Decode the message\n // When transferConfirmation is true, it means that the message is a result of a deposit or a withdrawal\n // process.\n (\n uint64 nonce,\n uint256 balance,\n bool transferConfirmation,\n uint256 timestamp\n ) = message.decodeBalanceCheckMessage();\n // Get the last cached nonce\n uint64 _lastCachedNonce = lastTransferNonce;\n\n if (nonce != _lastCachedNonce) {\n // If nonce is not the last cached nonce, it is an outdated message\n // Ignore it\n return;\n }\n\n // A received message nonce not yet processed indicates there is a\n // deposit or withdrawal in progress.\n bool transferInProgress = isTransferPending();\n\n if (transferInProgress) {\n if (transferConfirmation) {\n // Apply the effects of the deposit / withdrawal completion\n _markNonceAsProcessed(nonce);\n pendingAmount = 0;\n } else {\n // A balanceCheck arrived that is not part of the deposit / withdrawal process\n // that has been generated on the Remote contract after the deposit / withdrawal which is\n // still pending. This can happen when the CCTP bridge delivers the messages out of order.\n // Ignore it, since the pending deposit / withdrawal must first be cofirmed.\n emit BalanceCheckIgnored(nonce, timestamp, false);\n return;\n }\n } else {\n if (block.timestamp > timestamp + MAX_BALANCE_CHECK_AGE) {\n // Balance check is too old, ignore it\n emit BalanceCheckIgnored(nonce, timestamp, true);\n return;\n }\n }\n\n // At this point update the strategy balance the balanceCheck message is either:\n // - a confirmation of a deposit / withdrawal\n // - a message that updates balances when no deposit / withdrawal is in progress\n remoteStrategyBalance = balance;\n emit RemoteStrategyBalanceUpdated(balance);\n }\n}\n" + }, + "contracts/strategies/crosschain/CrossChainRemoteStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title CrossChainRemoteStrategy\n * @author Origin Protocol Inc\n *\n * @dev Part of the cross-chain strategy that lives on the remote chain.\n * Handles deposits and withdrawals from the master strategy on peer chain\n * and locally deposits the funds to a 4626 compatible vault.\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IERC4626 } from \"../../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IVaultV2 } from \"../../interfaces/morpho/IVaultV2.sol\";\nimport { Generalized4626Strategy } from \"../Generalized4626Strategy.sol\";\nimport { AbstractCCTPIntegrator } from \"./AbstractCCTPIntegrator.sol\";\nimport { CrossChainStrategyHelper } from \"./CrossChainStrategyHelper.sol\";\nimport { InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { Strategizable } from \"../../governance/Strategizable.sol\";\nimport { MorphoV2VaultUtils } from \"../MorphoV2VaultUtils.sol\";\n\ncontract CrossChainRemoteStrategy is\n AbstractCCTPIntegrator,\n Generalized4626Strategy,\n Strategizable\n{\n using SafeERC20 for IERC20;\n using CrossChainStrategyHelper for bytes;\n\n event DepositUnderlyingFailed(string reason);\n event WithdrawalFailed(uint256 amountRequested, uint256 amountAvailable);\n event WithdrawUnderlyingFailed(string reason);\n\n modifier onlyOperatorOrStrategistOrGovernor() {\n require(\n msg.sender == operator ||\n msg.sender == strategistAddr ||\n isGovernor(),\n \"Caller is not the Operator, Strategist or the Governor\"\n );\n _;\n }\n\n modifier onlyGovernorOrStrategist()\n override(InitializableAbstractStrategy, Strategizable) {\n require(\n msg.sender == strategistAddr || isGovernor(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n CCTPIntegrationConfig memory _cctpConfig\n )\n AbstractCCTPIntegrator(_cctpConfig)\n Generalized4626Strategy(_baseConfig, _cctpConfig.usdcToken)\n {\n require(usdcToken == address(assetToken), \"Token mismatch\");\n require(\n _baseConfig.platformAddress != address(0),\n \"Invalid platform address\"\n );\n // Vault address must always be address(0) for the remote strategy\n require(\n _baseConfig.vaultAddress == address(0),\n \"Invalid vault address\"\n );\n }\n\n /**\n * @dev Initialize the strategy implementation\n * @param _strategist Address of the strategist\n * @param _operator Address of the operator\n * @param _minFinalityThreshold Minimum finality threshold\n * @param _feePremiumBps Fee premium in basis points\n */\n function initialize(\n address _strategist,\n address _operator,\n uint16 _minFinalityThreshold,\n uint16 _feePremiumBps\n ) external virtual onlyGovernor initializer {\n _initialize(_operator, _minFinalityThreshold, _feePremiumBps);\n _setStrategistAddr(_strategist);\n\n address[] memory rewardTokens = new address[](0);\n address[] memory assets = new address[](1);\n address[] memory pTokens = new address[](1);\n\n assets[0] = address(usdcToken);\n pTokens[0] = address(platformAddress);\n\n InitializableAbstractStrategy._initialize(\n rewardTokens,\n assets,\n pTokens\n );\n }\n\n /// @inheritdoc Generalized4626Strategy\n function deposit(address _asset, uint256 _amount)\n external\n virtual\n override\n onlyGovernorOrStrategist\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /// @inheritdoc Generalized4626Strategy\n function depositAll()\n external\n virtual\n override\n onlyGovernorOrStrategist\n nonReentrant\n {\n _deposit(usdcToken, IERC20(usdcToken).balanceOf(address(this)));\n }\n\n /// @inheritdoc Generalized4626Strategy\n /// @dev Interface requires a recipient, but for compatibility it must be address(this).\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external virtual override onlyGovernorOrStrategist nonReentrant {\n _withdraw(_recipient, _asset, _amount);\n }\n\n /// @inheritdoc Generalized4626Strategy\n function withdrawAll()\n external\n virtual\n override\n onlyGovernorOrStrategist\n nonReentrant\n {\n IERC4626 platform = IERC4626(platformAddress);\n uint256 availableMorphoVault = MorphoV2VaultUtils.maxWithdrawableAssets(\n platformAddress,\n usdcToken\n );\n uint256 amountToWithdraw = Math.min(\n availableMorphoVault,\n platform.previewRedeem(platform.balanceOf(address(this)))\n );\n\n if (amountToWithdraw > 0) {\n _withdraw(address(this), usdcToken, amountToWithdraw);\n }\n }\n\n /// @inheritdoc AbstractCCTPIntegrator\n function _onMessageReceived(bytes memory payload) internal override {\n uint32 messageType = payload.getMessageType();\n if (messageType == CrossChainStrategyHelper.DEPOSIT_MESSAGE) {\n // Received when Master strategy sends tokens to the remote strategy\n // Do nothing because we receive acknowledgement with token transfer,\n // so _onTokenReceived will handle it\n } else if (messageType == CrossChainStrategyHelper.WITHDRAW_MESSAGE) {\n // Received when Master strategy requests a withdrawal\n _processWithdrawMessage(payload);\n } else {\n revert(\"Unknown message type\");\n }\n }\n\n /**\n * @dev Process deposit message from peer strategy\n * @param tokenAmount Amount of tokens received\n * @param feeExecuted Fee executed\n * @param payload Payload of the message\n */\n function _processDepositMessage(\n // solhint-disable-next-line no-unused-vars\n uint256 tokenAmount,\n // solhint-disable-next-line no-unused-vars\n uint256 feeExecuted,\n bytes memory payload\n ) internal virtual {\n (uint64 nonce, ) = payload.decodeDepositMessage();\n\n // Replay protection is part of the _markNonceAsProcessed function\n _markNonceAsProcessed(nonce);\n\n // Deposit everything we got, not just what was bridged\n uint256 balance = IERC20(usdcToken).balanceOf(address(this));\n\n // Underlying call to deposit funds can fail. It mustn't affect the overall\n // flow as confirmation message should still be sent.\n if (balance >= MIN_TRANSFER_AMOUNT) {\n _deposit(usdcToken, balance);\n }\n\n // Send balance check message to the peer strategy\n bytes memory message = CrossChainStrategyHelper\n .encodeBalanceCheckMessage(\n lastTransferNonce,\n checkBalance(usdcToken),\n true,\n block.timestamp\n );\n _sendMessage(message);\n }\n\n /**\n * @dev Deposit assets by converting them to shares\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal override {\n // By design, this function should not revert. Otherwise, it'd\n // not be able to process messages and might freeze the contracts\n // state. However these two require statements would never fail\n // in every function invoking this. The same kind of checks should\n // be enforced in all the calling functions for these two and any\n // other require statements added to this function.\n require(_amount > 0, \"Must deposit something\");\n require(_asset == address(usdcToken), \"Unexpected asset address\");\n\n // This call can fail, and the failure doesn't need to bubble up to the _processDepositMessage function\n // as the flow is not affected by the failure.\n\n try IERC4626(platformAddress).deposit(_amount, address(this)) {\n emit Deposit(_asset, address(shareToken), _amount);\n } catch Error(string memory reason) {\n emit DepositUnderlyingFailed(\n string(abi.encodePacked(\"Deposit failed: \", reason))\n );\n } catch (bytes memory lowLevelData) {\n emit DepositUnderlyingFailed(\n string(\n abi.encodePacked(\n \"Deposit failed: low-level call failed with data \",\n lowLevelData\n )\n )\n );\n }\n }\n\n /**\n * @dev Process withdrawal message from peer strategy\n * @param payload Payload of the message\n */\n function _processWithdrawMessage(bytes memory payload) internal virtual {\n (uint64 nonce, uint256 withdrawAmount) = payload\n .decodeWithdrawMessage();\n\n // Replay protection is part of the _markNonceAsProcessed function\n _markNonceAsProcessed(nonce);\n\n uint256 usdcBalance = IERC20(usdcToken).balanceOf(address(this));\n\n if (usdcBalance < withdrawAmount) {\n // Withdraw the missing funds from the remote strategy. This call can fail and\n // the failure doesn't bubble up to the _processWithdrawMessage function\n _withdraw(address(this), usdcToken, withdrawAmount - usdcBalance);\n\n // Update the possible increase in the balance on the contract.\n usdcBalance = IERC20(usdcToken).balanceOf(address(this));\n }\n\n // Check balance after withdrawal\n uint256 strategyBalance = checkBalance(usdcToken);\n\n // If there are some tokens to be sent AND the balance is sufficient\n // to satisfy the withdrawal request then send the funds to the peer strategy.\n // In case a direct withdraw(All) has previously been called\n // there is a possibility of USDC funds remaining on the contract.\n // A separate withdraw to extract or deposit to the Morpho vault needs to be\n // initiated from the peer Master strategy to utilise USDC funds.\n if (\n withdrawAmount >= MIN_TRANSFER_AMOUNT &&\n usdcBalance >= withdrawAmount\n ) {\n // The new balance on the contract needs to have USDC subtracted from it as\n // that will be withdrawn in the next step\n bytes memory message = CrossChainStrategyHelper\n .encodeBalanceCheckMessage(\n lastTransferNonce,\n strategyBalance - withdrawAmount,\n true,\n block.timestamp\n );\n _sendTokens(withdrawAmount, message);\n } else {\n // Contract either:\n // - only has small dust amount of USDC\n // - doesn't have sufficient funds to satisfy the withdrawal request\n // In both cases send the balance update message to the peer strategy.\n bytes memory message = CrossChainStrategyHelper\n .encodeBalanceCheckMessage(\n lastTransferNonce,\n strategyBalance,\n true,\n block.timestamp\n );\n _sendMessage(message);\n emit WithdrawalFailed(withdrawAmount, usdcBalance);\n }\n }\n\n /**\n * @dev Withdraw asset by burning shares\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal override {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient == address(this), \"Invalid recipient\");\n require(_asset == address(usdcToken), \"Unexpected asset address\");\n\n // This call can fail, and the failure doesn't need to bubble up to the _processWithdrawMessage function\n // as the flow is not affected by the failure.\n try\n // slither-disable-next-line unused-return\n IERC4626(platformAddress).withdraw(\n _amount,\n address(this),\n address(this)\n )\n {\n emit Withdrawal(_asset, address(shareToken), _amount);\n } catch Error(string memory reason) {\n emit WithdrawUnderlyingFailed(\n string(abi.encodePacked(\"Withdrawal failed: \", reason))\n );\n } catch (bytes memory lowLevelData) {\n emit WithdrawUnderlyingFailed(\n string(\n abi.encodePacked(\n \"Withdrawal failed: low-level call failed with data \",\n lowLevelData\n )\n )\n );\n }\n }\n\n /**\n * @dev Process token received message from peer strategy\n * @param tokenAmount Amount of tokens received\n * @param feeExecuted Fee executed\n * @param payload Payload of the message\n */\n function _onTokenReceived(\n uint256 tokenAmount,\n uint256 feeExecuted,\n bytes memory payload\n ) internal override {\n uint32 messageType = payload.getMessageType();\n\n require(\n messageType == CrossChainStrategyHelper.DEPOSIT_MESSAGE,\n \"Invalid message type\"\n );\n\n _processDepositMessage(tokenAmount, feeExecuted, payload);\n }\n\n /**\n * @dev Send balance update message to the peer strategy\n */\n function sendBalanceUpdate()\n external\n virtual\n onlyOperatorOrStrategistOrGovernor\n {\n uint256 balance = checkBalance(usdcToken);\n bytes memory message = CrossChainStrategyHelper\n .encodeBalanceCheckMessage(\n lastTransferNonce,\n balance,\n false,\n block.timestamp\n );\n _sendMessage(message);\n }\n\n /**\n * @notice Get the total asset value held in the platform and contract\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform and contract\n */\n function checkBalance(address _asset)\n public\n view\n override\n returns (uint256)\n {\n require(_asset == usdcToken, \"Unexpected asset address\");\n /**\n * Balance of USDC on the contract is counted towards the total balance, since a deposit\n * to the Morpho V2 might fail and the USDC might remain on this contract as a result of a\n * bridged transfer.\n */\n uint256 balanceOnContract = IERC20(usdcToken).balanceOf(address(this));\n\n IERC4626 platform = IERC4626(platformAddress);\n return\n platform.previewRedeem(platform.balanceOf(address(this))) +\n balanceOnContract;\n }\n}\n" + }, + "contracts/strategies/crosschain/CrossChainStrategyHelper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title CrossChainStrategyHelper\n * @author Origin Protocol Inc\n * @dev This library is used to encode and decode the messages for the cross-chain strategy.\n * It is used to ensure that the messages are valid and to get the message version and type.\n */\n\nimport { BytesHelper } from \"../../utils/BytesHelper.sol\";\n\nlibrary CrossChainStrategyHelper {\n using BytesHelper for bytes;\n\n uint32 public constant DEPOSIT_MESSAGE = 1;\n uint32 public constant WITHDRAW_MESSAGE = 2;\n uint32 public constant BALANCE_CHECK_MESSAGE = 3;\n\n uint32 public constant CCTP_MESSAGE_VERSION = 1;\n uint32 public constant ORIGIN_MESSAGE_VERSION = 1010;\n\n // CCTP Message Header fields\n // Ref: https://developers.circle.com/cctp/technical-guide#message-header\n uint8 private constant VERSION_INDEX = 0;\n uint8 private constant SOURCE_DOMAIN_INDEX = 4;\n uint8 private constant SENDER_INDEX = 44;\n uint8 private constant RECIPIENT_INDEX = 76;\n uint8 private constant MESSAGE_BODY_INDEX = 148;\n\n /**\n * @dev Get the message version from the message.\n * It should always be 4 bytes long,\n * starting from the 0th index.\n * @param message The message to get the version from\n * @return The message version\n */\n function getMessageVersion(bytes memory message)\n internal\n pure\n returns (uint32)\n {\n // uint32 bytes 0 to 4 is Origin message version\n // uint32 bytes 4 to 8 is Message type\n return message.extractUint32(0);\n }\n\n /**\n * @dev Get the message type from the message.\n * It should always be 4 bytes long,\n * starting from the 4th index.\n * @param message The message to get the type from\n * @return The message type\n */\n function getMessageType(bytes memory message)\n internal\n pure\n returns (uint32)\n {\n // uint32 bytes 0 to 4 is Origin message version\n // uint32 bytes 4 to 8 is Message type\n return message.extractUint32(4);\n }\n\n /**\n * @dev Verify the message version and type.\n * The message version should be the same as the Origin message version,\n * and the message type should be the same as the expected message type.\n * @param _message The message to verify\n * @param _type The expected message type\n */\n function verifyMessageVersionAndType(bytes memory _message, uint32 _type)\n internal\n pure\n {\n require(\n getMessageVersion(_message) == ORIGIN_MESSAGE_VERSION,\n \"Invalid Origin Message Version\"\n );\n require(getMessageType(_message) == _type, \"Invalid Message type\");\n }\n\n /**\n * @dev Get the message payload from the message.\n * The payload starts at the 8th byte.\n * @param message The message to get the payload from\n * @return The message payload\n */\n function getMessagePayload(bytes memory message)\n internal\n pure\n returns (bytes memory)\n {\n // uint32 bytes 0 to 4 is Origin message version\n // uint32 bytes 4 to 8 is Message type\n // Payload starts at byte 8\n return message.extractSlice(8, message.length);\n }\n\n /**\n * @dev Encode the deposit message.\n * The message version and type are always encoded in the message.\n * @param nonce The nonce of the deposit\n * @param depositAmount The amount of the deposit\n * @return The encoded deposit message\n */\n function encodeDepositMessage(uint64 nonce, uint256 depositAmount)\n internal\n pure\n returns (bytes memory)\n {\n return\n abi.encodePacked(\n ORIGIN_MESSAGE_VERSION,\n DEPOSIT_MESSAGE,\n abi.encode(nonce, depositAmount)\n );\n }\n\n /**\n * @dev Decode the deposit message.\n * The message version and type are verified in the message.\n * @param message The message to decode\n * @return The nonce and the amount of the deposit\n */\n function decodeDepositMessage(bytes memory message)\n internal\n pure\n returns (uint64, uint256)\n {\n verifyMessageVersionAndType(message, DEPOSIT_MESSAGE);\n\n (uint64 nonce, uint256 depositAmount) = abi.decode(\n getMessagePayload(message),\n (uint64, uint256)\n );\n return (nonce, depositAmount);\n }\n\n /**\n * @dev Encode the withdrawal message.\n * The message version and type are always encoded in the message.\n * @param nonce The nonce of the withdrawal\n * @param withdrawAmount The amount of the withdrawal\n * @return The encoded withdrawal message\n */\n function encodeWithdrawMessage(uint64 nonce, uint256 withdrawAmount)\n internal\n pure\n returns (bytes memory)\n {\n return\n abi.encodePacked(\n ORIGIN_MESSAGE_VERSION,\n WITHDRAW_MESSAGE,\n abi.encode(nonce, withdrawAmount)\n );\n }\n\n /**\n * @dev Decode the withdrawal message.\n * The message version and type are verified in the message.\n * @param message The message to decode\n * @return The nonce and the amount of the withdrawal\n */\n function decodeWithdrawMessage(bytes memory message)\n internal\n pure\n returns (uint64, uint256)\n {\n verifyMessageVersionAndType(message, WITHDRAW_MESSAGE);\n\n (uint64 nonce, uint256 withdrawAmount) = abi.decode(\n getMessagePayload(message),\n (uint64, uint256)\n );\n return (nonce, withdrawAmount);\n }\n\n /**\n * @dev Encode the balance check message.\n * The message version and type are always encoded in the message.\n * @param nonce The nonce of the balance check\n * @param balance The balance to check\n * @param transferConfirmation Indicates if the message is a transfer confirmation. This is true\n * when the message is a result of a deposit or a withdrawal.\n * @return The encoded balance check message\n */\n function encodeBalanceCheckMessage(\n uint64 nonce,\n uint256 balance,\n bool transferConfirmation,\n uint256 timestamp\n ) internal pure returns (bytes memory) {\n return\n abi.encodePacked(\n ORIGIN_MESSAGE_VERSION,\n BALANCE_CHECK_MESSAGE,\n abi.encode(nonce, balance, transferConfirmation, timestamp)\n );\n }\n\n /**\n * @dev Decode the balance check message.\n * The message version and type are verified in the message.\n * @param message The message to decode\n * @return The nonce, the balance and indicates if the message is a transfer confirmation\n */\n function decodeBalanceCheckMessage(bytes memory message)\n internal\n pure\n returns (\n uint64,\n uint256,\n bool,\n uint256\n )\n {\n verifyMessageVersionAndType(message, BALANCE_CHECK_MESSAGE);\n\n (\n uint64 nonce,\n uint256 balance,\n bool transferConfirmation,\n uint256 timestamp\n ) = abi.decode(\n getMessagePayload(message),\n (uint64, uint256, bool, uint256)\n );\n return (nonce, balance, transferConfirmation, timestamp);\n }\n\n /**\n * @dev Decode the CCTP message header\n * @param message Message to decode\n * @return version Version of the message\n * @return sourceDomainID Source domain ID\n * @return sender Sender of the message\n * @return recipient Recipient of the message\n * @return messageBody Message body\n */\n function decodeMessageHeader(bytes memory message)\n internal\n pure\n returns (\n uint32 version,\n uint32 sourceDomainID,\n address sender,\n address recipient,\n bytes memory messageBody\n )\n {\n version = message.extractUint32(VERSION_INDEX);\n sourceDomainID = message.extractUint32(SOURCE_DOMAIN_INDEX);\n // Address of MessageTransmitterV2 caller on source domain\n sender = message.extractAddress(SENDER_INDEX);\n // Address to handle message body on destination domain\n recipient = message.extractAddress(RECIPIENT_INDEX);\n messageBody = message.extractSlice(MESSAGE_BODY_INDEX, message.length);\n }\n}\n" + }, + "contracts/strategies/CurveAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Curve Automated Market Maker (AMO) Strategy\n * @notice AMO strategy for a Curve pool using an OToken.\n * @author Origin Protocol Inc\n */\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { ICurveStableSwapNG } from \"../interfaces/ICurveStableSwapNG.sol\";\nimport { ICurveLiquidityGaugeV6 } from \"../interfaces/ICurveLiquidityGaugeV6.sol\";\nimport { IBasicToken } from \"../interfaces/IBasicToken.sol\";\nimport { ICurveMinter } from \"../interfaces/ICurveMinter.sol\";\n\ncontract CurveAMOStrategy is InitializableAbstractStrategy {\n using SafeCast for uint256;\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n /**\n * @dev a threshold under which the contract no longer allows for the protocol to manually rebalance.\n * Guarding against a strategist / guardian being taken over and with multiple transactions\n * draining the protocol funds.\n */\n uint256 public constant SOLVENCY_THRESHOLD = 0.998 ether;\n\n // New immutable variables that must be set in the constructor\n /**\n * @notice Address of the hard asset (weth, usdt, usdc).\n */\n IERC20 public immutable hardAsset;\n\n /**\n * @notice Address of the OTOKEN token contract.\n */\n IERC20 public immutable oToken;\n\n /**\n * @notice Address of the LP (Liquidity Provider) token contract.\n */\n IERC20 public immutable lpToken;\n\n /**\n * @notice Address of the Curve StableSwap NG pool contract.\n */\n ICurveStableSwapNG public immutable curvePool;\n\n /**\n * @notice Address of the Curve X-Chain Liquidity Gauge contract.\n */\n ICurveLiquidityGaugeV6 public immutable gauge;\n\n /**\n * @notice Address of the Curve Minter contract.\n */\n ICurveMinter public immutable minter;\n\n /**\n * @notice Index of the OTOKEN and hardAsset in the Curve pool.\n */\n uint128 public immutable otokenCoinIndex;\n uint128 public immutable hardAssetCoinIndex;\n\n /**\n * @notice Decimals of the OTOKEN and hardAsset.\n */\n uint8 public immutable decimalsOToken;\n uint8 public immutable decimalsHardAsset;\n\n /**\n * @notice Maximum slippage allowed for adding/removing liquidity from the Curve pool.\n */\n uint256 public maxSlippage;\n\n event MaxSlippageUpdated(uint256 newMaxSlippage);\n\n /**\n * @dev Verifies that the caller is the Strategist.\n */\n modifier onlyStrategist() {\n require(\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n _;\n }\n\n /**\n * @dev Checks the Curve pool's balances have improved and the balances\n * have not tipped to the other side.\n * This modifier is only applied to functions that do a single sided add or remove.\n * The standard deposit function adds to both sides of the pool in a way that\n * the pool's balance is not worsened.\n * Withdrawals are proportional so doesn't change the pools asset balance.\n */\n modifier improvePoolBalance() {\n // Get the hard asset and OToken balances in the Curve pool\n uint256[] memory balancesBefore = curvePool.get_balances();\n // diff = hardAsset balance - OTOKEN balance\n int256 diffBefore = (\n balancesBefore[hardAssetCoinIndex].scaleBy(\n decimalsOToken,\n decimalsHardAsset\n )\n ).toInt256() - balancesBefore[otokenCoinIndex].toInt256();\n\n _;\n\n // Get the hard asset and OToken balances in the Curve pool\n uint256[] memory balancesAfter = curvePool.get_balances();\n // diff = hardAsset balance - OTOKEN balance\n int256 diffAfter = (\n balancesAfter[hardAssetCoinIndex].scaleBy(\n decimalsOToken,\n decimalsHardAsset\n )\n ).toInt256() - balancesAfter[otokenCoinIndex].toInt256();\n\n if (diffBefore == 0) {\n require(diffAfter == 0, \"Position balance is worsened\");\n } else if (diffBefore < 0) {\n // If the pool was originally imbalanced in favor of OTOKEN, then\n // we want to check that the pool is now more balanced\n require(diffAfter <= 0, \"OTokens overshot peg\");\n require(diffBefore < diffAfter, \"OTokens balance worse\");\n } else if (diffBefore > 0) {\n // If the pool was originally imbalanced in favor of hardAsset, then\n // we want to check that the pool is now more balanced\n require(diffAfter >= 0, \"Assets overshot peg\");\n require(diffAfter < diffBefore, \"Assets balance worse\");\n }\n }\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _otoken,\n address _hardAsset,\n address _gauge,\n address _minter\n ) InitializableAbstractStrategy(_baseConfig) {\n lpToken = IERC20(_baseConfig.platformAddress);\n curvePool = ICurveStableSwapNG(_baseConfig.platformAddress);\n minter = ICurveMinter(_minter);\n\n oToken = IERC20(_otoken);\n hardAsset = IERC20(_hardAsset);\n gauge = ICurveLiquidityGaugeV6(_gauge);\n decimalsHardAsset = IBasicToken(_hardAsset).decimals();\n decimalsOToken = IBasicToken(_otoken).decimals();\n\n (hardAssetCoinIndex, otokenCoinIndex) = curvePool.coins(0) == _hardAsset\n ? (0, 1)\n : (1, 0);\n require(\n curvePool.coins(otokenCoinIndex) == _otoken &&\n curvePool.coins(hardAssetCoinIndex) == _hardAsset,\n \"Invalid coin indexes\"\n );\n require(gauge.lp_token() == address(curvePool), \"Invalid pool\");\n }\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Curve strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Address of CRV\n * @param _maxSlippage Maximum slippage allowed for adding/removing liquidity from the Curve pool.\n */\n function initialize(\n address[] calldata _rewardTokenAddresses, // CRV\n uint256 _maxSlippage\n ) external onlyGovernor initializer {\n address[] memory pTokens = new address[](1);\n pTokens[0] = address(curvePool);\n\n address[] memory _assets = new address[](1);\n _assets[0] = address(hardAsset);\n\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n pTokens\n );\n\n _approveBase();\n _setMaxSlippage(_maxSlippage);\n }\n\n /***************************************\n Deposit\n ****************************************/\n\n /**\n * @notice Deposit hard asset into the Curve pool\n * @param _hardAsset Address of hard asset contract.\n * @param _amount Amount of hard asset to deposit.\n */\n function deposit(address _hardAsset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_hardAsset, _amount);\n }\n\n function _deposit(address _hardAsset, uint256 _hardAssetAmount) internal {\n require(_hardAssetAmount > 0, \"Must deposit something\");\n require(_hardAsset == address(hardAsset), \"Unsupported asset\");\n\n emit Deposit(_hardAsset, address(lpToken), _hardAssetAmount);\n uint256 scaledHardAssetAmount = _hardAssetAmount.scaleBy(\n decimalsOToken,\n decimalsHardAsset\n );\n\n // Get the asset and OToken balances in the Curve pool\n uint256[] memory balances = curvePool.get_balances();\n // safe to cast since min value is at least 0\n uint256 otokenToAdd = uint256(\n _max(\n 0,\n (\n balances[hardAssetCoinIndex].scaleBy(\n decimalsOToken,\n decimalsHardAsset\n )\n ).toInt256() +\n scaledHardAssetAmount.toInt256() -\n balances[otokenCoinIndex].toInt256()\n )\n );\n\n /* Add so much OTOKEN so that the pool ends up being balanced. And at minimum\n * add as much OTOKEN as hard asset and at maximum twice as much OTOKEN.\n */\n otokenToAdd = Math.max(otokenToAdd, scaledHardAssetAmount);\n otokenToAdd = Math.min(otokenToAdd, scaledHardAssetAmount * 2);\n\n /* Mint OTOKEN with a strategy that attempts to contribute to stability of OTOKEN/hardAsset pool. Try\n * to mint so much OTOKEN that after deployment of liquidity pool ends up being balanced.\n *\n * To manage unpredictability minimal OTOKEN minted will always be at least equal or greater\n * to hardAsset amount deployed. And never larger than twice the hardAsset amount deployed even if\n * it would have a further beneficial effect on pool stability.\n */\n IVault(vaultAddress).mintForStrategy(otokenToAdd);\n\n emit Deposit(address(oToken), address(lpToken), otokenToAdd);\n\n uint256[] memory _amounts = new uint256[](2);\n _amounts[hardAssetCoinIndex] = _hardAssetAmount;\n _amounts[otokenCoinIndex] = otokenToAdd;\n\n uint256 valueInLpTokens = (scaledHardAssetAmount + otokenToAdd)\n .divPrecisely(curvePool.get_virtual_price());\n uint256 minMintAmount = valueInLpTokens.mulTruncate(\n uint256(1e18) - maxSlippage\n );\n\n // Do the deposit to the Curve pool\n uint256 lpDeposited = curvePool.add_liquidity(_amounts, minMintAmount);\n require(lpDeposited >= minMintAmount, \"Min LP amount error\");\n\n // Deposit the Curve pool's LP tokens into the Curve gauge\n gauge.deposit(lpDeposited);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n }\n\n /**\n * @notice Deposit the strategy's entire balance of hardAsset into the Curve pool\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 balance = hardAsset.balanceOf(address(this));\n if (balance > 0) {\n _deposit(address(hardAsset), balance);\n }\n }\n\n /***************************************\n Withdraw\n ****************************************/\n\n /**\n * @notice Withdraw hardAsset and OTOKEN from the Curve pool, burn the OTOKEN,\n * transfer hardAsset to the recipient.\n * @param _recipient Address to receive withdrawn asset which is normally the Vault.\n * @param _hardAsset Address of the hardAsset contract.\n * @param _amount Amount of hardAsset to withdraw.\n */\n function withdraw(\n address _recipient,\n address _hardAsset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(\n _hardAsset == address(hardAsset),\n \"Can only withdraw hard asset\"\n );\n\n emit Withdrawal(_hardAsset, address(lpToken), _amount);\n\n uint256 requiredLpTokens = calcTokenToBurn(\n _amount.scaleBy(decimalsOToken, decimalsHardAsset)\n );\n\n _lpWithdraw(requiredLpTokens);\n\n /* math in requiredLpTokens should correctly calculate the amount of LP to remove\n * in that the strategy receives enough hardAsset on balanced removal\n */\n uint256[] memory _minWithdrawalAmounts = new uint256[](2);\n _minWithdrawalAmounts[hardAssetCoinIndex] = _amount;\n // slither-disable-next-line unused-return\n curvePool.remove_liquidity(requiredLpTokens, _minWithdrawalAmounts);\n\n // Burn all the removed OTOKEN and any that was left in the strategy\n uint256 otokenToBurn = oToken.balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(otokenToBurn);\n\n emit Withdrawal(address(oToken), address(lpToken), otokenToBurn);\n\n // Transfer hardAsset to the recipient\n hardAsset.safeTransfer(_recipient, _amount);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n }\n\n function calcTokenToBurn(uint256 _hardAssetAmount)\n internal\n view\n returns (uint256 lpToBurn)\n {\n /* The rate between coins in the pool determines the rate at which pool returns\n * tokens when doing balanced removal (remove_liquidity call). And by knowing how much hardAsset\n * we want we can determine how much of OTOKEN we receive by removing liquidity.\n *\n * Because we are doing balanced removal we should be making profit when removing liquidity in a\n * pool tilted to either side.\n *\n * Important: A downside is that the Strategist / Governor needs to be\n * cognisant of not removing too much liquidity. And while the proposal to remove liquidity\n * is being voted on the pool tilt might change so much that the proposal that has been valid while\n * created is no longer valid.\n */\n\n uint256 poolHardAssetBalance = curvePool\n .balances(hardAssetCoinIndex)\n .scaleBy(decimalsOToken, decimalsHardAsset);\n /* K is multiplied by 1e36 which is used for higher precision calculation of required\n * pool LP tokens. Without it the end value can have rounding errors up to precision of\n * 10 digits. This way we move the decimal point by 36 places when doing the calculation\n * and again by 36 places when we are done with it.\n */\n uint256 k = (1e36 * lpToken.totalSupply()) / poolHardAssetBalance;\n // prettier-ignore\n // slither-disable-next-line divide-before-multiply\n uint256 diff = (_hardAssetAmount + 1) * k;\n lpToBurn = diff / 1e36;\n }\n\n /**\n * @notice Remove all hardAsset and OTOKEN from the Curve pool, burn the OTOKEN,\n * transfer hardAsset to the Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 gaugeTokens = gauge.balanceOf(address(this));\n _lpWithdraw(gaugeTokens);\n\n // Withdraws are proportional to assets held by 3Pool\n uint256[] memory minWithdrawAmounts = new uint256[](2);\n\n // Check balance of LP tokens in the strategy, if 0 return\n uint256 lpBalance = lpToken.balanceOf(address(this));\n\n // Remove liquidity\n // slither-disable-next-line unused-return\n if (lpBalance > 0) {\n curvePool.remove_liquidity(lpBalance, minWithdrawAmounts);\n }\n\n // Burn all OTOKEN\n uint256 otokenToBurn = oToken.balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(otokenToBurn);\n\n // Get the strategy contract's hardAsset balance.\n // This includes all that was removed from the Curve pool and\n // any hardAsset that was sitting in the strategy contract before the removal.\n uint256 hardAssetBalance = hardAsset.balanceOf(address(this));\n hardAsset.safeTransfer(vaultAddress, hardAssetBalance);\n\n if (hardAssetBalance > 0)\n emit Withdrawal(\n address(hardAsset),\n address(lpToken),\n hardAssetBalance\n );\n if (otokenToBurn > 0)\n emit Withdrawal(address(oToken), address(lpToken), otokenToBurn);\n }\n\n /***************************************\n Curve pool Rebalancing\n ****************************************/\n\n /**\n * @notice Mint OTokens and one-sided add to the Curve pool.\n * This is used when the Curve pool does not have enough OTokens and too many hardAsset.\n * The OToken/Asset, eg OTOKEN/hardAsset, price with increase.\n * The amount of assets in the vault is unchanged.\n * The total supply of OTokens is increased.\n * The asset value of the strategy and vault is increased.\n * @param _oTokens The amount of OTokens to be minted and added to the pool.\n */\n function mintAndAddOTokens(uint256 _oTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n IVault(vaultAddress).mintForStrategy(_oTokens);\n\n uint256[] memory amounts = new uint256[](2);\n amounts[otokenCoinIndex] = _oTokens;\n\n // Convert OTOKEN to Curve pool LP tokens\n uint256 valueInLpTokens = (_oTokens).divPrecisely(\n curvePool.get_virtual_price()\n );\n // Apply slippage to LP tokens\n uint256 minMintAmount = valueInLpTokens.mulTruncate(\n uint256(1e18) - maxSlippage\n );\n\n // Add the minted OTokens to the Curve pool\n uint256 lpDeposited = curvePool.add_liquidity(amounts, minMintAmount);\n require(lpDeposited >= minMintAmount, \"Min LP amount error\");\n\n // Deposit the Curve pool LP tokens to the Curve gauge\n gauge.deposit(lpDeposited);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Deposit(address(oToken), address(lpToken), _oTokens);\n }\n\n /**\n * @notice One-sided remove of OTokens from the Curve pool which are then burned.\n * This is used when the Curve pool has too many OTokens and not enough hardAsset.\n * The amount of assets in the vault is unchanged.\n * The total supply of OTokens is reduced.\n * The asset value of the strategy and vault is reduced.\n * @param _lpTokens The amount of Curve pool LP tokens to be burned for OTokens.\n */\n function removeAndBurnOTokens(uint256 _lpTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n // Withdraw Curve pool LP tokens from gauge and remove OTokens from the Curve pool\n uint256 otokenToBurn = _withdrawAndRemoveFromPool(\n _lpTokens,\n otokenCoinIndex\n );\n\n // The vault burns the OTokens from this strategy\n IVault(vaultAddress).burnForStrategy(otokenToBurn);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Withdrawal(address(oToken), address(lpToken), otokenToBurn);\n }\n\n /**\n * @notice One-sided remove of hardAsset from the Curve pool and transfer to the vault.\n * This is used when the Curve pool does not have enough OTokens and too many hardAsset.\n * The OToken/Asset, eg OTOKEN/hardAsset, price with decrease.\n * The amount of assets in the vault increases.\n * The total supply of OTokens does not change.\n * The asset value of the strategy reduces.\n * The asset value of the vault should be close to the same.\n * @param _lpTokens The amount of Curve pool LP tokens to be burned for hardAsset.\n * @dev Curve pool LP tokens is used rather than hardAsset assets as Curve does not\n * have a way to accurately calculate the amount of LP tokens for a required\n * amount of hardAsset. Curve's `calc_token_amount` function does not include fees.\n * A 3rd party library can be used that takes into account the fees, but this\n * is a gas intensive process. It's easier for the trusted strategist to\n * calculate the amount of Curve pool LP tokens required off-chain.\n */\n function removeOnlyAssets(uint256 _lpTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n // Withdraw Curve pool LP tokens from Curve gauge and remove hardAsset from the Curve pool\n uint256 hardAssetAmount = _withdrawAndRemoveFromPool(\n _lpTokens,\n hardAssetCoinIndex\n );\n\n // Transfer hardAsset to the vault\n hardAsset.safeTransfer(vaultAddress, hardAssetAmount);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Withdrawal(address(hardAsset), address(lpToken), hardAssetAmount);\n }\n\n /**\n * @dev Remove Curve pool LP tokens from the gauge and\n * do a one-sided remove of hardAsset or OTOKEN from the Curve pool.\n * @param _lpTokens The amount of Curve pool LP tokens to be removed from the gauge\n * @param coinIndex The index of the coin to be removed from the Curve pool. 0 = hardAsset, 1 = OTOKEN.\n * @return coinsRemoved The amount of hardAsset or OTOKEN removed from the Curve pool.\n */\n function _withdrawAndRemoveFromPool(uint256 _lpTokens, uint128 coinIndex)\n internal\n returns (uint256 coinsRemoved)\n {\n // Withdraw Curve pool LP tokens from Curve gauge\n _lpWithdraw(_lpTokens);\n\n // Convert Curve pool LP tokens to hardAsset value\n uint256 valueInEth = _lpTokens.mulTruncate(\n curvePool.get_virtual_price()\n );\n\n if (coinIndex == hardAssetCoinIndex) {\n valueInEth = valueInEth.scaleBy(decimalsHardAsset, decimalsOToken);\n }\n\n // Apply slippage to hardAsset value\n uint256 minAmount = valueInEth.mulTruncate(uint256(1e18) - maxSlippage);\n\n // Remove just the hardAsset from the Curve pool\n coinsRemoved = curvePool.remove_liquidity_one_coin(\n _lpTokens,\n int128(coinIndex),\n minAmount,\n address(this)\n );\n }\n\n /**\n * Checks that the protocol is solvent, protecting from a rogue Strategist / Guardian that can\n * keep rebalancing the pool in both directions making the protocol lose a tiny amount of\n * funds each time.\n *\n * Protocol must be at least SOLVENCY_THRESHOLD (99,8 %) backed in order for the rebalances to\n * function.\n */\n function _solvencyAssert() internal view {\n uint256 _totalVaultValue = IVault(vaultAddress).totalValue();\n uint256 _totalOtokenSupply = oToken.totalSupply();\n\n if (\n _totalVaultValue.divPrecisely(_totalOtokenSupply) <\n SOLVENCY_THRESHOLD\n ) {\n revert(\"Protocol insolvent\");\n }\n }\n\n /***************************************\n Assets and Rewards\n ****************************************/\n\n /**\n * @notice Collect accumulated CRV (and other) rewards and send to the Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvesterOrStrategist\n nonReentrant\n {\n // Collect CRV rewards from inflation\n minter.mint(address(gauge));\n\n // Collect extra gauge rewards (outside of CRV)\n gauge.claim_rewards();\n\n _collectRewardTokens();\n }\n\n function _lpWithdraw(uint256 _lpAmount) internal {\n require(\n gauge.balanceOf(address(this)) >= _lpAmount,\n \"Insufficient LP tokens\"\n );\n // withdraw lp tokens from the gauge without claiming rewards\n gauge.withdraw(_lpAmount);\n }\n\n /**\n * @notice Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == address(hardAsset), \"Unsupported asset\");\n\n // hardAsset balance needed here for the balance check that happens from vault during depositing.\n balance = hardAsset.balanceOf(address(this));\n uint256 lpTokens = gauge.balanceOf(address(this));\n if (lpTokens > 0) {\n balance += ((lpTokens * curvePool.get_virtual_price()) / 1e18)\n .scaleBy(decimalsHardAsset, decimalsOToken);\n }\n }\n\n /**\n * @notice Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == address(hardAsset);\n }\n\n /***************************************\n Approvals\n ****************************************/\n\n /**\n * @notice Sets the maximum slippage allowed for any swap/liquidity operation\n * @param _maxSlippage Maximum slippage allowed, 1e18 = 100%.\n */\n function setMaxSlippage(uint256 _maxSlippage) external onlyGovernor {\n _setMaxSlippage(_maxSlippage);\n }\n\n function _setMaxSlippage(uint256 _maxSlippage) internal {\n require(_maxSlippage <= 5e16, \"Slippage must be less than 100%\");\n maxSlippage = _maxSlippage;\n emit MaxSlippageUpdated(_maxSlippage);\n }\n\n /**\n * @notice Approve the spending of all assets by their corresponding pool tokens,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n _approveBase();\n }\n\n /**\n * @dev Since we are unwrapping WETH before depositing it to Curve\n * there is no need to set an approval for WETH on the Curve\n * pool\n * @param _asset Address of the asset\n * @param _pToken Address of the Curve LP token\n */\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {}\n\n function _approveBase() internal {\n // Approve Curve pool for OTOKEN (required for adding liquidity)\n // slither-disable-next-line unused-return\n oToken.approve(platformAddress, type(uint256).max);\n\n // Approve Curve pool for hardAsset (required for adding liquidity)\n // slither-disable-next-line unused-return\n hardAsset.safeApprove(platformAddress, type(uint256).max);\n\n // Approve Curve gauge contract to transfer Curve pool LP tokens\n // This is needed for deposits if Curve pool LP tokens into the Curve gauge.\n // slither-disable-next-line unused-return\n lpToken.approve(address(gauge), type(uint256).max);\n }\n\n /**\n * @dev Returns the largest of two numbers int256 version\n */\n function _max(int256 a, int256 b) internal pure returns (int256) {\n return a >= b ? a : b;\n }\n}\n" + }, + "contracts/strategies/Generalized4626Strategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Generalized 4626 Strategy\n * @notice Investment strategy for ERC-4626 Tokenized Vaults\n * @dev This strategy should not be used for the Morpho V2 Vaults as those are not\n * completley ERC-4626 compliant - they don't implement the maxWithdraw() and\n * maxRedeem() functions and rather return 0 when any of them is called.\n * @author Origin Protocol Inc\n */\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { IDistributor } from \"../interfaces/IMerkl.sol\";\n\ncontract Generalized4626Strategy is InitializableAbstractStrategy {\n /// @notice The address of the Merkle Distributor contract.\n IDistributor public constant merkleDistributor =\n IDistributor(0x3Ef3D8bA38EBe18DB133cEc108f4D14CE00Dd9Ae);\n\n /// @dev Replaced with an immutable variable\n // slither-disable-next-line constable-states\n address private _deprecate_shareToken;\n /// @dev Replaced with an immutable variable\n // slither-disable-next-line constable-states\n address private _deprecate_assetToken;\n\n IERC20 public immutable shareToken;\n IERC20 public immutable assetToken;\n\n // For future use\n uint256[50] private __gap;\n\n event ClaimedRewards(address indexed token, uint256 amount);\n\n /**\n * @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI,\n * and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\n * @param _assetToken Address of the ERC-4626 asset token. eg frxETH or DAI\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _assetToken)\n InitializableAbstractStrategy(_baseConfig)\n {\n shareToken = IERC20(_baseConfig.platformAddress);\n assetToken = IERC20(_assetToken);\n }\n\n function initialize() external virtual onlyGovernor initializer {\n address[] memory rewardTokens = new address[](0);\n address[] memory assets = new address[](1);\n address[] memory pTokens = new address[](1);\n\n assets[0] = address(assetToken);\n pTokens[0] = address(platformAddress);\n\n InitializableAbstractStrategy._initialize(\n rewardTokens,\n assets,\n pTokens\n );\n }\n\n /**\n * @dev Deposit assets by converting them to shares\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n virtual\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /**\n * @dev Deposit assets by converting them to shares\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal virtual {\n require(_amount > 0, \"Must deposit something\");\n require(_asset == address(assetToken), \"Unexpected asset address\");\n\n // slither-disable-next-line unused-return\n IERC4626(platformAddress).deposit(_amount, address(this));\n emit Deposit(_asset, address(shareToken), _amount);\n }\n\n /**\n * @dev Deposit the entire balance of assetToken to gain shareToken\n */\n function depositAll() external virtual override onlyVault nonReentrant {\n uint256 balance = assetToken.balanceOf(address(this));\n if (balance > 0) {\n _deposit(address(assetToken), balance);\n }\n }\n\n /**\n * @dev Withdraw asset by burning shares\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external virtual override onlyVault nonReentrant {\n _withdraw(_recipient, _asset, _amount);\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal virtual {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n require(_asset == address(assetToken), \"Unexpected asset address\");\n\n // slither-disable-next-line unused-return\n IERC4626(platformAddress).withdraw(_amount, _recipient, address(this));\n emit Withdrawal(_asset, address(shareToken), _amount);\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset / share tokens\n */\n function _abstractSetPToken(address, address) internal virtual override {\n _approveBase();\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll()\n external\n virtual\n override\n onlyVaultOrGovernor\n nonReentrant\n {\n // @dev Don't use for Morpho V2 Vaults as below line will return 0\n uint256 sharesToRedeem = IERC4626(platformAddress).maxRedeem(\n address(this)\n );\n\n uint256 assetAmount = 0;\n if (sharesToRedeem > 0) {\n assetAmount = IERC4626(platformAddress).redeem(\n sharesToRedeem,\n vaultAddress,\n address(this)\n );\n emit Withdrawal(\n address(assetToken),\n address(shareToken),\n assetAmount\n );\n }\n }\n\n /**\n * @notice Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n public\n view\n virtual\n override\n returns (uint256 balance)\n {\n require(_asset == address(assetToken), \"Unexpected asset address\");\n /* We are intentionally not counting the amount of assetToken parked on the\n * contract toward the checkBalance. The deposit and withdraw functions\n * should not result in assetToken being unused and owned by this strategy\n * contract.\n */\n IERC4626 platform = IERC4626(platformAddress);\n return platform.previewRedeem(platform.balanceOf(address(this)));\n }\n\n /**\n * @notice Governor approves the ERC-4626 Tokenized Vault to spend the asset.\n */\n function safeApproveAllTokens() external override onlyGovernor {\n _approveBase();\n }\n\n function _approveBase() internal virtual {\n // Approval the asset to be transferred to the ERC-4626 Tokenized Vault.\n // Used by the ERC-4626 deposit() and mint() functions\n // slither-disable-next-line unused-return\n assetToken.approve(platformAddress, type(uint256).max);\n }\n\n /**\n * @dev Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset)\n public\n view\n virtual\n override\n returns (bool)\n {\n return _asset == address(assetToken);\n }\n\n /**\n * @notice is not supported for this strategy as the asset and\n * ERC-4626 Tokenized Vault are set at deploy time.\n * @dev If the ERC-4626 Tokenized Vault needed to be changed, a new\n * contract would need to be deployed and the proxy updated.\n */\n function setPTokenAddress(address, address) external override onlyGovernor {\n revert(\"unsupported function\");\n }\n\n /**\n * @notice is not supported for this strategy as the asset and\n * ERC-4626 Tokenized Vault are set at deploy time.\n * @dev If the ERC-4626 Tokenized Vault needed to be changed, a new\n * contract would need to be deployed and the proxy updated.\n */\n function removePToken(uint256) external override onlyGovernor {\n revert(\"unsupported function\");\n }\n\n /// @notice Claim tokens from the Merkle Distributor\n /// @param token The address of the token to claim.\n /// @param amount The amount of tokens to claim.\n /// @param proof The Merkle proof to validate the claim.\n function merkleClaim(\n address token,\n uint256 amount,\n bytes32[] calldata proof\n ) external {\n address[] memory users = new address[](1);\n users[0] = address(this);\n\n address[] memory tokens = new address[](1);\n tokens[0] = token;\n\n uint256[] memory amounts = new uint256[](1);\n amounts[0] = amount;\n\n bytes32[][] memory proofs = new bytes32[][](1);\n proofs[0] = proof;\n\n merkleDistributor.claim(users, tokens, amounts, proofs);\n\n emit ClaimedRewards(token, amount);\n }\n}\n" + }, + "contracts/strategies/hydrex/OETHbHydrexAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OETHb Hydrex Algorithmic Market Maker (AMO) Strategy\n * @notice AMO strategy for the Hydrex superOETHb/WETH stable pool on Base\n * @author Origin Protocol Inc\n */\nimport { StableSwapAMMStrategy } from \"../algebra/StableSwapAMMStrategy.sol\";\nimport { IHydrexGauge } from \"../../interfaces/hydrex/IHydrexGauge.sol\";\n\ncontract OETHbHydrexAMOStrategy is StableSwapAMMStrategy {\n /**\n * @param _baseConfig The `platformAddress` is the address of the Hydrex superOETHb/WETH pool.\n * The `vaultAddress` is the address of the OETHBase Vault.\n * @param _gauge Address of the Hydrex gauge for the pool. Hydrex GaugeV2\n * (>= v2.5) renamed `TOKEN()` to `stakeToken()`, which is what we\n * resolve here and forward to the parent.\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _gauge)\n StableSwapAMMStrategy(\n _baseConfig,\n _gauge,\n IHydrexGauge(_gauge).stakeToken()\n )\n {}\n}\n" + }, + "contracts/strategies/ICurvePool.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface ICurvePool {\n function get_virtual_price() external view returns (uint256);\n\n function add_liquidity(uint256[3] calldata _amounts, uint256 _min) external;\n\n function balances(uint256) external view returns (uint256);\n\n function calc_token_amount(uint256[3] calldata _amounts, bool _deposit)\n external\n returns (uint256);\n\n function fee() external view returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _amount,\n int128 _index,\n uint256 _minAmount\n ) external;\n\n function remove_liquidity(\n uint256 _amount,\n uint256[3] calldata _minWithdrawAmounts\n ) external;\n\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n external\n view\n returns (uint256);\n\n function exchange(\n uint256 i,\n uint256 j,\n uint256 dx,\n uint256 min_dy\n ) external returns (uint256);\n\n function coins(uint256 _index) external view returns (address);\n\n function remove_liquidity_imbalance(\n uint256[3] calldata _amounts,\n uint256 maxBurnAmount\n ) external;\n}\n" + }, + "contracts/strategies/MorphoV2Strategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Generalized 4626 Strategy when the underlying platform is Morpho V2\n * @notice Investment strategy for ERC-4626 Tokenized Vaults for the Morpho V2 platform.\n * @author Origin Protocol Inc\n */\nimport { Generalized4626Strategy } from \"./Generalized4626Strategy.sol\";\nimport { MorphoV2VaultUtils } from \"./MorphoV2VaultUtils.sol\";\nimport { IVaultV2 } from \"../interfaces/morpho/IVaultV2.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\ncontract MorphoV2Strategy is Generalized4626Strategy {\n /**\n * @param _baseConfig Base strategy config with Morpho V2 Vault and\n * vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\n * @param _assetToken Address of the ERC-4626 asset token. e.g. USDC\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _assetToken)\n Generalized4626Strategy(_baseConfig, _assetToken)\n {}\n\n /**\n * @notice Remove all the liquidity that is available in the Morpho V2 vault.\n * Which might not be all of the liquidity owned by the strategy.\n * @dev Remove all the liquidity that is available in the Morpho V2 vault\n * The particular behaviour of the Morpho V2 vault is that it can hold\n * multiple Morpho V1 vaults as adapters but only one liquidity adapter.\n * The immediate available funds on the Morpho V2 vault are therfore any\n * liquid assets residing on the Vault V2 contract and the maxWithdraw\n * amount that the Morpho V1 contract can supply.\n */\n function withdrawAll()\n external\n virtual\n override\n onlyVaultOrGovernor\n nonReentrant\n {\n uint256 availableMorphoVault = _maxWithdraw();\n uint256 balanceToWithdraw = Math.min(\n availableMorphoVault,\n checkBalance(address(assetToken))\n );\n\n if (balanceToWithdraw > 0) {\n // slither-disable-next-line unused-return\n IVaultV2(platformAddress).withdraw(\n balanceToWithdraw,\n vaultAddress,\n address(this)\n );\n }\n\n emit Withdrawal(\n address(assetToken),\n address(shareToken),\n balanceToWithdraw\n );\n }\n\n function maxWithdraw() external view returns (uint256) {\n return _maxWithdraw();\n }\n\n function _maxWithdraw()\n internal\n view\n returns (uint256 availableAssetLiquidity)\n {\n availableAssetLiquidity = MorphoV2VaultUtils.maxWithdrawableAssets(\n platformAddress,\n address(assetToken)\n );\n }\n}\n" + }, + "contracts/strategies/MorphoV2VaultUtils.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IVaultV2 } from \"../interfaces/morpho/IVaultV2.sol\";\nimport { IMorphoV2Adapter } from \"../interfaces/morpho/IMorphoV2Adapter.sol\";\n\nlibrary MorphoV2VaultUtils {\n error IncompatibleAdapter(address adapter);\n\n /**\n * @notice Return maximum amount that can be safely withdrawn from a Morpho V2 vault.\n * @dev Available liquidity is:\n * 1) asset balance parked on Morpho V2 vault contract\n * 2) additional liquidity from the active adapter if it resolves to a Morpho V1 vault\n * and, when provided, matches the expected adapter\n */\n function maxWithdrawableAssets(address platformAddress, address assetToken)\n internal\n view\n returns (uint256 availableAssetLiquidity)\n {\n availableAssetLiquidity = IERC20(assetToken).balanceOf(platformAddress);\n\n address liquidityAdapter = IVaultV2(platformAddress).liquidityAdapter();\n // this is a sufficient check to ensure the adapter is Morpho V1\n try IMorphoV2Adapter(liquidityAdapter).morphoVaultV1() returns (\n address underlyingVault\n ) {\n availableAssetLiquidity += IERC4626(underlyingVault).maxWithdraw(\n liquidityAdapter\n );\n } catch {\n revert IncompatibleAdapter(liquidityAdapter);\n }\n }\n}\n" + }, + "contracts/strategies/NativeStaking/CompoundingStakingSSVStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { CompoundingValidatorManager } from \"./CompoundingValidatorManager.sol\";\n\n/// @title Compounding Staking SSV Strategy\n/// @notice Strategy to deploy funds into DVT validators powered by the SSV Network\n/// @author Origin Protocol Inc\ncontract CompoundingStakingSSVStrategy is\n CompoundingValidatorManager,\n InitializableAbstractStrategy\n{\n // For future use\n uint256[50] private __gap;\n\n /// @param _baseConfig Base strategy config with\n /// `platformAddress` not used so empty address\n /// `vaultAddress` the address of the OETH Vault contract\n /// @param _wethAddress Address of the WETH Token contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _beaconProofs Address of the Beacon Proofs contract that verifies beacon chain data\n /// @param _beaconGenesisTimestamp The timestamp of the Beacon chain's genesis.\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _wethAddress,\n address _ssvNetwork,\n address _beaconChainDepositContract,\n address _beaconProofs,\n uint64 _beaconGenesisTimestamp\n )\n InitializableAbstractStrategy(_baseConfig)\n CompoundingValidatorManager(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork,\n _beaconProofs,\n _beaconGenesisTimestamp\n )\n {\n // Make sure nobody owns the implementation contract\n _setGovernor(address(0));\n }\n\n /// @notice Set up initial internal state including\n /// 1. approving the SSVNetwork to transfer SSV tokens from this strategy contract\n /// @param _rewardTokenAddresses Not used so empty array\n /// @param _assets Not used so empty array\n /// @param _pTokens Not used so empty array\n function initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n }\n\n /// @notice Unlike other strategies, this does not deposit assets into the underlying platform.\n /// It just checks the asset is WETH and emits the Deposit event.\n /// To deposit WETH into validators, `registerSsvValidator` and `stakeEth` must be used.\n /// @param _asset Address of the WETH token.\n /// @param _amount Amount of WETH that was transferred to the strategy by the vault.\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n require(_asset == WETH, \"Unsupported asset\");\n require(_amount > 0, \"Must deposit something\");\n\n // Account for the new WETH\n depositedWethAccountedFor += _amount;\n\n emit Deposit(_asset, address(0), _amount);\n }\n\n /// @notice Unlike other strategies, this does not deposit assets into the underlying platform.\n /// It just emits the Deposit event.\n /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used.\n function depositAll() external override onlyVault nonReentrant {\n uint256 wethBalance = IERC20(WETH).balanceOf(address(this));\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\n\n if (newWeth > 0) {\n // Account for the new WETH\n depositedWethAccountedFor = wethBalance;\n\n emit Deposit(WETH, address(0), newWeth);\n }\n }\n\n /// @notice Withdraw ETH and WETH from this strategy contract.\n /// @param _recipient Address to receive withdrawn assets.\n /// @param _asset Address of the WETH token.\n /// @param _amount Amount of WETH to withdraw.\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override nonReentrant {\n require(_asset == WETH, \"Unsupported asset\");\n require(\n msg.sender == vaultAddress || msg.sender == validatorRegistrator,\n \"Caller not Vault or Registrator\"\n );\n\n _withdraw(_recipient, _amount, address(this).balance);\n }\n\n function _withdraw(\n address _recipient,\n uint256 _withdrawAmount,\n uint256 _ethBalance\n ) internal {\n require(_withdrawAmount > 0, \"Must withdraw something\");\n require(_recipient == vaultAddress, \"Recipient not Vault\");\n\n // Convert any ETH from validator partial withdrawals, exits\n // or execution rewards to WETH and do the necessary accounting.\n if (_ethBalance > 0) _convertEthToWeth(_ethBalance);\n\n // Transfer WETH to the recipient and do the necessary accounting.\n _transferWeth(_withdrawAmount, _recipient);\n\n emit Withdrawal(WETH, address(0), _withdrawAmount);\n }\n\n /// @notice Transfer all WETH deposits, ETH from validator withdrawals and ETH from\n /// execution rewards in this strategy to the vault.\n /// This does not withdraw from the validators. That has to be done separately with the\n /// `validatorWithdrawal` operation.\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 ethBalance = address(this).balance;\n uint256 withdrawAmount = IERC20(WETH).balanceOf(address(this)) +\n ethBalance;\n\n if (withdrawAmount > 0) {\n _withdraw(vaultAddress, withdrawAmount, ethBalance);\n }\n }\n\n /// @notice Accounts for all the assets managed by this strategy which includes:\n /// 1. The current WETH in this strategy contract\n /// 2. The last verified ETH balance, total deposits and total validator balances\n /// @param _asset Address of WETH asset.\n /// @return balance Total value in ETH\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == WETH, \"Unsupported asset\");\n\n // Load the last verified balance from the storage\n // and add to the latest WETH balance of this strategy.\n balance =\n lastVerifiedEthBalance +\n IWETH9(WETH).balanceOf(address(this));\n }\n\n /// @notice Returns bool indicating whether asset is supported by the strategy.\n /// @param _asset The address of the WETH token.\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == WETH;\n }\n\n /// @notice Does nothing but needed as this function is abstract on InitializableAbstractStrategy\n /// @dev Use to be used to approve SSV tokens but that is no longer used by the SSV Network.\n function safeApproveAllTokens() public override {}\n\n /**\n * @notice We can accept ETH directly to this contract from anyone as it does not impact our accounting\n * like it did in the legacy NativeStakingStrategy.\n * The new ETH will be accounted for in `checkBalance` after the next snapBalances and verifyBalances txs.\n */\n receive() external payable {}\n\n /***************************************\n Internal functions\n ****************************************/\n\n /// @notice is not supported for this strategy as there is no platform token.\n function setPTokenAddress(address, address) external pure override {\n revert(\"Unsupported function\");\n }\n\n /// @notice is not supported for this strategy as there is no platform token.\n function removePToken(uint256) external pure override {\n revert(\"Unsupported function\");\n }\n\n /// @dev This strategy does not use a platform token like the old Aave and Compound strategies.\n function _abstractSetPToken(address _asset, address) internal override {}\n\n /// @dev Consensus rewards are compounded to the validator's balance instead of being\n /// swept to this strategy contract.\n /// Execution rewards from MEV and tx priority accumulate as ETH in this strategy contract.\n /// Withdrawals from validators also accumulate as ETH in this strategy contract.\n /// It's too complex to separate the rewards from withdrawals so this function is not implemented.\n /// Besides, ETH rewards are not sent to the Dripper any more. The Vault can now regulate\n /// the increase in assets.\n function _collectRewardTokens() internal pure override {\n revert(\"Unsupported function\");\n }\n}\n" + }, + "contracts/strategies/NativeStaking/CompoundingValidatorManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { Governable } from \"../../governance/Governable.sol\";\nimport { IDepositContract } from \"../../interfaces/IDepositContract.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { ISSVNetwork, Cluster } from \"../../interfaces/ISSVNetwork.sol\";\nimport { BeaconRoots } from \"../../beacon/BeaconRoots.sol\";\nimport { PartialWithdrawal } from \"../../beacon/PartialWithdrawal.sol\";\nimport { IBeaconProofs } from \"../../interfaces/IBeaconProofs.sol\";\n\n/**\n * @title Validator lifecycle management contract\n * @notice This contract implements all the required functionality to\n * register, deposit, withdraw, exit and remove validators.\n * @author Origin Protocol Inc\n */\nabstract contract CompoundingValidatorManager is Governable, Pausable {\n using SafeERC20 for IERC20;\n\n /// @dev The amount of ETH in wei that is required for a deposit to a new validator.\n uint256 internal constant DEPOSIT_AMOUNT_WEI = 1 ether;\n /// @dev Validator balances over this amount will eventually become active on the beacon chain.\n /// Due to hysteresis, if the effective balance is 31 ETH, the actual balance\n /// must rise to 32.25 ETH to trigger an effective balance update to 32 ETH.\n /// https://eth2book.info/capella/part2/incentives/balances/#hysteresis\n uint256 internal constant MIN_ACTIVATION_BALANCE_GWEI = 32.25 ether / 1e9;\n /// @dev The maximum number of deposits that are waiting to be verified as processed on the beacon chain.\n uint256 internal constant MAX_DEPOSITS = 32;\n /// @dev The maximum number of validators that can be verified.\n uint256 internal constant MAX_VERIFIED_VALIDATORS = 48;\n /// @dev The default withdrawable epoch value on the Beacon chain.\n /// A value in the far future means the validator is not exiting.\n uint64 internal constant FAR_FUTURE_EPOCH = type(uint64).max;\n /// @dev The number of seconds between each beacon chain slot.\n uint64 internal constant SLOT_DURATION = 12;\n /// @dev The number of slots in each beacon chain epoch.\n uint64 internal constant SLOTS_PER_EPOCH = 32;\n /// @dev Minimum time in seconds to allow snapped balances to be verified.\n /// Set to 35 slots which is 3 slots more than 1 epoch (32 slots). Deposits get processed\n /// once per epoch. This larger than 1 epoch delay should achieve that `snapBalances` sometimes\n /// get called in the middle (or towards the end) of the epoch. Giving the off-chain script\n /// sufficient time after the end of the epoch to prepare the proofs and call `verifyBalances`.\n /// This is considering a malicious actor would keep calling `snapBalances` as frequent as possible\n /// to disturb our operations.\n uint64 public constant SNAP_BALANCES_DELAY = 35 * SLOT_DURATION;\n\n /// @notice The address of the Wrapped ETH (WETH) token contract\n address internal immutable WETH;\n /// @notice The address of the beacon chain deposit contract\n address internal immutable BEACON_CHAIN_DEPOSIT_CONTRACT;\n /// @notice The address of the SSV Network contract used to interface with\n address internal immutable SSV_NETWORK;\n /// @notice Address of the OETH Vault proxy contract\n address internal immutable VAULT_ADDRESS;\n /// @notice Address of the Beacon Proofs contract that verifies beacon chain data\n address public immutable BEACON_PROOFS;\n /// @notice The timestamp of the Beacon chain genesis.\n /// @dev this is different on Testnets like Hoodi so is set at deployment time.\n uint64 internal immutable BEACON_GENESIS_TIMESTAMP;\n\n /// @notice Address of the registrator - allowed to register, withdraw, exit and remove validators\n address public validatorRegistrator;\n\n /// @notice Deposit data for new compounding validators.\n /// @dev A `VERIFIED` deposit can mean 3 separate things:\n /// - a deposit has been processed by the beacon chain and shall be included in the\n /// balance of the next verifyBalances call\n /// - a deposit has been done to a slashed validator and has probably been recovered\n /// back to this strategy. Probably because we can not know for certain. This contract\n /// only detects when the validator has passed its withdrawal epoch. It is close to impossible\n /// to prove with Merkle Proofs that the postponed deposit this contract is responsible for\n /// creating is not present anymore in BeaconChain.state.pending_deposits. This in effect\n /// means that there might be a period where this contract thinks the deposit has been already\n /// returned as ETH balance before it happens. This will result in some days (or weeks)\n /// -> depending on the size of deposit queue of showing a deficit when calling `checkBalance`.\n /// As this only offsets the yield and doesn't cause a critical double-counting we are not addressing\n /// this issue.\n /// - A deposit has been done to the validator, but our deposit has been front run by a malicious\n /// actor. Funds in the deposit this contract makes are not recoverable.\n enum DepositStatus {\n UNKNOWN, // default value\n PENDING, // deposit is pending and waiting to be verified\n VERIFIED // deposit has been verified\n }\n\n /// @param pubKeyHash Hash of validator's public key using the Beacon Chain's format\n /// @param amountGwei Amount of ETH in gwei that has been deposited to the beacon chain deposit contract\n /// @param slot The beacon chain slot number when the deposit has been made\n /// @param depositIndex The index of the deposit in the list of active deposits\n /// @param status The status of the deposit, either UNKNOWN, PENDING or VERIFIED\n struct DepositData {\n bytes32 pubKeyHash;\n uint64 amountGwei;\n uint64 slot;\n uint32 depositIndex;\n DepositStatus status;\n }\n /// @notice Restricts to only one deposit to an unverified validator at a time.\n /// This is to limit front-running attacks of deposits to the beacon chain contract.\n ///\n /// @dev The value is set to true when a deposit to a new validator has been done that has\n /// not yet be verified.\n bool public firstDeposit;\n /// @notice Mapping of the pending deposit roots to the deposit data\n mapping(bytes32 => DepositData) public deposits;\n /// @notice List of strategy deposit IDs to a validator.\n /// The ID is the merkle root of the pending deposit data which is unique for each validator, amount and block.\n /// Duplicate pending deposit roots are prevented so can be used as an identifier to each strategy deposit.\n /// The list can be for deposits waiting to be verified as processed on the beacon chain,\n /// or deposits that have been verified to an exiting validator and is now waiting for the\n /// validator's balance to be swept.\n /// The list may not be ordered by time of deposit.\n /// Removed deposits will move the last deposit to the removed index.\n bytes32[] public depositList;\n\n enum ValidatorState {\n NON_REGISTERED, // validator is not registered on the SSV network\n REGISTERED, // validator is registered on the SSV network\n STAKED, // validator has funds staked\n VERIFIED, // validator has been verified to exist on the beacon chain\n ACTIVE, // The validator balance is at least 32 ETH. The validator may not yet be active on the beacon chain.\n EXITING, // The validator has been requested to exit\n EXITED, // The validator has been verified to have a zero balance\n REMOVED, // validator has funds withdrawn to this strategy contract and is removed from the SSV\n INVALID // The validator has been front-run and the withdrawal address is not this strategy\n }\n\n // Validator data\n struct ValidatorData {\n ValidatorState state; // The state of the validator known to this contract\n uint40 index; // The index of the validator on the beacon chain\n }\n /// @notice List of validator public key hashes that have been verified to exist on the beacon chain.\n /// These have had a deposit processed and the validator's balance increased.\n /// Validators will be removed from this list when its verified they have a zero balance.\n bytes32[] public verifiedValidators;\n /// @notice Mapping of the hash of the validator's public key to the validator state and index.\n /// Uses the Beacon chain hashing for BLSPubkey which is sha256(abi.encodePacked(validator.pubkey, bytes16(0)))\n mapping(bytes32 => ValidatorData) public validator;\n\n /// @param blockRoot Beacon chain block root of the snapshot\n /// @param timestamp Timestamp of the snapshot\n /// @param ethBalance The balance of ETH in the strategy contract at the snapshot\n struct Balances {\n bytes32 blockRoot;\n uint64 timestamp;\n uint128 ethBalance;\n }\n /// @notice Mapping of the block root to the balances at that slot\n Balances public snappedBalance;\n /// @notice The last verified ETH balance of the strategy\n uint256 public lastVerifiedEthBalance;\n\n /// @dev This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately\n /// deposit it to an underlying platform. Rather a special privilege account stakes it to the validators.\n /// For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been\n /// deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track\n /// of WETH that has already been accounted for.\n /// This value represents the amount of WETH balance of this contract that has already been accounted for by the\n /// deposit events.\n /// It is important to note that this variable is not concerned with WETH that is a result of full/partial\n /// withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to\n /// be staked.\n uint256 public depositedWethAccountedFor;\n\n // For future use\n uint256[41] private __gap;\n\n event RegistratorChanged(address indexed newAddress);\n event FirstDepositReset();\n event SSVValidatorRegistered(\n bytes32 indexed pubKeyHash,\n uint64[] operatorIds\n );\n event SSVValidatorRemoved(bytes32 indexed pubKeyHash, uint64[] operatorIds);\n event ETHStaked(\n bytes32 indexed pubKeyHash,\n bytes32 indexed pendingDepositRoot,\n bytes pubKey,\n uint256 amountWei\n );\n event ValidatorVerified(\n bytes32 indexed pubKeyHash,\n uint40 indexed validatorIndex\n );\n event ValidatorInvalid(bytes32 indexed pubKeyHash);\n event DepositVerified(\n bytes32 indexed pendingDepositRoot,\n uint256 amountWei\n );\n event ValidatorWithdraw(bytes32 indexed pubKeyHash, uint256 amountWei);\n event BalancesSnapped(bytes32 indexed blockRoot, uint256 ethBalance);\n event BalancesVerified(\n uint64 indexed timestamp,\n uint256 totalDepositsWei,\n uint256 totalValidatorBalance,\n uint256 ethBalance\n );\n\n /// @dev Throws if called by any account other than the Registrator\n modifier onlyRegistrator() {\n _onlyRegistrator();\n _;\n }\n\n /// @dev internal function used to reduce contract size\n function _onlyRegistrator() internal view {\n require(msg.sender == validatorRegistrator, \"Not Registrator\");\n }\n\n /// @dev Throws if called by any account other than the Registrator or Governor\n modifier onlyRegistratorOrGovernor() {\n require(\n msg.sender == validatorRegistrator || isGovernor(),\n \"Not Registrator or Governor\"\n );\n _;\n }\n\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _vaultAddress Address of the Vault\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _beaconProofs Address of the Beacon Proofs contract that verifies beacon chain data\n /// @param _beaconGenesisTimestamp The timestamp of the Beacon chain's genesis.\n constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork,\n address _beaconProofs,\n uint64 _beaconGenesisTimestamp\n ) {\n WETH = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK = _ssvNetwork;\n VAULT_ADDRESS = _vaultAddress;\n BEACON_PROOFS = _beaconProofs;\n BEACON_GENESIS_TIMESTAMP = _beaconGenesisTimestamp;\n\n require(\n block.timestamp > _beaconGenesisTimestamp,\n \"Invalid genesis timestamp\"\n );\n }\n\n /**\n *\n * Admin Functions\n *\n */\n\n /// @notice Set the address of the registrator which can register, exit and remove validators\n function setRegistrator(address _address) external onlyGovernor {\n validatorRegistrator = _address;\n emit RegistratorChanged(_address);\n }\n\n /// @notice Reset the `firstDeposit` flag to false so deposits to unverified validators can be made again.\n function resetFirstDeposit() external onlyGovernor {\n require(firstDeposit, \"No first deposit\");\n\n firstDeposit = false;\n\n emit FirstDepositReset();\n }\n\n function pause() external onlyRegistratorOrGovernor {\n _pause();\n }\n\n function unPause() external onlyGovernor {\n _unpause();\n }\n\n /**\n *\n * Validator Management\n *\n */\n\n /// @notice Registers a single validator in a SSV Cluster.\n /// Only the Registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param sharesData The shares data for the validator\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n // slither-disable-start reentrancy-no-eth\n function registerSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n bytes calldata sharesData,\n Cluster calldata cluster\n ) external payable onlyRegistrator whenNotPaused {\n // Hash the public key using the Beacon Chain's format\n bytes32 pubKeyHash = _hashPubKey(publicKey);\n // Check each public key has not already been used\n require(\n validator[pubKeyHash].state == ValidatorState.NON_REGISTERED,\n \"Validator already registered\"\n );\n\n // Store the validator state as registered\n validator[pubKeyHash].state = ValidatorState.REGISTERED;\n\n ISSVNetwork(SSV_NETWORK).registerValidator{ value: msg.value }(\n publicKey,\n operatorIds,\n sharesData,\n cluster\n );\n\n emit SSVValidatorRegistered(pubKeyHash, operatorIds);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n struct ValidatorStakeData {\n bytes pubkey;\n bytes signature;\n bytes32 depositDataRoot;\n }\n\n /// @notice Stakes WETH in this strategy to a compounding validator.\n /// The first deposit to a new validator, the amount must be 1 ETH.\n /// Another deposit of at least 31 ETH is required for the validator to be activated.\n /// This second deposit has to be done after the validator has been verified.\n /// Does not convert any ETH sitting in this strategy to WETH.\n /// There can not be two deposits to the same validator in the same block for the same amount.\n /// Function is pausable so in case a run-away Registrator can be prevented from continuing\n /// to deposit funds to slashed or undesired validators.\n /// @param validatorStakeData validator data needed to stake.\n /// The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot.\n /// Only the registrator can call this function.\n /// @param depositAmountGwei The amount of WETH to stake to the validator in Gwei.\n // slither-disable-start reentrancy-eth,reentrancy-no-eth\n function stakeEth(\n ValidatorStakeData calldata validatorStakeData,\n uint64 depositAmountGwei\n ) external onlyRegistrator whenNotPaused {\n uint256 depositAmountWei = uint256(depositAmountGwei) * 1 gwei;\n // Check there is enough WETH from the deposits sitting in this strategy contract\n // There could be ETH from withdrawals but we'll ignore that. If it's really needed\n // the ETH can be withdrawn and then deposited back to the strategy.\n require(\n depositAmountWei <= IWETH9(WETH).balanceOf(address(this)),\n \"Insufficient WETH\"\n );\n require(depositList.length < MAX_DEPOSITS, \"Max deposits\");\n\n // Convert required ETH from WETH and do the necessary accounting\n _convertWethToEth(depositAmountWei);\n\n // Hash the public key using the Beacon Chain's hashing for BLSPubkey\n bytes32 pubKeyHash = _hashPubKey(validatorStakeData.pubkey);\n ValidatorState currentState = validator[pubKeyHash].state;\n // Can only stake to a validator that has been registered, verified or active.\n // Can not stake to a validator that has been staked but not yet verified.\n require(\n (currentState == ValidatorState.REGISTERED ||\n currentState == ValidatorState.VERIFIED ||\n currentState == ValidatorState.ACTIVE),\n \"Not registered or verified\"\n );\n require(depositAmountWei >= 1 ether, \"Deposit too small\");\n if (currentState == ValidatorState.REGISTERED) {\n // Can only have one pending deposit to an unverified validator at a time.\n // This is to limit front-running deposit attacks to a single deposit.\n // The exiting deposit needs to be verified before another deposit can be made.\n // If there was a front-running attack, the validator needs to be verified as invalid\n // and the Governor calls `resetFirstDeposit` to set `firstDeposit` to false.\n require(!firstDeposit, \"Existing first deposit\");\n // Limits the amount of ETH that can be at risk from a front-running deposit attack.\n require(\n depositAmountWei == DEPOSIT_AMOUNT_WEI,\n \"Invalid first deposit amount\"\n );\n // Limits the number of validator balance proofs to verifyBalances\n require(\n verifiedValidators.length + 1 <= MAX_VERIFIED_VALIDATORS,\n \"Max validators\"\n );\n\n // Flag a deposit to an unverified validator so no other deposits can be made\n // to an unverified validator.\n firstDeposit = true;\n validator[pubKeyHash].state = ValidatorState.STAKED;\n }\n\n /* 0x02 to indicate that withdrawal credentials are for a compounding validator\n * that was introduced with the Pectra upgrade.\n * bytes11(0) to fill up the required zeros\n * remaining bytes20 are for the address\n */\n bytes memory withdrawalCredentials = abi.encodePacked(\n bytes1(0x02),\n bytes11(0),\n address(this)\n );\n\n /// After the Pectra upgrade the validators have a new restriction when proposing\n /// blocks. The timestamps are at strict intervals of 12 seconds from the genesis block\n /// forward. Each slot is created at strict 12 second intervals and those slots can\n /// either have blocks attached to them or not. This way using the block.timestamp\n /// the slot number can easily be calculated.\n uint64 depositSlot = (SafeCast.toUint64(block.timestamp) -\n BEACON_GENESIS_TIMESTAMP) / SLOT_DURATION;\n\n // Calculate the merkle root of the beacon chain pending deposit data.\n // This is used as the unique ID of the deposit.\n bytes32 pendingDepositRoot = IBeaconProofs(BEACON_PROOFS)\n .merkleizePendingDeposit(\n pubKeyHash,\n withdrawalCredentials,\n depositAmountGwei,\n validatorStakeData.signature,\n depositSlot\n );\n require(\n deposits[pendingDepositRoot].status == DepositStatus.UNKNOWN,\n \"Duplicate deposit\"\n );\n\n // Store the deposit data for verifyDeposit and verifyBalances\n deposits[pendingDepositRoot] = DepositData({\n pubKeyHash: pubKeyHash,\n amountGwei: depositAmountGwei,\n slot: depositSlot,\n depositIndex: SafeCast.toUint32(depositList.length),\n status: DepositStatus.PENDING\n });\n depositList.push(pendingDepositRoot);\n\n // Deposit to the Beacon Chain deposit contract.\n // This will create a deposit in the beacon chain's pending deposit queue.\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\n value: depositAmountWei\n }(\n validatorStakeData.pubkey,\n withdrawalCredentials,\n validatorStakeData.signature,\n validatorStakeData.depositDataRoot\n );\n\n emit ETHStaked(\n pubKeyHash,\n pendingDepositRoot,\n validatorStakeData.pubkey,\n depositAmountWei\n );\n }\n\n // slither-disable-end reentrancy-eth,reentrancy-no-eth\n\n /// @notice Request a full or partial withdrawal from a validator.\n /// A zero amount will trigger a full withdrawal.\n /// If the remaining balance is < 32 ETH then only the amount in excess of 32 ETH will be withdrawn.\n /// Only the Registrator can call this function.\n /// 1 wei of value should be sent with the tx to pay for the withdrawal request fee.\n /// If no value sent, 1 wei will be taken from the strategy's ETH balance if it has any.\n /// If no ETH balance, the tx will revert.\n /// @param publicKey The public key of the validator\n /// @param amountGwei The amount of ETH to be withdrawn from the validator in Gwei.\n /// A zero amount will trigger a full withdrawal.\n // slither-disable-start reentrancy-no-eth\n function validatorWithdrawal(bytes calldata publicKey, uint64 amountGwei)\n external\n payable\n onlyRegistrator\n {\n // Hash the public key using the Beacon Chain's format\n bytes32 pubKeyHash = _hashPubKey(publicKey);\n ValidatorData memory validatorDataMem = validator[pubKeyHash];\n // Validator full withdrawal could be denied due to multiple reasons:\n // - the validator has not been activated or active long enough\n // (current_epoch < activation_epoch + SHARD_COMMITTEE_PERIOD)\n // - the validator has pending balance to withdraw from a previous partial withdrawal request\n //\n // Meaning that the on-chain to beacon chain full withdrawal request could fail. Instead\n // of adding complexity of verifying if a validator is eligible for a full exit, we allow\n // multiple full withdrawal requests per validator.\n require(\n validatorDataMem.state == ValidatorState.ACTIVE ||\n validatorDataMem.state == ValidatorState.EXITING,\n \"Validator not active/exiting\"\n );\n\n // If a full withdrawal (validator exit)\n if (amountGwei == 0) {\n // For each staking strategy's deposits\n uint256 depositsCount = depositList.length;\n for (uint256 i = 0; i < depositsCount; ++i) {\n bytes32 pendingDepositRoot = depositList[i];\n // Check there is no pending deposits to the exiting validator\n require(\n pubKeyHash != deposits[pendingDepositRoot].pubKeyHash,\n \"Pending deposit\"\n );\n }\n\n // Store the validator state as exiting so no more deposits can be made to it.\n // This may already be EXITING if the previous exit request failed. eg the validator\n // was not active long enough.\n validator[pubKeyHash].state = ValidatorState.EXITING;\n }\n\n // Do not remove from the list of verified validators.\n // This is done in the verifyBalances function once the validator's balance has been verified to be zero.\n // The validator state will be set to EXITED in the verifyBalances function.\n\n PartialWithdrawal.request(publicKey, amountGwei);\n\n emit ValidatorWithdraw(pubKeyHash, uint256(amountGwei) * 1 gwei);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Remove the validator from the SSV Cluster after:\n /// - the validator has been exited from `validatorWithdrawal` or slashed\n /// - the validator has incorrectly registered and can not be staked to\n /// - the initial deposit was front-run and the withdrawal address is not this strategy's address.\n /// Make sure `validatorWithdrawal` is called with a zero amount and the validator has exited the Beacon chain.\n /// If removed before the validator has exited the beacon chain will result in the validator being slashed.\n /// Only the registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n // slither-disable-start reentrancy-no-eth\n function removeSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator {\n // Hash the public key using the Beacon Chain's format\n bytes32 pubKeyHash = _hashPubKey(publicKey);\n ValidatorState currentState = validator[pubKeyHash].state;\n // Can remove SSV validators that were incorrectly registered and can not be deposited to.\n require(\n currentState == ValidatorState.REGISTERED ||\n currentState == ValidatorState.EXITED ||\n currentState == ValidatorState.INVALID,\n \"Validator not regd or exited\"\n );\n\n validator[pubKeyHash].state = ValidatorState.REMOVED;\n\n ISSVNetwork(SSV_NETWORK).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n\n emit SSVValidatorRemoved(pubKeyHash, operatorIds);\n }\n\n /**\n *\n * SSV Management\n *\n */\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Migrate the SSV cluster to use ETH for payment instead of SSV tokens.\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n function migrateClusterToETH(\n uint64[] memory operatorIds,\n Cluster memory cluster\n ) external payable onlyGovernor {\n ISSVNetwork(SSV_NETWORK).migrateClusterToETH{ value: msg.value }(\n operatorIds,\n cluster\n );\n\n // The SSV Network emits\n // ClusterMigratedToETH(msg.sender, operatorIds, msg.value, ssvClusterBalance, effectiveBalance, cluster)\n }\n\n /**\n *\n * Beacon Chain Proofs\n *\n */\n\n /// @notice Verifies a validator's index to its public key.\n /// Adds to the list of verified validators if the validator's withdrawal address is this strategy's address.\n /// Marks the validator as invalid and removes the deposit if the withdrawal address is not this strategy's address.\n /// @param nextBlockTimestamp The timestamp of the execution layer block after the beacon chain slot\n /// we are verifying.\n /// The next one is needed as the Beacon Oracle returns the parent beacon block root for a block timestamp,\n /// which is the beacon block root of the previous block.\n /// @param validatorIndex The index of the validator on the beacon chain.\n /// @param pubKeyHash The hash of the validator's public key using the Beacon Chain's format\n /// @param withdrawalCredentials contain the validator type and withdrawal address. These can be incorrect and/or\n /// malformed. In case of incorrect withdrawalCredentials the validator deposit has been front run\n /// @param validatorPubKeyProof The merkle proof for the validator public key to the beacon block root.\n /// This is 53 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n /// BeaconBlock.state.validators[validatorIndex].pubkey\n function verifyValidator(\n uint64 nextBlockTimestamp,\n uint40 validatorIndex,\n bytes32 pubKeyHash,\n bytes32 withdrawalCredentials,\n bytes calldata validatorPubKeyProof\n ) external {\n require(\n validator[pubKeyHash].state == ValidatorState.STAKED,\n \"Validator not staked\"\n );\n\n // Get the beacon block root of the slot we are verifying the validator in.\n // The parent beacon block root of the next block is the beacon block root of the slot we are verifying.\n bytes32 blockRoot = BeaconRoots.parentBlockRoot(nextBlockTimestamp);\n\n // Verify the validator index is for the validator with the given public key.\n // Also verify the validator's withdrawal credentials\n IBeaconProofs(BEACON_PROOFS).verifyValidator(\n blockRoot,\n pubKeyHash,\n validatorPubKeyProof,\n validatorIndex,\n withdrawalCredentials\n );\n\n // Store the validator state as verified\n validator[pubKeyHash] = ValidatorData({\n state: ValidatorState.VERIFIED,\n index: validatorIndex\n });\n\n bytes32 expectedWithdrawalCredentials = bytes32(\n abi.encodePacked(bytes1(0x02), bytes11(0), address(this))\n );\n\n // If the initial deposit was front-run and the withdrawal address is not this strategy\n // or the validator type is not a compounding validator (0x02)\n if (expectedWithdrawalCredentials != withdrawalCredentials) {\n // override the validator state\n validator[pubKeyHash].state = ValidatorState.INVALID;\n\n // Find and remove the deposit as the funds can not be recovered\n uint256 depositCount = depositList.length;\n for (uint256 i = 0; i < depositCount; i++) {\n DepositData memory deposit = deposits[depositList[i]];\n if (deposit.pubKeyHash == pubKeyHash) {\n // next verifyBalances will correctly account for the loss of a front-run\n // deposit. Doing it here accounts for the loss as soon as possible\n lastVerifiedEthBalance -= Math.min(\n lastVerifiedEthBalance,\n uint256(deposit.amountGwei) * 1 gwei\n );\n _removeDeposit(depositList[i], deposit);\n break;\n }\n }\n\n // Leave the `firstDeposit` flag as true so no more deposits to unverified validators can be made.\n // The Governor has to reset the `firstDeposit` to false before another deposit to\n // an unverified validator can be made.\n // The Governor can set a new `validatorRegistrator` if they suspect it has been compromised.\n\n emit ValidatorInvalid(pubKeyHash);\n return;\n }\n\n // Add the new validator to the list of verified validators\n verifiedValidators.push(pubKeyHash);\n\n // Reset the firstDeposit flag as the first deposit to an unverified validator has been verified.\n firstDeposit = false;\n\n emit ValidatorVerified(pubKeyHash, validatorIndex);\n }\n\n struct FirstPendingDepositSlotProofData {\n uint64 slot;\n bytes proof;\n }\n\n struct StrategyValidatorProofData {\n uint64 withdrawableEpoch;\n bytes withdrawableEpochProof;\n }\n\n /// @notice Verifies a deposit on the execution layer has been processed by the beacon chain.\n /// This means the accounting of the strategy's ETH moves from a pending deposit to a validator balance.\n ///\n /// Important: this function has a limitation where `depositProcessedSlot` that is passed by the off-chain\n /// verifier requires a slot immediately after it to propose a block otherwise the `BeaconRoots.parentBlockRoot`\n /// will fail. This shouldn't be a problem, since by the current behaviour of beacon chain only 1%-3% slots\n /// don't propose a block.\n /// @param pendingDepositRoot The unique identifier of the deposit emitted in `ETHStaked` from\n /// the `stakeEth` function.\n /// @param depositProcessedSlot Any slot on or after the strategy's deposit was processed on the beacon chain.\n /// Can not be a slot with pending deposits with the same slot as the deposit being verified.\n /// Can not be a slot before a missed slot as the Beacon Root contract will have the parent block root\n /// set for the next block timestamp in 12 seconds time.\n /// @param firstPendingDeposit a `FirstPendingDepositSlotProofData` struct containing:\n /// - slot: The beacon chain slot of the first deposit in the beacon chain's deposit queue.\n /// Can be any non-zero value if the deposit queue is empty.\n /// - proof: The merkle proof of the first pending deposit's slot to the beacon block root.\n /// Can be either:\n /// * 40 witness hashes for BeaconBlock.state.PendingDeposits[0].slot when the deposit queue is not empty.\n /// * 37 witness hashes for BeaconBlock.state.PendingDeposits[0] when the deposit queue is empty.\n /// The 32 byte witness hashes are concatenated together starting from the leaf node.\n /// @param strategyValidatorData a `StrategyValidatorProofData` struct containing:\n /// - withdrawableEpoch: The withdrawable epoch of the validator the strategy is depositing to.\n /// - withdrawableEpochProof: The merkle proof for the withdrawable epoch of the validator the strategy\n /// is depositing to, to the beacon block root.\n /// This is 53 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n // slither-disable-start reentrancy-no-eth\n function verifyDeposit(\n bytes32 pendingDepositRoot,\n uint64 depositProcessedSlot,\n FirstPendingDepositSlotProofData calldata firstPendingDeposit,\n StrategyValidatorProofData calldata strategyValidatorData\n ) external {\n // Load into memory the previously saved deposit data\n DepositData memory deposit = deposits[pendingDepositRoot];\n ValidatorData memory strategyValidator = validator[deposit.pubKeyHash];\n require(deposit.status == DepositStatus.PENDING, \"Deposit not pending\");\n require(firstPendingDeposit.slot != 0, \"Zero 1st pending deposit slot\");\n\n // We should allow the verification of deposits for validators that have been marked as exiting\n // to cover this situation:\n // - there are 2 pending deposits\n // - beacon chain has slashed the validator\n // - when verifyDeposit is called for the first deposit it sets the Validator state to EXITING\n // - verifyDeposit should allow a secondary call for the other deposit to a slashed validator\n require(\n strategyValidator.state == ValidatorState.VERIFIED ||\n strategyValidator.state == ValidatorState.ACTIVE ||\n strategyValidator.state == ValidatorState.EXITING,\n \"Not verified/active/exiting\"\n );\n // The verification slot must be after the deposit's slot.\n // This is needed for when the deposit queue is empty.\n require(deposit.slot < depositProcessedSlot, \"Slot not after deposit\");\n\n uint64 snapTimestamp = snappedBalance.timestamp;\n\n // This check prevents an accounting error that can happen if:\n // - snapBalances are snapped at the time of T\n // - deposit is processed on the beacon chain after time T and before verifyBalances()\n // - verifyDeposit is called before verifyBalances which removes a deposit from depositList\n // and deposit balance from totalDepositsWei\n // - verifyBalances is called under-reporting the strategy's balance\n require(\n (_calcNextBlockTimestamp(depositProcessedSlot) <= snapTimestamp) ||\n snapTimestamp == 0,\n \"Deposit after balance snapshot\"\n );\n\n // Get the parent beacon block root of the next block which is the block root of the deposit verification slot.\n // This will revert if the slot after the verification slot was missed.\n bytes32 depositBlockRoot = BeaconRoots.parentBlockRoot(\n _calcNextBlockTimestamp(depositProcessedSlot)\n );\n\n // Verify the slot of the first pending deposit matches the beacon chain\n bool isDepositQueueEmpty = IBeaconProofs(BEACON_PROOFS)\n .verifyFirstPendingDeposit(\n depositBlockRoot,\n firstPendingDeposit.slot,\n firstPendingDeposit.proof\n );\n\n // Verify the withdrawableEpoch on the validator of the strategy's deposit\n IBeaconProofs(BEACON_PROOFS).verifyValidatorWithdrawable(\n depositBlockRoot,\n strategyValidator.index,\n strategyValidatorData.withdrawableEpoch,\n strategyValidatorData.withdrawableEpochProof\n );\n\n uint64 firstPendingDepositEpoch = firstPendingDeposit.slot /\n SLOTS_PER_EPOCH;\n\n // If deposit queue is empty all deposits have certainly been processed. If not\n // a validator can either be not exiting and no further checks are required.\n // Or a validator is exiting then this function needs to make sure that the\n // pending deposit to an exited validator has certainly been processed. The\n // slot/epoch of first pending deposit is the one that contains the transaction\n // where the deposit to the ETH Deposit Contract has been made.\n //\n // Once the firstPendingDepositEpoch becomes greater than the withdrawableEpoch of\n // the slashed validator then the deposit has certainly been processed. When the beacon\n // chain reaches the withdrawableEpoch of the validator the deposit will no longer be\n // postponed. And any new deposits created (and present in the deposit queue)\n // will have an equal or larger withdrawableEpoch.\n require(\n strategyValidatorData.withdrawableEpoch == FAR_FUTURE_EPOCH ||\n strategyValidatorData.withdrawableEpoch <=\n firstPendingDepositEpoch ||\n isDepositQueueEmpty,\n \"Exit Deposit likely not proc.\"\n );\n\n // solhint-disable max-line-length\n // Check the deposit slot is before the first pending deposit's slot on the beacon chain.\n // If this is not true then we can't guarantee the deposit has been processed by the beacon chain.\n // The deposit's slot can not be the same slot as the first pending deposit as there could be\n // many deposits in the same block, hence have the same pending deposit slot.\n // If the deposit queue is empty then our deposit must have been processed on the beacon chain.\n // The deposit slot can be zero for validators consolidating to a compounding validator or 0x01 validator\n // being promoted to a compounding one. Reference:\n // - [switch_to_compounding_validator](https://ethereum.github.io/consensus-specs/specs/electra/beacon-chain/#new-switch_to_compounding_validator\n // - [queue_excess_active_balance](https://ethereum.github.io/consensus-specs/specs/electra/beacon-chain/#new-queue_excess_active_balance)\n // - [process_consolidation_request](https://ethereum.github.io/consensus-specs/specs/electra/beacon-chain/#new-process_consolidation_request)\n // We can not guarantee that the deposit has been processed in that case.\n // solhint-enable max-line-length\n require(\n deposit.slot < firstPendingDeposit.slot || isDepositQueueEmpty,\n \"Deposit likely not processed\"\n );\n\n // Remove the deposit now it has been verified as processed on the beacon chain.\n _removeDeposit(pendingDepositRoot, deposit);\n\n emit DepositVerified(\n pendingDepositRoot,\n uint256(deposit.amountGwei) * 1 gwei\n );\n }\n\n function _removeDeposit(\n bytes32 pendingDepositRoot,\n DepositData memory deposit\n ) internal {\n // After verifying the proof, update the contract storage\n deposits[pendingDepositRoot].status = DepositStatus.VERIFIED;\n // Move the last deposit to the index of the verified deposit\n bytes32 lastDeposit = depositList[depositList.length - 1];\n depositList[deposit.depositIndex] = lastDeposit;\n deposits[lastDeposit].depositIndex = deposit.depositIndex;\n // Delete the last deposit from the list\n depositList.pop();\n }\n\n /// @dev Calculates the timestamp of the next execution block from the given slot.\n /// @param slot The beacon chain slot number used for merkle proof verification.\n function _calcNextBlockTimestamp(uint64 slot)\n internal\n view\n returns (uint64)\n {\n // Calculate the next block timestamp from the slot.\n return SLOT_DURATION * slot + BEACON_GENESIS_TIMESTAMP + SLOT_DURATION;\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Stores the current ETH balance at the current block and beacon block root\n /// of the slot that is associated with the previous block.\n ///\n /// When snapping / verifying balance it is of a high importance that there is no\n /// miss-match in respect to ETH that is held by the contract and balances that are\n /// verified on the validators.\n ///\n /// First some context on the beacon-chain block building behaviour. Relevant parts of\n /// constructing a block on the beacon chain consist of:\n /// - process_withdrawals: ETH is deducted from the validator's balance\n /// - process_execution_payload: immediately after the previous step executing all the\n /// transactions\n /// - apply the withdrawals: adding ETH to the recipient which is the withdrawal address\n /// contained in the withdrawal credentials of the exited validators\n ///\n /// That means that balance increases which are part of the post-block execution state are\n /// done within the block, but the transaction that are contained within that block can not\n /// see / interact with the balance from the exited validators. Only transactions in the\n /// next block can do that.\n ///\n /// When snap balances is performed the state of the chain is snapped across 2 separate\n /// chain states:\n /// - ETH balance of the contract is recorded on block X -> and corresponding slot Y\n /// - beacon chain block root is recorded of block X - 1 -> and corresponding slot Y - 1\n /// given there were no missed slots. It could also be Y - 2, Y - 3 depending on how\n /// many slots have not managed to propose a block. For the sake of simplicity this slot\n /// will be referred to as Y - 1 as it makes no difference in the argument\n ///\n /// Given these 2 separate chain states it is paramount that verify balances can not experience\n /// miss-counting ETH or much more dangerous double counting of the ETH.\n ///\n /// When verifyBalances is called it is performed on the current block Z where Z > X. Verify\n /// balances adds up all the ETH (omitting WETH) controlled by this contract:\n /// - ETH balance in the contract on block X\n /// - ETH balance in Deposits on block Z that haven't been yet processed in slot Y - 1\n /// - ETH balance in validators that are active in slot Y - 1\n /// - skips the ETH balance in validators that have withdrawn in slot Y - 1 (or sooner)\n /// and have their balance visible to transactions in slot Y and corresponding block X\n /// (or sooner)\n ///\n /// Lets verify the correctness of ETH accounting given the above described behaviour.\n ///\n /// *ETH balance in the contract on block X*\n ///\n /// This is an ETH balance of the contract on a non current X block. Any ETH leaving the\n /// contract as a result of a withdrawal subtracts from the ETH accounted for on block X\n /// if `verifyBalances` has already been called. It also invalidates a `snapBalances` in\n /// case `verifyBalances` has not been called yet. Not performing this would result in not\n /// accounting for the withdrawn ETH that has happened anywhere in the block interval [X + 1, Z].\n ///\n /// Similarly to withdrawals any `stakeEth` deposits to the deposit contract adds to the ETH\n /// accounted for since the last `verifyBalances` has been called. And it invalidates the\n /// `snapBalances` in case `verifyBalances` hasn't been yet called. Not performing this\n /// would result in double counting the `stakedEth` since it would be present once in the\n /// snapped contract balance and the second time in deposit storage variables.\n ///\n /// This behaviour is correct.\n ///\n /// *ETH balance in Deposits on block Z that haven't been yet processed in slot Y - 1*\n ///\n /// The contract sums up all the ETH that has been deposited to the Beacon chain deposit\n /// contract at block Z. The execution layer doesn't have direct access to the state of\n /// deposits on the beacon chain. And if it is to sum up all the ETH that is marked to be\n /// deposited it needs to be sure to not double count ETH that is in deposits (storage vars)\n /// and could also be part of the validator balances. It does that by verifying that at\n /// slot Y - 1 none of the deposits visible on block Z have been processed. Meaning since\n /// the last snap till now all are still in queue. Which ensures they can not be part of\n /// the validator balances in later steps.\n ///\n /// This behaviour is correct.\n ///\n /// *ETH balance in validators that are active in slot Y - 1*\n ///\n /// The contract is verifying none of the deposits on Y - 1 slot have been processed and\n /// for that reason it checks the validator balances in the same slot. Ensuring accounting\n /// correctness.\n ///\n /// This behaviour is correct.\n ///\n /// *The withdrawn validators*\n ///\n /// The withdrawn validators could have their balances deducted in any slot before slot\n /// Y - 1 and the execution layer sees the balance increase in the subsequent slot. Lets\n /// look at the \"worst case scenario\" where the validator withdrawal is processed in the\n /// slot Y - 1 (snapped slot) and see their balance increase (in execution layer) in slot\n /// Y -> block X. The ETH balance on the contract is snapped at block X meaning that\n /// even if the validator exits at the latest possible time it is paramount that the ETH\n /// balance on the execution layer is recorded in the next block. Correctly accounting\n /// for the withdrawn ETH.\n ///\n /// Worth mentioning if the validator exit is processed by the slot Y and balance increase\n /// seen on the execution layer on block X + 1 the withdrawal is ignored by both the\n /// validator balance verification as well as execution layer contract balance snap.\n ///\n /// This behaviour is correct.\n ///\n /// The validator balances on the beacon chain can then be proved with `verifyBalances`.\n function snapBalances() external onlyRegistrator {\n uint64 currentTimestamp = SafeCast.toUint64(block.timestamp);\n require(\n snappedBalance.timestamp + SNAP_BALANCES_DELAY < currentTimestamp,\n \"Snap too soon\"\n );\n\n bytes32 blockRoot = BeaconRoots.parentBlockRoot(currentTimestamp);\n // Get the current ETH balance\n uint256 ethBalance = address(this).balance;\n\n // Store the snapped balance\n snappedBalance = Balances({\n blockRoot: blockRoot,\n timestamp: currentTimestamp,\n ethBalance: SafeCast.toUint128(ethBalance)\n });\n\n emit BalancesSnapped(blockRoot, ethBalance);\n }\n\n // A struct is used to avoid stack too deep errors\n struct BalanceProofs {\n // BeaconBlock.state.balances\n bytes32 balancesContainerRoot;\n bytes balancesContainerProof;\n // BeaconBlock.state.balances[validatorIndex]\n bytes32[] validatorBalanceLeaves;\n bytes[] validatorBalanceProofs;\n }\n\n struct PendingDepositProofs {\n bytes32 pendingDepositContainerRoot;\n bytes pendingDepositContainerProof;\n uint32[] pendingDepositIndexes;\n bytes[] pendingDepositProofs;\n }\n\n /// @notice Verifies the balances of all active validators on the beacon chain\n /// and checks each of the strategy's deposits are still to be processed by the beacon chain.\n /// @param balanceProofs a `BalanceProofs` struct containing the following:\n /// - balancesContainerRoot: The merkle root of the balances container\n /// - balancesContainerProof: The merkle proof for the balances container to the beacon block root.\n /// This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n /// - validatorBalanceLeaves: Array of leaf nodes containing the validator balance with three other balances.\n /// - validatorBalanceProofs: Array of merkle proofs for the validator balance to the Balances container root.\n /// This is 39 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n /// @param pendingDepositProofs a `PendingDepositProofs` struct containing the following:\n /// - pendingDepositContainerRoot: The merkle root of the pending deposits list container\n /// - pendingDepositContainerProof: The merkle proof from the pending deposits list container\n /// to the beacon block root.\n /// This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n /// - pendingDepositIndexes: Array of indexes in the pending deposits list container for each\n /// of the strategy's deposits.\n /// - pendingDepositProofs: Array of merkle proofs for each strategy deposit in the\n /// beacon chain's pending deposit list container to the pending deposits list container root.\n /// These are 28 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n // slither-disable-start reentrancy-no-eth\n function verifyBalances(\n BalanceProofs calldata balanceProofs,\n PendingDepositProofs calldata pendingDepositProofs\n ) external onlyRegistrator {\n // Load previously snapped balances for the given block root\n Balances memory balancesMem = snappedBalance;\n // Check the balances are the latest\n require(balancesMem.timestamp > 0, \"No snapped balances\");\n\n uint256 verifiedValidatorsCount = verifiedValidators.length;\n uint256 totalValidatorBalance = 0;\n uint256 depositsCount = depositList.length;\n\n // If there are no verified validators then we can skip the balance verification\n if (verifiedValidatorsCount > 0) {\n require(\n balanceProofs.validatorBalanceProofs.length ==\n verifiedValidatorsCount,\n \"Invalid balance proofs\"\n );\n require(\n balanceProofs.validatorBalanceLeaves.length ==\n verifiedValidatorsCount,\n \"Invalid balance leaves\"\n );\n // verify beaconBlock.state.balances root to beacon block root\n IBeaconProofs(BEACON_PROOFS).verifyBalancesContainer(\n balancesMem.blockRoot,\n balanceProofs.balancesContainerRoot,\n balanceProofs.balancesContainerProof\n );\n\n bytes32[]\n memory validatorHashesMem = _getPendingDepositValidatorHashes(\n depositsCount\n );\n\n // for each validator in reverse order so we can pop off exited validators at the end\n for (uint256 i = verifiedValidatorsCount; i > 0; ) {\n --i;\n ValidatorData memory validatorDataMem = validator[\n verifiedValidators[i]\n ];\n // verify validator's balance in beaconBlock.state.balances to the\n // beaconBlock.state.balances container root\n uint256 validatorBalanceGwei = IBeaconProofs(BEACON_PROOFS)\n .verifyValidatorBalance(\n balanceProofs.balancesContainerRoot,\n balanceProofs.validatorBalanceLeaves[i],\n balanceProofs.validatorBalanceProofs[i],\n validatorDataMem.index\n );\n\n // If the validator has exited and the balance is now zero\n if (validatorBalanceGwei == 0) {\n // Check if there are any pending deposits to this validator\n bool depositPending = false;\n for (uint256 j = 0; j < validatorHashesMem.length; j++) {\n if (validatorHashesMem[j] == verifiedValidators[i]) {\n depositPending = true;\n break;\n }\n }\n\n // If validator has a pending deposit we can not remove due to\n // the following situation:\n // - validator has a pending deposit\n // - validator has been slashed\n // - sweep cycle has withdrawn all ETH from the validator. Balance is 0\n // - beacon chain has processed the deposit and set the validator balance\n // to deposit amount\n // - if validator is no longer in the list of verifiedValidators its\n // balance will not be considered and be under-counted.\n if (!depositPending) {\n // Store the validator state as exited\n // This could have been in VERIFIED, ACTIVE or EXITING state\n validator[verifiedValidators[i]].state = ValidatorState\n .EXITED;\n\n // Remove the validator with a zero balance from the list of verified validators\n\n // Reduce the count of verified validators which is the last index before the pop removes it.\n verifiedValidatorsCount -= 1;\n\n // Move the last validator that has already been verified to the current index.\n // There's an extra SSTORE if i is the last active validator but that's fine,\n // It's not a common case and the code is simpler this way.\n verifiedValidators[i] = verifiedValidators[\n verifiedValidatorsCount\n ];\n // Delete the last validator from the list\n verifiedValidators.pop();\n }\n\n // The validator balance is zero so not need to add to totalValidatorBalance\n continue;\n } else if (\n validatorDataMem.state == ValidatorState.VERIFIED &&\n validatorBalanceGwei > MIN_ACTIVATION_BALANCE_GWEI\n ) {\n // Store the validator state as active. This does not necessarily mean the\n // validator is active on the beacon chain yet. It just means the validator has\n // enough balance that it can become active.\n validator[verifiedValidators[i]].state = ValidatorState\n .ACTIVE;\n }\n\n // convert Gwei balance to Wei and add to the total validator balance\n totalValidatorBalance += validatorBalanceGwei * 1 gwei;\n }\n }\n\n uint256 totalDepositsWei = 0;\n\n // If there are no deposits then we can skip the deposit verification.\n // This section is after the validator balance verifications so an exited validator will be marked\n // as EXITED before the deposits are verified. If there was a deposit to an exited validator\n // then the deposit can only be removed once the validator is fully exited.\n // It is possible that validator fully exits and a postponed deposit to an exited validator increases\n // its balance again. In such case the contract will erroneously consider a deposit applied before it\n // has been applied on the beacon chain showing a smaller than real `totalValidatorBalance`.\n if (depositsCount > 0) {\n require(\n pendingDepositProofs.pendingDepositProofs.length ==\n depositsCount,\n \"Invalid deposit proofs\"\n );\n require(\n pendingDepositProofs.pendingDepositIndexes.length ==\n depositsCount,\n \"Invalid deposit indexes\"\n );\n\n // Verify from the root of the pending deposit list container to the beacon block root\n IBeaconProofs(BEACON_PROOFS).verifyPendingDepositsContainer(\n balancesMem.blockRoot,\n pendingDepositProofs.pendingDepositContainerRoot,\n pendingDepositProofs.pendingDepositContainerProof\n );\n\n // For each staking strategy's deposit.\n for (uint256 i = 0; i < depositsCount; ++i) {\n bytes32 pendingDepositRoot = depositList[i];\n\n // Verify the strategy's deposit is still pending on the beacon chain.\n IBeaconProofs(BEACON_PROOFS).verifyPendingDeposit(\n pendingDepositProofs.pendingDepositContainerRoot,\n pendingDepositRoot,\n pendingDepositProofs.pendingDepositProofs[i],\n pendingDepositProofs.pendingDepositIndexes[i]\n );\n\n // Convert the deposit amount from Gwei to Wei and add to the total\n totalDepositsWei +=\n uint256(deposits[pendingDepositRoot].amountGwei) *\n 1 gwei;\n }\n }\n\n // Store the verified balance in storage\n lastVerifiedEthBalance =\n totalDepositsWei +\n totalValidatorBalance +\n balancesMem.ethBalance;\n // Reset the last snap timestamp so a new snapBalances has to be made\n snappedBalance.timestamp = 0;\n\n emit BalancesVerified(\n balancesMem.timestamp,\n totalDepositsWei,\n totalValidatorBalance,\n balancesMem.ethBalance\n );\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice get a list of all validator hashes present in the pending deposits\n /// list can have duplicate entries\n function _getPendingDepositValidatorHashes(uint256 depositsCount)\n internal\n view\n returns (bytes32[] memory validatorHashes)\n {\n validatorHashes = new bytes32[](depositsCount);\n for (uint256 i = 0; i < depositsCount; i++) {\n validatorHashes[i] = deposits[depositList[i]].pubKeyHash;\n }\n }\n\n /// @notice Hash a validator public key using the Beacon Chain's format\n function _hashPubKey(bytes memory pubKey) internal pure returns (bytes32) {\n require(pubKey.length == 48, \"Invalid public key\");\n return sha256(abi.encodePacked(pubKey, bytes16(0)));\n }\n\n /**\n *\n * WETH and ETH Accounting\n *\n */\n\n /// @dev Called when WETH is transferred out of the strategy so\n /// the strategy knows how much WETH it has on deposit.\n /// This is so it can emit the correct amount in the Deposit event in depositAll().\n function _transferWeth(uint256 _amount, address _recipient) internal {\n IERC20(WETH).safeTransfer(_recipient, _amount);\n\n // The min is required as more WETH can be withdrawn than deposited\n // as the strategy earns consensus and execution rewards.\n uint256 deductAmount = Math.min(_amount, depositedWethAccountedFor);\n depositedWethAccountedFor -= deductAmount;\n\n // No change in ETH balance so no need to snapshot the balances\n }\n\n /// @dev Converts ETH to WETH and updates the accounting.\n /// @param _ethAmount The amount of ETH in wei.\n function _convertEthToWeth(uint256 _ethAmount) internal {\n // slither-disable-next-line arbitrary-send-eth\n IWETH9(WETH).deposit{ value: _ethAmount }();\n\n depositedWethAccountedFor += _ethAmount;\n\n // Store the reduced ETH balance.\n // The ETH balance in this strategy contract can be more than the last verified ETH balance\n // due to partial withdrawals or full exits being processed by the beacon chain since the last snapBalances.\n // It can also happen from execution rewards (MEV) or ETH donations.\n lastVerifiedEthBalance -= Math.min(lastVerifiedEthBalance, _ethAmount);\n\n // The ETH balance was decreased to WETH so we need to invalidate the last balances snap.\n snappedBalance.timestamp = 0;\n }\n\n /// @dev Converts WETH to ETH and updates the accounting.\n /// @param _wethAmount The amount of WETH in wei.\n function _convertWethToEth(uint256 _wethAmount) internal {\n IWETH9(WETH).withdraw(_wethAmount);\n\n uint256 deductAmount = Math.min(_wethAmount, depositedWethAccountedFor);\n depositedWethAccountedFor -= deductAmount;\n\n // Store the increased ETH balance\n lastVerifiedEthBalance += _wethAmount;\n\n // The ETH balance was increased from WETH so we need to invalidate the last balances snap.\n snappedBalance.timestamp = 0;\n }\n\n /**\n *\n * View Functions\n *\n */\n\n /// @notice Returns the number of deposits waiting to be verified as processed on the beacon chain,\n /// or deposits that have been verified to an exiting validator and is now waiting for the\n /// validator's balance to be swept.\n function depositListLength() external view returns (uint256) {\n return depositList.length;\n }\n\n /// @notice Returns the number of verified validators.\n function verifiedValidatorsLength() external view returns (uint256) {\n return verifiedValidators.length;\n }\n}\n" + }, + "contracts/strategies/NativeStaking/ConsolidationController.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\n\nimport { CompoundingStakingSSVStrategy, CompoundingValidatorManager } from \"./CompoundingStakingSSVStrategy.sol\";\nimport { ValidatorAccountant } from \"./ValidatorAccountant.sol\";\nimport { Cluster } from \"../../interfaces/ISSVNetwork.sol\";\n\n/// @title Consolidation Controller\n/// @notice Orchestrates the consolidation of validators from old Native Staking Strategies\n/// to the new Compounding Staking Strategy.\n/// @author Origin Protocol Inc\ncontract ConsolidationController is Ownable {\n /// @dev Minimum time that must pass before a consolidation request can be processed.\n /// 261 epochs * 32 slots/epoch * 12 seconds/slot = 100224 seconds (~27.8 hours)\n /// Includes 256 epochs minimum withdrawability delay + 5 epochs from\n /// compute_activation_exit_epoch (MAX_SEED_LOOKAHEAD + 1).\n /// The actual time can be a lot longer than this depending on the number of\n /// requests in the beacon chain's pending consolidation queue.\n uint256 internal constant MIN_CONSOLIDATION_PERIOD = 261 * 32 * 12;\n\n /// @notice Address of the validator registrator account\n address public immutable validatorRegistrator;\n /// @dev The old Native Staking Strategy connected to the second SSV cluster\n address internal immutable nativeStakingStrategy2;\n /// @dev The old Native Staking Strategy connected to the third SSV cluster\n address internal immutable nativeStakingStrategy3;\n /// @dev The new Compounding Staking Strategy\n CompoundingStakingSSVStrategy internal immutable targetStrategy;\n\n /// @notice Number of validators being consolidated\n uint64 public consolidationCount;\n /// @notice Timestamp when the consolidation process was requested\n uint64 public consolidationStartTimestamp;\n /// @notice The address of the source Native Staking Strategy being consolidated from\n address public sourceStrategy;\n /// @notice The public key hash of the target validator on the new Compounding Staking Strategy\n bytes32 public targetPubKeyHash;\n /// @dev Tracks source validators that were requested for a consolidation round.\n /// Keyed by keccak256(sourcePubKeyHash, consolidationStartTimestamp).\n mapping(bytes32 => bool) private pendingSourceInRound;\n\n /// @dev Throws if called by any account other than the Validator Registrator\n modifier onlyRegistrator() {\n require(\n msg.sender == validatorRegistrator,\n \"Caller is not the Registrator\"\n );\n _;\n }\n\n /// @param _owner The owner who can request, fail and confirm consolidations\n /// @param _validatorRegistrator The validator registrator who does operations on the old staking strategy\n constructor(\n address _owner,\n address _validatorRegistrator,\n address _nativeStakingStrategy2,\n address _nativeStakingStrategy3,\n address _targetStrategy\n ) {\n _transferOwnership(_owner);\n\n validatorRegistrator = _validatorRegistrator;\n nativeStakingStrategy2 = _nativeStakingStrategy2;\n nativeStakingStrategy3 = _nativeStakingStrategy3;\n targetStrategy = CompoundingStakingSSVStrategy(\n payable(_targetStrategy)\n );\n }\n\n /**\n * @notice Request consolidation of validators from an old Native Staking Strategy\n * to the new Compounding Staking Strategy\n * @param _sourceStrategy The address of the old Native Staking Strategy\n * @param sourcePubKeys The public keys of the validators to be consolidated from the old Native Staking Strategy\n * @param targetPubKey The public key of the target validator on the new Compounding Staking Strategy\n */\n function requestConsolidation(\n address _sourceStrategy,\n bytes[] calldata sourcePubKeys,\n bytes calldata targetPubKey\n ) external payable onlyOwner {\n // Check no consolidations are already in progress\n require(consolidationCount == 0, \"Consolidation in progress\");\n // Check at least one source validator is provided\n require(sourcePubKeys.length > 0, \"Empty source validators\");\n // Check sourceStrategy is a valid old Native Staking Strategy\n _checkSourceStrategy(_sourceStrategy);\n\n // Check target validator is Active on the new Compounding Staking Strategy\n bytes32 targetPubKeyHashMem = _hashPubKey(targetPubKey);\n (CompoundingStakingSSVStrategy.ValidatorState state, ) = targetStrategy\n .validator(targetPubKeyHashMem);\n require(\n state == CompoundingValidatorManager.ValidatorState.ACTIVE,\n \"Target validator not active\"\n );\n // Check no pending deposits in the new target validator\n require(\n _hasPendingDeposit(targetPubKeyHashMem) == false,\n \"Target has pending deposit\"\n );\n\n // Store the state at the start of the consolidation process\n consolidationCount = SafeCast.toUint64(sourcePubKeys.length);\n uint64 consolidationStartTimestampMem = uint64(block.timestamp);\n consolidationStartTimestamp = consolidationStartTimestampMem;\n sourceStrategy = _sourceStrategy;\n targetPubKeyHash = targetPubKeyHashMem;\n\n // Store source validators for this consolidation round.\n for (uint256 i = 0; i < sourcePubKeys.length; ++i) {\n bytes32 roundKey = _sourceValidatorRoundKey(\n sourcePubKeys[i],\n consolidationStartTimestampMem\n );\n require(\n pendingSourceInRound[roundKey] == false,\n \"Duplicate source validator\"\n );\n pendingSourceInRound[roundKey] = true;\n }\n\n // Call requestConsolidation on the old Native Staking Strategy\n // to initiate the consolidations\n ValidatorAccountant(_sourceStrategy).requestConsolidation{\n value: msg.value\n }(sourcePubKeys, targetPubKey);\n\n // Snap the balances for the last time on the new Compounding Staking Strategy\n // if it hasn't been called recently. Otherwise skip to prevent a DoS\n // attack where an attacker front-runs this call with the permissionless snapBalances().\n (, uint64 lastSnapTimestamp, ) = targetStrategy.snappedBalance();\n if (\n uint64(block.timestamp) >\n lastSnapTimestamp + targetStrategy.SNAP_BALANCES_DELAY()\n ) {\n targetStrategy.snapBalances();\n }\n\n // No event emitted as ConsolidationRequested is emitted from the old Native Staking Strategy\n }\n\n /**\n * @notice A consolidation request can fail to be processed on the beacon chain\n * for various reasons. For example, the pending consolidation queue is full with 262,144 requests.\n * Or the source validator has exited from a voluntary exit request.\n * This reduces the consolidation count and changes the validator state back to STAKED.\n * @param sourcePubKeys The public keys of the source validators that failed to be consolidated.\n */\n function failConsolidation(bytes[] calldata sourcePubKeys)\n external\n onlyOwner\n {\n // Check consolidations are in progress\n require(consolidationCount > 0, \"No consolidation in progress\");\n // There a min time before a failed consolidation can be unwound.\n // This gives the beacon chain time to process the request.\n require(\n block.timestamp >=\n consolidationStartTimestamp + MIN_CONSOLIDATION_PERIOD,\n \"Source not withdrawable\"\n );\n require(\n sourcePubKeys.length <= consolidationCount,\n \"Exceeds consolidation count\"\n );\n uint64 consolidationStartTimestampMem = consolidationStartTimestamp;\n\n for (uint256 i = 0; i < sourcePubKeys.length; ++i) {\n bytes32 roundKey = _sourceValidatorRoundKey(\n sourcePubKeys[i],\n consolidationStartTimestampMem\n );\n require(pendingSourceInRound[roundKey], \"Unknown source validator\");\n pendingSourceInRound[roundKey] = false;\n }\n\n // Read into memory in case it gets reset in storage before\n // the external call to the source strategy\n address sourceStrategyMem = sourceStrategy;\n\n // Store updated consolidation state\n consolidationCount -= SafeCast.toUint64(sourcePubKeys.length);\n if (consolidationCount == 0) {\n // Reset the rest of the consolidation state\n consolidationStartTimestamp = 0;\n sourceStrategy = address(0);\n targetPubKeyHash = bytes32(0);\n }\n\n ValidatorAccountant(sourceStrategyMem).failConsolidation(sourcePubKeys);\n\n // No event emitted as ConsolidationFailed is emitted from the old Native Staking Strategy\n }\n\n /**\n * @notice Confirm the consolidation of validators from an old Native Staking Strategy\n * to the new Compounding Staking Strategy has been completed.\n * @param balanceProofs a `BalanceProofs` struct containing the following:\n * - balancesContainerRoot: The merkle root of the balances container\n * - balancesContainerProof: The merkle proof for the balances container to the beacon block root.\n * This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * - validatorBalanceLeaves: Array of leaf nodes containing the validator balance with three other balances.\n * - validatorBalanceProofs: Array of merkle proofs for the validator balance to the Balances container root.\n * This is 39 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * @param pendingDepositProofs a `PendingDepositProofs` struct containing the following:\n * - pendingDepositContainerRoot: The merkle root of the pending deposits list container\n * - pendingDepositContainerProof: The merkle proof from the pending deposits list container\n * to the beacon block root.\n * This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * - pendingDepositIndexes: Array of indexes in the pending deposits list container for each\n * of the strategy's deposits.\n * - pendingDepositProofs: Array of merkle proofs for each strategy deposit in the\n * beacon chain's pending deposit list container to the pending deposits list container root.\n * These are 28 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n */\n function confirmConsolidation(\n CompoundingValidatorManager.BalanceProofs calldata balanceProofs,\n CompoundingValidatorManager.PendingDepositProofs\n calldata pendingDepositProofs\n ) external onlyOwner {\n // Check consolidations are in progress\n require(consolidationCount > 0, \"No consolidation in progress\");\n // There a min time before a consolidation can be processed on the beacon chain\n (, uint64 snappedTimestamp, ) = targetStrategy.snappedBalance();\n require(\n uint64(snappedTimestamp) >\n consolidationStartTimestamp + MIN_CONSOLIDATION_PERIOD,\n \"Source not withdrawable\"\n );\n\n // Load into memory as the storage is about to be reset.\n // These are used in the external contract calls\n address sourceStrategyMem = sourceStrategy;\n uint256 consolidationCountMem = consolidationCount;\n\n // Reset consolidation state before external calls\n consolidationCount = 0;\n consolidationStartTimestamp = 0;\n sourceStrategy = address(0);\n targetPubKeyHash = bytes32(0);\n\n // Verify balances on the new Compounding Staking Strategy and update the strategy's balance\n targetStrategy.verifyBalances(balanceProofs, pendingDepositProofs);\n\n // Reduce the balance of the old Native Staking Strategy\n ValidatorAccountant(sourceStrategyMem).confirmConsolidation(\n consolidationCountMem\n );\n\n // No event emitted as ConsolidationConfirmed is emitted from the old Native Staking Strategy\n }\n\n /**\n *\n * Functions that forward to the old Native Staking Strategy\n *\n */\n\n /// @notice The validator registrator of the old Native Staking Strategy can call doAccounting\n /// @param _sourceStrategy The address of the old Native Staking Strategy\n /// @return accountingValid true if accounting was successful, false if fuse is blown\n function doAccounting(address _sourceStrategy)\n external\n onlyRegistrator\n returns (bool accountingValid)\n {\n // Check sourceStrategy is a valid old Native Staking Strategy\n _checkSourceStrategy(_sourceStrategy);\n\n return ValidatorAccountant(_sourceStrategy).doAccounting();\n }\n\n /**\n * @notice Exit of source validators are allowed during the consolidation process\n * as consolidated validators will be in EXITING state hence can not be consolidated after exit.\n * Only callable by the validator registrator.\n * @param _sourceStrategy The address of the old Native Staking Strategy\n * @param publicKey The public key of the validator to exit which must have STAKED state.\n * @param operatorIds The operator IDs for the source SSV cluster\n */\n function exitSsvValidator(\n address _sourceStrategy,\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external onlyRegistrator {\n // Check sourceStrategy is a valid old Native Staking Strategy\n _checkSourceStrategy(_sourceStrategy);\n\n ValidatorAccountant(_sourceStrategy).exitSsvValidator(\n publicKey,\n operatorIds\n );\n }\n\n /**\n * @notice Removing source validators is not allowed during the consolidation process\n * as consolidated validators will be in EXITING state hence can not be consolidated after removal.\n * Only callable by the validator registrator.\n * @param _sourceStrategy The address of the old Native Staking Strategy\n * @param publicKey The public key of the validator to remove which must have EXITING or REGISTERED state.\n * @param operatorIds The operator IDs for the source SSV cluster\n * @param cluster The SSV cluster information for the source validator\n */\n function removeSsvValidator(\n address _sourceStrategy,\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator {\n // Check sourceStrategy is a valid old Native Staking Strategy\n _checkSourceStrategy(_sourceStrategy);\n // Prevent removing a validator from the SSV cluster before the consolidation\n // process has been completed for the source strategy being consolidated.\n // This prevents validators that have been exited rather than consolidated but that's ok.\n // The exited validator can be removed after the consolidation process is complete.\n require(_sourceStrategy != sourceStrategy, \"Consolidation in progress\");\n\n ValidatorAccountant(_sourceStrategy).removeSsvValidator(\n publicKey,\n operatorIds,\n cluster\n );\n }\n\n /**\n *\n * Functions that forward to the new Compounding Staking Strategy\n *\n */\n\n /// @notice Forwards to the new Compounding Staking Strategy.\n /// Is only callable by the validator registrator when a consolidation is in progress.\n /// Anyone can call when there are no consolidations in progress.\n function snapBalances() external {\n if (consolidationCount > 0 && msg.sender != validatorRegistrator) {\n revert(\"Consolidation in progress\");\n }\n if (consolidationCount > 0) {\n require(\n block.timestamp >\n consolidationStartTimestamp + MIN_CONSOLIDATION_PERIOD,\n \"Source not withdrawable\"\n );\n }\n\n targetStrategy.snapBalances();\n }\n\n /**\n * @notice Anyone can verify balances on the new Compounding Staking Strategy\n * as long as there are no consolidations in progress.\n * @param balanceProofs a `BalanceProofs` struct containing the following:\n * - balancesContainerRoot: The merkle root of the balances container\n * - balancesContainerProof: The merkle proof for the balances container to the beacon block root.\n * This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * - validatorBalanceLeaves: Array of leaf nodes containing the validator balance with three other balances.\n * - validatorBalanceProofs: Array of merkle proofs for the validator balance to the Balances container root.\n * This is 39 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * @param pendingDepositProofs a `PendingDepositProofs` struct containing the following:\n * - pendingDepositContainerRoot: The merkle root of the pending deposits list container\n * - pendingDepositContainerProof: The merkle proof from the pending deposits list container\n * to the beacon block root.\n * This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * - pendingDepositIndexes: Array of indexes in the pending deposits list container for each\n * of the strategy's deposits.\n * - pendingDepositProofs: Array of merkle proofs for each strategy deposit in the\n * beacon chain's pending deposit list container to the pending deposits list container root.\n * These are 28 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n */\n function verifyBalances(\n CompoundingValidatorManager.BalanceProofs calldata balanceProofs,\n CompoundingValidatorManager.PendingDepositProofs\n calldata pendingDepositProofs\n ) external {\n (, uint64 snappedTimestamp, ) = targetStrategy.snappedBalance();\n // Can not verify balances while consolidations are in progress\n // if the snap was taken after the consolidation process started.\n // This still allows verifying a pre-existing snap.\n if (\n consolidationCount > 0 &&\n snappedTimestamp > consolidationStartTimestamp\n ) {\n revert(\"Consolidation in progress\");\n }\n\n targetStrategy.verifyBalances(balanceProofs, pendingDepositProofs);\n }\n\n /// @notice Partial withdrawals are allowed during consolidation from the new Compounding Staking Strategy.\n /// This includes partial withdrawals from the target validator.\n // Full validator exits from any Compounding Staking Strategy validator are\n /// not allowed during the migration period.\n /// Only the registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param amountGwei The amount of ETH to be withdrawn from the validator in Gwei.\n /// A zero amount is not allowed.\n function validatorWithdrawal(bytes calldata publicKey, uint64 amountGwei)\n external\n payable\n onlyRegistrator\n {\n // Prevent full exits from any new compounding validators.\n // This includes when there is no consolidation in progress.\n // This reduces the risk of an exit request being processed before a consolidation request\n require(amountGwei > 0, \"No exit during migration\");\n targetStrategy.validatorWithdrawal{ value: msg.value }(\n publicKey,\n amountGwei\n );\n }\n\n /**\n * @notice Deposits to Compounding Staking Strategy validators that are\n * not the target of a consolidation are allowed.\n * Only the registrator can call this function.\n * @param validatorStakeData validator data needed to stake.\n * The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot.\n * @param depositAmountGwei The amount of WETH to stake to the validator in Gwei.\n */\n function stakeEth(\n CompoundingValidatorManager.ValidatorStakeData\n calldata validatorStakeData,\n uint64 depositAmountGwei\n ) external onlyRegistrator {\n require(\n _hashPubKey(validatorStakeData.pubkey) != targetPubKeyHash,\n \"Stake to consolidation target\"\n );\n\n targetStrategy.stakeEth(validatorStakeData, depositAmountGwei);\n }\n\n /// removeSsvValidator from the new Compounding Staking Strategy is not allowed until after\n /// all the validators have been consolidated. This is done by restoring the validator registrator\n /// back to the account used before the consolidation upgrades.\n\n /**\n *\n * Internal Functions\n *\n */\n\n /// @dev Check if there are any pending deposits for a validator with a given public key hash.\n /// Need to iterate over the target strategy’s `deposits`\n /// @return True if there is at least one pending deposit for the validator\n function _hasPendingDeposit(bytes32 _targetPubKeyHash)\n internal\n view\n returns (bool)\n {\n uint256 depositsCount = targetStrategy.depositListLength();\n for (uint256 i = 0; i < depositsCount; ++i) {\n (\n bytes32 depositPubKeyHash,\n ,\n ,\n ,\n CompoundingValidatorManager.DepositStatus status\n ) = targetStrategy.deposits(targetStrategy.depositList(i));\n if (\n depositPubKeyHash == _targetPubKeyHash &&\n status == CompoundingValidatorManager.DepositStatus.PENDING\n ) {\n return true;\n }\n }\n return false;\n }\n\n /// @dev Hash a validator public key using the Beacon Chain's format\n /// @param pubKey The full validator public key\n /// @return The hashed public key using the Beacon Chain's hashing for BLSPubkey\n function _hashPubKey(bytes memory pubKey) internal pure returns (bytes32) {\n require(pubKey.length == 48, \"Invalid public key\");\n return sha256(abi.encodePacked(pubKey, bytes16(0)));\n }\n\n /// @dev Build a key for tracking source validators in a consolidation round.\n function _sourceValidatorRoundKey(\n bytes memory sourcePubKey,\n uint64 roundTimestamp\n ) internal pure returns (bytes32) {\n return keccak256(abi.encode(_hashPubKey(sourcePubKey), roundTimestamp));\n }\n\n /// @dev Check source strategy is a valid old Native Staking Strategy\n /// @param _sourceStrategy The address of the old Native Staking Strategy\n function _checkSourceStrategy(address _sourceStrategy) internal view {\n require(\n _sourceStrategy == nativeStakingStrategy2 ||\n _sourceStrategy == nativeStakingStrategy3,\n \"Invalid source strategy\"\n );\n }\n}\n" + }, + "contracts/strategies/NativeStaking/FeeAccumulator.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\n/**\n * @title Fee Accumulator for Native Staking SSV Strategy\n * @notice Receives execution rewards which includes tx fees and\n * MEV rewards like tx priority and tx ordering.\n * It does NOT include swept ETH from beacon chain consensus rewards or full validator withdrawals.\n * @author Origin Protocol Inc\n */\ncontract FeeAccumulator {\n /// @notice The address of the Native Staking Strategy\n address public immutable STRATEGY;\n\n event ExecutionRewardsCollected(address indexed strategy, uint256 amount);\n\n /**\n * @param _strategy Address of the Native Staking Strategy\n */\n constructor(address _strategy) {\n STRATEGY = _strategy;\n }\n\n /**\n * @notice sends all ETH in this FeeAccumulator contract to the Native Staking Strategy.\n * @return eth The amount of execution rewards that were sent to the Native Staking Strategy\n */\n function collect() external returns (uint256 eth) {\n require(msg.sender == STRATEGY, \"Caller is not the Strategy\");\n\n eth = address(this).balance;\n if (eth > 0) {\n // Send the ETH to the Native Staking Strategy\n Address.sendValue(payable(STRATEGY), eth);\n\n emit ExecutionRewardsCollected(STRATEGY, eth);\n }\n }\n\n /**\n * @dev Accept ETH\n */\n receive() external payable {}\n}\n" + }, + "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { FeeAccumulator } from \"./FeeAccumulator.sol\";\nimport { ValidatorAccountant } from \"./ValidatorAccountant.sol\";\nimport { ISSVNetwork } from \"../../interfaces/ISSVNetwork.sol\";\n\nstruct ValidatorStakeData {\n bytes pubkey;\n bytes signature;\n bytes32 depositDataRoot;\n}\n\n/// @title Native Staking SSV Strategy\n/// @notice Strategy to deploy funds into DVT validators powered by the SSV Network\n/// @author Origin Protocol Inc\n/// @dev This contract handles WETH and ETH and in some operations interchanges between the two. Any WETH that\n/// is on the contract across multiple blocks (and not just transitory within a transaction) is considered an\n/// asset. Meaning deposits increase the balance of the asset and withdrawal decrease it. As opposed to all\n/// our other strategies the WETH doesn't immediately get deposited into an underlying strategy and can be present\n/// across multiple blocks waiting to be unwrapped to ETH and staked to validators. This separation of WETH and ETH is\n/// required since the rewards (reward token) is also in ETH.\n///\n/// To simplify the accounting of WETH there is another difference in behavior compared to the other strategies.\n/// To withdraw WETH asset - exit message is posted to validators and the ETH hits this contract with multiple days\n/// delay. In order to simplify the WETH accounting upon detection of such an event the ValidatorAccountant\n/// immediately wraps ETH to WETH and sends it to the Vault.\n///\n/// On the other hand any ETH on the contract (across multiple blocks) is there either:\n/// - as a result of already accounted for consensus rewards\n/// - as a result of not yet accounted for consensus rewards\n/// - as a results of not yet accounted for full validator withdrawals (or validator slashes)\n///\n/// Even though the strategy assets and rewards are a very similar asset the consensus layer rewards and the\n/// execution layer rewards are considered rewards and those are dripped to the Vault over a configurable time\n/// interval and not immediately.\ncontract NativeStakingSSVStrategy is\n ValidatorAccountant,\n InitializableAbstractStrategy\n{\n using SafeERC20 for IERC20;\n\n /// @notice SSV ERC20 token that serves as a payment for operating SSV validators\n address public immutable SSV_TOKEN;\n /// @notice Fee collector address\n /// @dev this address will receive maximal extractable value (MEV) rewards. These are\n /// rewards for arranging transactions in a way that benefits the validator.\n address payable public immutable FEE_ACCUMULATOR_ADDRESS;\n\n /// @dev This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately\n /// deposit it to an underlying platform. Rather a special privilege account stakes it to the validators.\n /// For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been\n /// deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track\n /// of WETH that has already been accounted for.\n /// This value represents the amount of WETH balance of this contract that has already been accounted for by the\n /// deposit events.\n /// It is important to note that this variable is not concerned with WETH that is a result of full/partial\n /// withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to\n /// be staked.\n uint256 public depositedWethAccountedFor;\n\n // For future use\n uint256[49] private __gap;\n\n /// @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI,\n /// and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _ssvToken Address of the Erc20 SSV Token contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _maxValidators Maximum number of validators that can be registered in the strategy\n /// @param _feeAccumulator Address of the fee accumulator receiving execution layer validator rewards\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _wethAddress,\n address _ssvToken,\n address _ssvNetwork,\n uint256 _maxValidators,\n address _feeAccumulator,\n address _beaconChainDepositContract\n )\n InitializableAbstractStrategy(_baseConfig)\n ValidatorAccountant(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork,\n _maxValidators\n )\n {\n SSV_TOKEN = _ssvToken;\n FEE_ACCUMULATOR_ADDRESS = payable(_feeAccumulator);\n }\n\n /// @notice Set up initial internal state including\n /// 1. approving the SSVNetwork to transfer SSV tokens from this strategy contract\n /// 2. setting the recipient of SSV validator MEV rewards to the FeeAccumulator contract.\n /// @param _rewardTokenAddresses Address of reward token for platform\n /// @param _assets Addresses of initial supported assets\n /// @param _pTokens Platform Token corresponding addresses\n function initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n\n // Approves the SSV Network contract to transfer SSV tokens for deposits\n IERC20(SSV_TOKEN).approve(SSV_NETWORK, type(uint256).max);\n\n // Set the FeeAccumulator as the address for SSV validators to send MEV rewards to\n ISSVNetwork(SSV_NETWORK).setFeeRecipientAddress(\n FEE_ACCUMULATOR_ADDRESS\n );\n }\n\n /// @notice Unlike other strategies, this does not deposit assets into the underlying platform.\n /// It just checks the asset is WETH and emits the Deposit event.\n /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used.\n /// Will NOT revert if the strategy is paused from an accounting failure.\n /// @param _asset Address of asset to deposit. Has to be WETH.\n /// @param _amount Amount of assets that were transferred to the strategy by the vault.\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n require(_asset == WETH, \"Unsupported asset\");\n depositedWethAccountedFor += _amount;\n _deposit(_asset, _amount);\n }\n\n /// @dev Deposit WETH to this strategy so it can later be staked into a validator.\n /// @param _asset Address of WETH\n /// @param _amount Amount of WETH to deposit\n function _deposit(address _asset, uint256 _amount) internal {\n require(_amount > 0, \"Must deposit something\");\n /*\n * We could do a check here that would revert when \"_amount % 32 ether != 0\". With the idea of\n * not allowing deposits that will result in WETH sitting on the strategy after all the possible batches\n * of 32ETH have been staked.\n * But someone could mess with our strategy by sending some WETH to it. And we might want to deposit just\n * enough WETH to add it up to 32 so it can be staked. For that reason the check is left out.\n *\n * WETH sitting on the strategy won't interfere with the accounting since accounting only operates on ETH.\n */\n emit Deposit(_asset, address(0), _amount);\n }\n\n /// @notice Unlike other strategies, this does not deposit assets into the underlying platform.\n /// It just emits the Deposit event.\n /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used.\n /// Will NOT revert if the strategy is paused from an accounting failure.\n function depositAll() external override onlyVault nonReentrant {\n uint256 wethBalance = IERC20(WETH).balanceOf(address(this));\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\n\n if (newWeth > 0) {\n depositedWethAccountedFor = wethBalance;\n\n _deposit(WETH, newWeth);\n }\n }\n\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract.\n /// That can happen when:\n /// - after mints if the strategy is the default\n /// - time between depositToStrategy and stakeEth\n /// - the deposit was not a multiple of 32 WETH\n /// - someone sent WETH directly to this contract\n /// Will NOT revert if the strategy is paused from an accounting failure.\n /// @param _recipient Address to receive withdrawn assets\n /// @param _asset WETH to withdraw\n /// @param _amount Amount of WETH to withdraw\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_asset == WETH, \"Unsupported asset\");\n _withdraw(_recipient, _asset, _amount);\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n _wethWithdrawn(_amount);\n\n IERC20(_asset).safeTransfer(_recipient, _amount);\n emit Withdrawal(_asset, address(0), _amount);\n }\n\n /// @notice transfer all WETH deposits back to the vault.\n /// This does not withdraw from the validators. That has to be done separately with the\n /// `exitSsvValidator` and `removeSsvValidator` operations.\n /// This does not withdraw any execution rewards from the FeeAccumulator or\n /// consensus rewards in this strategy.\n /// Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn.\n /// ETH from full validator withdrawals is sent to the Vault using `doAccounting`.\n /// Will NOT revert if the strategy is paused from an accounting failure.\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 wethBalance = IERC20(WETH).balanceOf(address(this));\n if (wethBalance > 0) {\n _withdraw(vaultAddress, WETH, wethBalance);\n }\n }\n\n /// @notice Returns the total value of (W)ETH that is staked to the validators\n /// and WETH deposits that are still to be staked.\n /// This does not include ETH from consensus rewards sitting in this strategy\n /// or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested\n /// and sent to the Dripper so will eventually be sent to the Vault as WETH.\n /// @param _asset Address of weth asset\n /// @return balance Total value of (W)ETH\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == WETH, \"Unsupported asset\");\n\n balance =\n // add the ETH that has been staked in validators\n activeDepositedValidators *\n FULL_STAKE +\n // add the WETH in the strategy from deposits that are still to be staked\n IERC20(WETH).balanceOf(address(this));\n }\n\n function pause() external onlyStrategist {\n _pause();\n }\n\n /// @notice Returns bool indicating whether asset is supported by strategy.\n /// @param _asset The address of the asset token.\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == WETH;\n }\n\n /// @notice Approves the SSV Network contract to transfer SSV tokens for deposits\n function safeApproveAllTokens() external override {\n // Approves the SSV Network contract to transfer SSV tokens for deposits\n IERC20(SSV_TOKEN).approve(SSV_NETWORK, type(uint256).max);\n }\n\n /// @notice Set the FeeAccumulator as the address for SSV validators to send MEV rewards to\n function setFeeRecipient() external {\n ISSVNetwork(SSV_NETWORK).setFeeRecipientAddress(\n FEE_ACCUMULATOR_ADDRESS\n );\n }\n\n /**\n * @notice Only accept ETH from the FeeAccumulator and the WETH contract - required when\n * unwrapping WETH just before staking it to the validator.\n * The strategy will also receive ETH from the priority fees of transactions when producing blocks\n * as defined in EIP-1559.\n * The tx fees come from the Beacon chain so do not need any EVM level permissions to receive ETH.\n * The tx fees are paid with each block produced. They are not included in the consensus rewards\n * which are periodically swept from the validators to this strategy.\n * For accounting purposes, the priority fees of transactions will be considered consensus rewards\n * and will be included in the AccountingConsensusRewards event.\n * @dev don't want to receive donations from anyone else as donations over the fuse limits will\n * mess with the accounting of the consensus rewards and validator full withdrawals.\n */\n receive() external payable {\n require(\n msg.sender == FEE_ACCUMULATOR_ADDRESS || msg.sender == WETH,\n \"Eth not from allowed contracts\"\n );\n }\n\n /***************************************\n Internal functions\n ****************************************/\n\n function _abstractSetPToken(address _asset, address) internal override {}\n\n /// @dev Convert accumulated ETH to WETH and send to the Harvester.\n /// Will revert if the strategy is paused for accounting.\n function _collectRewardTokens() internal override whenNotPaused {\n // collect ETH from execution rewards from the fee accumulator\n uint256 executionRewards = FeeAccumulator(FEE_ACCUMULATOR_ADDRESS)\n .collect();\n\n // total ETH rewards to be harvested = execution rewards + consensus rewards\n uint256 ethRewards = executionRewards + consensusRewards;\n\n require(\n address(this).balance >= ethRewards,\n \"Insufficient eth balance\"\n );\n\n if (ethRewards > 0) {\n // reset the counter keeping track of beacon chain consensus rewards\n consensusRewards = 0;\n\n // Convert ETH rewards to WETH\n IWETH9(WETH).deposit{ value: ethRewards }();\n\n IERC20(WETH).safeTransfer(harvesterAddress, ethRewards);\n emit RewardTokenCollected(harvesterAddress, WETH, ethRewards);\n }\n }\n\n /// @dev emits Withdrawal event from NativeStakingSSVStrategy\n function _wethWithdrawnToVault(uint256 _amount) internal override {\n emit Withdrawal(WETH, address(0), _amount);\n }\n\n /// @dev Called when WETH is withdrawn from the strategy or staked to a validator so\n /// the strategy knows how much WETH it has on deposit.\n /// This is so it can emit the correct amount in the Deposit event in depositAll().\n function _wethWithdrawn(uint256 _amount) internal override {\n /* In an ideal world we wouldn't need to reduce the deduction amount when the\n * depositedWethAccountedFor is smaller than the _amount.\n *\n * The reason this is required is that a malicious actor could sent WETH directly\n * to this contract and that would circumvent the increase of depositedWethAccountedFor\n * property. When the ETH would be staked the depositedWethAccountedFor amount could\n * be deducted so much that it would be negative.\n */\n uint256 deductAmount = Math.min(_amount, depositedWethAccountedFor);\n depositedWethAccountedFor -= deductAmount;\n }\n}\n" + }, + "contracts/strategies/NativeStaking/ValidatorAccountant.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ValidatorRegistrator } from \"./ValidatorRegistrator.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\n\n/// @title Validator Accountant\n/// @notice Attributes the ETH swept from beacon chain validators to this strategy contract\n/// as either full or partial withdrawals. Partial withdrawals being consensus rewards.\n/// Full withdrawals are from exited validators.\n/// @author Origin Protocol Inc\nabstract contract ValidatorAccountant is ValidatorRegistrator {\n /// @notice The minimum amount of blocks that need to pass between two calls to manuallyFixAccounting\n uint256 public constant MIN_FIX_ACCOUNTING_CADENCE = 7200; // 1 day\n\n /// @notice Keeps track of the total consensus rewards swept from the beacon chain\n uint256 public consensusRewards;\n\n /// @notice start of fuse interval\n uint256 public fuseIntervalStart;\n /// @notice end of fuse interval\n uint256 public fuseIntervalEnd;\n /// @notice last block number manuallyFixAccounting has been called\n uint256 public lastFixAccountingBlockNumber;\n\n uint256[49] private __gap;\n\n event FuseIntervalUpdated(uint256 start, uint256 end);\n event AccountingFullyWithdrawnValidator(\n uint256 noOfValidators,\n uint256 remainingValidators,\n uint256 wethSentToVault\n );\n event AccountingValidatorSlashed(\n uint256 remainingValidators,\n uint256 wethSentToVault\n );\n event AccountingConsensusRewards(uint256 amount);\n\n event AccountingManuallyFixed(\n int256 validatorsDelta,\n int256 consensusRewardsDelta,\n uint256 wethToVault\n );\n\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _vaultAddress Address of the Vault\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _maxValidators Maximum number of validators that can be registered in the strategy\n constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork,\n uint256 _maxValidators\n )\n ValidatorRegistrator(\n _wethAddress,\n _vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork,\n _maxValidators\n )\n {}\n\n /// @notice set fuse interval values\n function setFuseInterval(\n uint256 _fuseIntervalStart,\n uint256 _fuseIntervalEnd\n ) external onlyGovernor {\n require(\n _fuseIntervalStart < _fuseIntervalEnd &&\n _fuseIntervalEnd < 32 ether &&\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\n \"Incorrect fuse interval\"\n );\n\n fuseIntervalStart = _fuseIntervalStart;\n fuseIntervalEnd = _fuseIntervalEnd;\n\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\n }\n\n /* solhint-disable max-line-length */\n /// This notion page offers a good explanation of how the accounting functions\n /// https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d\n /// In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart,\n /// the accounting function will treat that ETH as Beacon chain consensus rewards.\n /// On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32,\n /// the accounting function will treat that as a validator slashing.\n /// @notice Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when\n /// accounting is valid and fuse isn't \"blown\". Returns false when fuse is blown.\n /// @dev This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it\n /// for now.\n /// @return accountingValid true if accounting was successful, false if fuse is blown\n /* solhint-enable max-line-length */\n function doAccounting()\n external\n onlyRegistrator\n whenNotPaused\n nonReentrant\n returns (bool accountingValid)\n {\n // pause the accounting on failure\n accountingValid = _doAccounting(true);\n }\n\n // slither-disable-start reentrancy-eth\n function _doAccounting(bool pauseOnFail)\n internal\n returns (bool accountingValid)\n {\n if (address(this).balance < consensusRewards) {\n return _failAccounting(pauseOnFail);\n }\n\n // Calculate all the new ETH that has been swept to the contract since the last accounting\n uint256 newSweptETH = address(this).balance - consensusRewards;\n accountingValid = true;\n\n // send the ETH that is from fully withdrawn validators to the Vault\n if (newSweptETH >= FULL_STAKE) {\n uint256 fullyWithdrawnValidators;\n // explicitly cast to uint256 as we want to round to a whole number of validators\n fullyWithdrawnValidators = uint256(newSweptETH / FULL_STAKE);\n activeDepositedValidators -= fullyWithdrawnValidators;\n\n uint256 wethToVault = FULL_STAKE * fullyWithdrawnValidators;\n IWETH9(WETH).deposit{ value: wethToVault }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH).transfer(VAULT_ADDRESS, wethToVault);\n _wethWithdrawnToVault(wethToVault);\n\n emit AccountingFullyWithdrawnValidator(\n fullyWithdrawnValidators,\n activeDepositedValidators,\n wethToVault\n );\n }\n\n uint256 ethRemaining = address(this).balance - consensusRewards;\n // should be less than a whole validator stake\n require(ethRemaining < FULL_STAKE, \"Unexpected accounting\");\n\n // If no Beacon chain consensus rewards swept\n if (ethRemaining == 0) {\n // do nothing\n return accountingValid;\n } else if (ethRemaining < fuseIntervalStart) {\n // Beacon chain consensus rewards swept (partial validator withdrawals)\n // solhint-disable-next-line reentrancy\n consensusRewards += ethRemaining;\n emit AccountingConsensusRewards(ethRemaining);\n } else if (ethRemaining > fuseIntervalEnd) {\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\n IWETH9(WETH).deposit{ value: ethRemaining }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH).transfer(VAULT_ADDRESS, ethRemaining);\n activeDepositedValidators -= 1;\n\n _wethWithdrawnToVault(ethRemaining);\n\n emit AccountingValidatorSlashed(\n activeDepositedValidators,\n ethRemaining\n );\n }\n // Oh no... Fuse is blown. The Strategist needs to adjust the accounting values.\n else {\n return _failAccounting(pauseOnFail);\n }\n }\n\n // slither-disable-end reentrancy-eth\n\n /// @dev pause any further accounting if required and return false\n function _failAccounting(bool pauseOnFail)\n internal\n returns (bool accountingValid)\n {\n // pause if not already\n if (pauseOnFail) {\n _pause();\n }\n // fail the accounting\n accountingValid = false;\n }\n\n /// @notice Allow the Strategist to fix the accounting of this strategy and unpause.\n /// @param _validatorsDelta adjust the active validators by up to plus three or minus three\n /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down\n /// @param _ethToVaultAmount the amount of ETH that gets wrapped into WETH and sent to the Vault\n /// @dev There is a case when a validator(s) gets slashed so much that the eth swept from\n /// the beacon chain enters the fuse area and there are no consensus rewards on the contract\n /// to \"dip into\"/use. To increase the amount of unaccounted ETH over the fuse end interval\n /// we need to reduce the amount of active deposited validators and immediately send WETH\n /// to the vault, so it doesn't interfere with further accounting.\n function manuallyFixAccounting(\n int256 _validatorsDelta,\n int256 _consensusRewardsDelta,\n uint256 _ethToVaultAmount\n ) external onlyStrategist whenPaused nonReentrant {\n require(\n lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE <\n block.number,\n \"Fix accounting called too soon\"\n );\n require(\n _validatorsDelta >= -3 &&\n _validatorsDelta <= 3 &&\n // new value must be positive\n int256(activeDepositedValidators) + _validatorsDelta >= 0,\n \"Invalid validatorsDelta\"\n );\n require(\n _consensusRewardsDelta >= -332 ether &&\n _consensusRewardsDelta <= 332 ether &&\n // new value must be positive\n int256(consensusRewards) + _consensusRewardsDelta >= 0,\n \"Invalid consensusRewardsDelta\"\n );\n require(_ethToVaultAmount <= 32 ether * 3, \"Invalid wethToVaultAmount\");\n\n activeDepositedValidators = uint256(\n int256(activeDepositedValidators) + _validatorsDelta\n );\n consensusRewards = uint256(\n int256(consensusRewards) + _consensusRewardsDelta\n );\n lastFixAccountingBlockNumber = block.number;\n if (_ethToVaultAmount > 0) {\n IWETH9(WETH).deposit{ value: _ethToVaultAmount }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH).transfer(VAULT_ADDRESS, _ethToVaultAmount);\n _wethWithdrawnToVault(_ethToVaultAmount);\n }\n\n emit AccountingManuallyFixed(\n _validatorsDelta,\n _consensusRewardsDelta,\n _ethToVaultAmount\n );\n\n // rerun the accounting to see if it has now been fixed.\n // Do not pause the accounting on failure as it is already paused\n require(_doAccounting(false), \"Fuse still blown\");\n\n // unpause since doAccounting was successful\n _unpause();\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n /// @dev allows for NativeStakingSSVStrategy contract to emit the Withdrawal event\n function _wethWithdrawnToVault(uint256 _amount) internal virtual;\n}\n" + }, + "contracts/strategies/NativeStaking/ValidatorRegistrator.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { Governable } from \"../../governance/Governable.sol\";\nimport { IDepositContract } from \"../../interfaces/IDepositContract.sol\";\nimport { IVault } from \"../../interfaces/IVault.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { ISSVNetwork, Cluster } from \"../../interfaces/ISSVNetwork.sol\";\nimport { BeaconConsolidation } from \"../../beacon/BeaconConsolidation.sol\";\n\nstruct ValidatorStakeData {\n bytes pubkey;\n bytes signature;\n bytes32 depositDataRoot;\n}\n\n/**\n * @title Registrator of the validators\n * @notice This contract implements all the required functionality to register, exit and remove validators.\n * @author Origin Protocol Inc\n */\nabstract contract ValidatorRegistrator is Governable, Pausable {\n /// @notice The maximum amount of ETH that can be staked by a validator\n /// @dev this can change in the future with EIP-7251, Increase the MAX_EFFECTIVE_BALANCE\n uint256 public constant FULL_STAKE = 32 ether;\n\n /// @notice The address of the Wrapped ETH (WETH) token contract\n address public immutable WETH;\n /// @notice The address of the beacon chain deposit contract\n address public immutable BEACON_CHAIN_DEPOSIT_CONTRACT;\n /// @notice The address of the SSV Network contract used to interface with\n address public immutable SSV_NETWORK;\n /// @notice Address of the OETH Vault proxy contract\n address public immutable VAULT_ADDRESS;\n /// @notice Maximum number of validators that can be registered in this strategy\n uint256 public immutable MAX_VALIDATORS;\n\n /// @notice Address of the registrator - allowed to register, exit and remove validators\n address public validatorRegistrator;\n /// @notice The number of validators that have 32 (!) ETH actively deposited. When a new deposit\n /// to a validator happens this number increases, when a validator exit is detected this number\n /// decreases.\n uint256 public activeDepositedValidators;\n /// @notice State of the validators keccak256(pubKey) => state\n mapping(bytes32 => VALIDATOR_STATE) public validatorsStates;\n /// @notice The account that is allowed to reset stakeETHTally\n address public stakingMonitor;\n /// @notice Amount of ETH that can be staked before staking on the contract is suspended\n /// and the `stakingMonitor` needs to approve further staking by calling `resetStakeETHTally`\n uint256 public stakeETHThreshold;\n /// @notice Amount of ETH that has been staked since the `stakingMonitor` last called `resetStakeETHTally`.\n /// This can not go above `stakeETHThreshold`.\n uint256 public stakeETHTally;\n // For future use\n uint256[47] private __gap;\n\n enum VALIDATOR_STATE {\n NON_REGISTERED, // validator is not registered on the SSV network\n REGISTERED, // validator is registered on the SSV network\n STAKED, // validator has funds staked\n EXITING, // exit message has been posted and validator is in the process of exiting\n EXIT_COMPLETE // validator has funds withdrawn to the EigenPod and is removed from the SSV\n }\n\n event RegistratorChanged(address indexed newAddress);\n event StakingMonitorChanged(address indexed newAddress);\n event ETHStaked(bytes32 indexed pubKeyHash, bytes pubKey, uint256 amount);\n event SSVValidatorRegistered(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint64[] operatorIds\n );\n event SSVValidatorExitInitiated(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint64[] operatorIds\n );\n event SSVValidatorExitCompleted(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint64[] operatorIds\n );\n event ConsolidationRequested(\n bytes[] sourcePubKeys,\n bytes targetPubKey,\n uint256 consolidationCount\n );\n event ConsolidationFailed(\n bytes[] sourcePubKeys,\n uint256 consolidationCount\n );\n event ConsolidationConfirmed(\n uint256 consolidationCount,\n uint256 activeDepositedValidators\n );\n event StakeETHThresholdChanged(uint256 amount);\n event StakeETHTallyReset();\n\n /// @dev Throws if called by any account other than the Registrator\n modifier onlyRegistrator() {\n require(\n msg.sender == validatorRegistrator,\n \"Caller is not the Registrator\"\n );\n _;\n }\n\n /// @dev Throws if called by any account other than the Staking monitor\n modifier onlyStakingMonitor() {\n require(msg.sender == stakingMonitor, \"Caller is not the Monitor\");\n _;\n }\n\n /// @dev Throws if called by any account other than the Strategist\n modifier onlyStrategist() {\n require(\n msg.sender == IVault(VAULT_ADDRESS).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n _;\n }\n\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _vaultAddress Address of the Vault\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _maxValidators Maximum number of validators that can be registered in the strategy\n constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork,\n uint256 _maxValidators\n ) {\n WETH = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK = _ssvNetwork;\n VAULT_ADDRESS = _vaultAddress;\n MAX_VALIDATORS = _maxValidators;\n }\n\n /// @notice Set the address of the registrator which can register, exit and remove validators\n function setRegistrator(address _address) external onlyGovernor {\n validatorRegistrator = _address;\n emit RegistratorChanged(_address);\n }\n\n /// @notice Set the address of the staking monitor that is allowed to reset stakeETHTally\n function setStakingMonitor(address _address) external onlyGovernor {\n stakingMonitor = _address;\n emit StakingMonitorChanged(_address);\n }\n\n /// @notice Set the amount of ETH that can be staked before staking monitor\n // needs to a approve further staking by resetting the stake ETH tally\n function setStakeETHThreshold(uint256 _amount) external onlyGovernor {\n stakeETHThreshold = _amount;\n emit StakeETHThresholdChanged(_amount);\n }\n\n /// @notice Reset the stakeETHTally\n function resetStakeETHTally() external onlyStakingMonitor {\n stakeETHTally = 0;\n emit StakeETHTallyReset();\n }\n\n /// @notice Stakes WETH to the node validators\n /// @param validators A list of validator data needed to stake.\n /// The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot.\n /// Only the registrator can call this function.\n // slither-disable-start reentrancy-eth\n function stakeEth(ValidatorStakeData[] calldata validators)\n external\n onlyRegistrator\n whenNotPaused\n nonReentrant\n {\n uint256 requiredETH = validators.length * FULL_STAKE;\n\n // Check there is enough WETH from the deposits sitting in this strategy contract\n require(\n requiredETH <= IWETH9(WETH).balanceOf(address(this)),\n \"Insufficient WETH\"\n );\n require(\n activeDepositedValidators + validators.length <= MAX_VALIDATORS,\n \"Max validators reached\"\n );\n\n require(\n stakeETHTally + requiredETH <= stakeETHThreshold,\n \"Staking ETH over threshold\"\n );\n stakeETHTally += requiredETH;\n\n // Convert required ETH from WETH\n IWETH9(WETH).withdraw(requiredETH);\n _wethWithdrawn(requiredETH);\n\n /* 0x01 to indicate that withdrawal credentials will contain an EOA address that the sweeping function\n * can sweep funds to.\n * bytes11(0) to fill up the required zeros\n * remaining bytes20 are for the address\n */\n bytes memory withdrawalCredentials = abi.encodePacked(\n bytes1(0x01),\n bytes11(0),\n address(this)\n );\n\n // For each validator\n for (uint256 i = 0; i < validators.length; ++i) {\n bytes32 pubKeyHash = keccak256(validators[i].pubkey);\n\n require(\n validatorsStates[pubKeyHash] == VALIDATOR_STATE.REGISTERED,\n \"Validator not registered\"\n );\n\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\n value: FULL_STAKE\n }(\n validators[i].pubkey,\n withdrawalCredentials,\n validators[i].signature,\n validators[i].depositDataRoot\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.STAKED;\n\n emit ETHStaked(pubKeyHash, validators[i].pubkey, FULL_STAKE);\n }\n // save gas by changing this storage variable only once rather each time in the loop.\n activeDepositedValidators += validators.length;\n }\n\n // slither-disable-end reentrancy-eth\n\n /// @notice Registers a new validator in the SSV Cluster.\n /// Only the registrator can call this function.\n /// @param publicKeys The public keys of the validators\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param sharesData The shares data for each validator\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n // slither-disable-start reentrancy-no-eth\n function registerSsvValidators(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds,\n bytes[] calldata sharesData,\n Cluster calldata cluster\n ) external payable onlyRegistrator whenNotPaused {\n require(\n publicKeys.length == sharesData.length,\n \"Pubkey sharesData mismatch\"\n );\n // Check each public key has not already been used\n bytes32 pubKeyHash;\n VALIDATOR_STATE currentState;\n for (uint256 i = 0; i < publicKeys.length; ++i) {\n pubKeyHash = keccak256(publicKeys[i]);\n currentState = validatorsStates[pubKeyHash];\n require(\n currentState == VALIDATOR_STATE.NON_REGISTERED,\n \"Validator already registered\"\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.REGISTERED;\n\n emit SSVValidatorRegistered(pubKeyHash, publicKeys[i], operatorIds);\n }\n\n ISSVNetwork(SSV_NETWORK).bulkRegisterValidator{ value: msg.value }(\n publicKeys,\n operatorIds,\n sharesData,\n cluster\n );\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Exit a validator from the Beacon chain.\n /// The staked ETH will eventually swept to this native staking strategy.\n /// Only the registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n // slither-disable-start reentrancy-no-eth\n function exitSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external onlyRegistrator whenNotPaused {\n bytes32 pubKeyHash = keccak256(publicKey);\n VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];\n require(currentState == VALIDATOR_STATE.STAKED, \"Validator not staked\");\n\n ISSVNetwork(SSV_NETWORK).exitValidator(publicKey, operatorIds);\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXITING;\n\n emit SSVValidatorExitInitiated(pubKeyHash, publicKey, operatorIds);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Remove a validator from the SSV Cluster.\n /// Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain.\n /// If removed before the validator has exited the beacon chain will result in the validator being slashed.\n /// Only the registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n // slither-disable-start reentrancy-no-eth\n function removeSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n bytes32 pubKeyHash = keccak256(publicKey);\n VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];\n // Can remove SSV validators that were incorrectly registered and can not be deposited to.\n require(\n currentState == VALIDATOR_STATE.EXITING ||\n currentState == VALIDATOR_STATE.REGISTERED,\n \"Validator not regd or exiting\"\n );\n\n ISSVNetwork(SSV_NETWORK).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXIT_COMPLETE;\n\n emit SSVValidatorExitCompleted(pubKeyHash, publicKey, operatorIds);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Migrate the SSV cluster to use ETH for payment instead of SSV tokens.\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n function migrateClusterToETH(\n uint64[] memory operatorIds,\n Cluster memory cluster\n ) external payable onlyGovernor {\n ISSVNetwork(SSV_NETWORK).migrateClusterToETH{ value: msg.value }(\n operatorIds,\n cluster\n );\n\n // The SSV Network emits\n // ClusterMigratedToETH(msg.sender, operatorIds, msg.value, ssvClusterBalance, effectiveBalance, cluster)\n }\n\n /***************************************\n Consolidation functions\n ****************************************/\n\n /**\n * @notice Initiates the consolidation of multiple source sweeping validators to a single compounding validator.\n * @dev The validator registrator should be set to the ConsolidationController contract which\n * has checks against the target validator.\n * @param sourcePubKeys The full public keys of the source validators to be consolidated.\n * @param targetPubKey The full public key of the target validator to consolidate into.\n */\n // slither-disable-start reentrancy-no-eth\n function requestConsolidation(\n bytes[] calldata sourcePubKeys,\n bytes calldata targetPubKey\n ) external payable nonReentrant whenNotPaused onlyRegistrator {\n // Hash using the Native Staking Strategy's hashing method.\n // This is different to the Beacon chain's method.\n bytes32 targetPubKeyHash = keccak256(targetPubKey);\n bytes32 sourcePubKeyHash;\n uint256 totalConsolidationFees = 0;\n\n // For each source validator\n for (uint256 i = 0; i < sourcePubKeys.length; ++i) {\n sourcePubKeyHash = keccak256(sourcePubKeys[i]);\n require(sourcePubKeys[i].length == 48, \"Invalid source public key\");\n require(sourcePubKeyHash != targetPubKeyHash, \"Self consolidation\");\n require(\n validatorsStates[sourcePubKeyHash] == VALIDATOR_STATE.STAKED,\n \"Source validator not staked\"\n );\n\n // Store the state of the source validator as exiting so it can be removed\n // after the consolidation is confirmed\n validatorsStates[sourcePubKeyHash] = VALIDATOR_STATE.EXITING;\n\n // Request consolidation from source to target validator\n totalConsolidationFees += BeaconConsolidation.request(\n sourcePubKeys[i],\n targetPubKey\n );\n }\n\n require(\n totalConsolidationFees <= msg.value,\n \"Insufficient consolidation fee\"\n );\n\n emit ConsolidationRequested(\n sourcePubKeys,\n targetPubKey,\n sourcePubKeys.length\n );\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /**\n * @notice A consolidation request can fail to be processed on the beacon chain\n * for various reasons. For example, the pending consolidation queue is full with 262,144 requests.\n * This restores the validator states back to STAKED so they can be consolidated again or exited.\n * @param sourcePubKeys The full public keys of the source validators that failed to be consolidated.\n */\n function failConsolidation(bytes[] calldata sourcePubKeys)\n external\n nonReentrant\n whenNotPaused\n onlyRegistrator\n {\n bytes32 sourcePubKeyHash;\n\n // For each failed source validator\n for (uint256 i = 0; i < sourcePubKeys.length; ++i) {\n require(sourcePubKeys[i].length == 48, \"Invalid source public key\");\n sourcePubKeyHash = keccak256(sourcePubKeys[i]);\n require(\n validatorsStates[sourcePubKeyHash] == VALIDATOR_STATE.EXITING,\n \"Source validator not exiting\"\n );\n\n // Store the state of the source validator back to staked\n validatorsStates[sourcePubKeyHash] = VALIDATOR_STATE.STAKED;\n }\n\n emit ConsolidationFailed(sourcePubKeys, sourcePubKeys.length);\n }\n\n /**\n * @notice Confirms that a consolidation has completed successfully on the beacon chain.\n * This reduces the number of active deposited validators managed by this strategy which\n * reduces the strategy's balance.\n * @param consolidationCount The number of source validators that were consolidated.\n */\n function confirmConsolidation(uint256 consolidationCount)\n external\n nonReentrant\n whenNotPaused\n onlyRegistrator\n {\n // Store the reduced number of active deposited validators\n // managed by this strategy\n activeDepositedValidators -= consolidationCount;\n\n emit ConsolidationConfirmed(\n consolidationCount,\n activeDepositedValidators\n );\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n /// @dev Called when WETH is withdrawn from the strategy or staked to a validator so\n /// the strategy knows how much WETH it has on deposit.\n /// This is so it can emit the correct amount in the Deposit event in depositAll().\n function _wethWithdrawn(uint256 _amount) internal virtual;\n}\n" + }, + "contracts/strategies/sonic/SonicStakingStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SonicValidatorDelegator } from \"./SonicValidatorDelegator.sol\";\nimport { IWrappedSonic } from \"../../interfaces/sonic/IWrappedSonic.sol\";\n\n/**\n * @title Staking Strategy for Sonic's native S currency\n * @author Origin Protocol Inc\n */\ncontract SonicStakingStrategy is SonicValidatorDelegator {\n // For future use\n uint256[50] private __gap;\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _wrappedSonic,\n address _sfc\n ) SonicValidatorDelegator(_baseConfig, _wrappedSonic, _sfc) {}\n\n /// @notice Deposit wrapped S asset into the underlying platform.\n /// @param _asset Address of asset to deposit. Has to be Wrapped Sonic (wS).\n /// @param _amount Amount of assets that were transferred to the strategy by the vault.\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n require(_asset == wrappedSonic, \"Unsupported asset\");\n _deposit(_asset, _amount);\n }\n\n /**\n * @notice Deposit Wrapped Sonic (wS) to this strategy and delegate to a validator.\n * @param _asset Address of Wrapped Sonic (wS) token\n * @param _amount Amount of Wrapped Sonic (wS) to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal virtual {\n require(_amount > 0, \"Must deposit something\");\n\n _delegate(_amount);\n emit Deposit(_asset, address(0), _amount);\n }\n\n /**\n * @notice Deposit the entire balance of wrapped S in this strategy contract into\n * the underlying platform.\n */\n function depositAll() external virtual override onlyVault nonReentrant {\n uint256 wSBalance = IERC20(wrappedSonic).balanceOf(address(this));\n\n if (wSBalance > 0) {\n _deposit(wrappedSonic, wSBalance);\n }\n }\n\n /// @notice Withdraw Wrapped Sonic (wS) from this strategy contract.\n /// Used only if some wS is lingering on the contract.\n /// That can happen only when someone sends wS directly to this contract\n /// @param _recipient Address to receive withdrawn assets\n /// @param _asset Address of the Wrapped Sonic (wS) token\n /// @param _amount Amount of Wrapped Sonic (wS) to withdraw\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_asset == wrappedSonic, \"Unsupported asset\");\n _withdraw(_recipient, _asset, _amount);\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal override {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n // slither-disable-next-line unchecked-transfer unused-return\n IERC20(_asset).transfer(_recipient, _amount);\n\n emit Withdrawal(wrappedSonic, address(0), _amount);\n }\n\n /// @notice Transfer all Wrapped Sonic (wS) deposits back to the vault.\n /// This does not withdraw from delegated validators. That has to be done separately with `undelegate`.\n /// Any native S in this strategy will be withdrawn.\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 balance = address(this).balance;\n if (balance > 0) {\n IWrappedSonic(wrappedSonic).deposit{ value: balance }();\n }\n uint256 wSBalance = IERC20(wrappedSonic).balanceOf(address(this));\n if (wSBalance > 0) {\n _withdraw(vaultAddress, wrappedSonic, wSBalance);\n }\n }\n\n /**\n * @dev Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset token\n */\n function supportsAsset(address _asset)\n public\n view\n virtual\n override\n returns (bool)\n {\n return _asset == wrappedSonic;\n }\n\n /**\n * @notice is not supported for this strategy as the\n * Wrapped Sonic (wS) token is set at deploy time.\n */\n function setPTokenAddress(address, address)\n external\n view\n override\n onlyGovernor\n {\n revert(\"unsupported function\");\n }\n\n /// @notice is not used by this strategy as all staking rewards are restaked\n function collectRewardTokens() external override nonReentrant {\n revert(\"unsupported function\");\n }\n\n /**\n * @notice is not supported for this strategy as the\n * Wrapped Sonic (wS) token is set at deploy time.\n */\n function removePToken(uint256) external view override onlyGovernor {\n revert(\"unsupported function\");\n }\n\n /// @dev is not used by this strategy but must be implemented as it's abstract\n /// in the inherited `InitializableAbstractStrategy` contract.\n function _abstractSetPToken(address, address) internal virtual override {}\n\n /// @notice is not used by this strategy\n function safeApproveAllTokens() external override onlyGovernor {}\n}\n" + }, + "contracts/strategies/sonic/SonicSwapXAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title SwapX Algorithmic Market Maker (AMO) Strategy\n * @notice AMO strategy for the SwapX OS/wS stable pool\n * @author Origin Protocol Inc\n */\nimport { StableSwapAMMStrategy } from \"../algebra/StableSwapAMMStrategy.sol\";\nimport { IGauge } from \"../../interfaces/algebra/IAlgebraGauge.sol\";\n\ncontract SonicSwapXAMOStrategy is StableSwapAMMStrategy {\n /**\n * @param _baseConfig The `platformAddress` is the address of the SwapX pool.\n * The `vaultAddress` is the address of the Origin Sonic Vault.\n * @param _gauge Address of the SwapX gauge for the pool.\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _gauge)\n StableSwapAMMStrategy(_baseConfig, _gauge, IGauge(_gauge).TOKEN())\n {}\n}\n" + }, + "contracts/strategies/sonic/SonicValidatorDelegator.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IVault } from \"../../interfaces/IVault.sol\";\nimport { ISFC } from \"../../interfaces/sonic/ISFC.sol\";\nimport { IWrappedSonic } from \"../../interfaces/sonic/IWrappedSonic.sol\";\n\n/**\n * @title Manages delegation to Sonic validators\n * @notice This contract implements all the required functionality to delegate to,\n undelegate from and withdraw from validators.\n * @author Origin Protocol Inc\n */\nabstract contract SonicValidatorDelegator is InitializableAbstractStrategy {\n /// @notice Address of Sonic's wrapped S token\n address public immutable wrappedSonic;\n /// @notice Sonic's Special Fee Contract (SFC)\n ISFC public immutable sfc;\n\n /// @notice a unique ID for each withdrawal request\n uint256 public nextWithdrawId;\n /// @notice Sonic (S) that is pending withdrawal after undelegating\n uint256 public pendingWithdrawals;\n\n /// @notice List of supported validator IDs that can be delegated to\n uint256[] public supportedValidators;\n\n /// @notice Default validator id to deposit to\n uint256 public defaultValidatorId;\n\n struct WithdrawRequest {\n uint256 validatorId;\n uint256 undelegatedAmount;\n uint256 timestamp;\n }\n /// @notice Mapping of withdrawIds to validatorIds and undelegatedAmounts\n mapping(uint256 => WithdrawRequest) public withdrawals;\n\n /// @notice Address of the registrator - allowed to register, exit and remove validators\n address public validatorRegistrator;\n\n // For future use\n uint256[44] private __gap;\n\n event Delegated(uint256 indexed validatorId, uint256 delegatedAmount);\n event Undelegated(\n uint256 indexed withdrawId,\n uint256 indexed validatorId,\n uint256 undelegatedAmount\n );\n event Withdrawn(\n uint256 indexed withdrawId,\n uint256 indexed validatorId,\n uint256 undelegatedAmount,\n uint256 withdrawnAmount\n );\n event RegistratorChanged(address indexed newAddress);\n event SupportedValidator(uint256 indexed validatorId);\n event UnsupportedValidator(uint256 indexed validatorId);\n event DefaultValidatorIdChanged(uint256 indexed validatorId);\n\n /// @dev Throws if called by any account other than the Registrator or Strategist\n modifier onlyRegistratorOrStrategist() {\n require(\n msg.sender == validatorRegistrator ||\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Registrator or Strategist\"\n );\n _;\n }\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _wrappedSonic,\n address _sfc\n ) InitializableAbstractStrategy(_baseConfig) {\n wrappedSonic = _wrappedSonic;\n sfc = ISFC(_sfc);\n }\n\n function initialize() external virtual onlyGovernor initializer {\n address[] memory rewardTokens = new address[](0);\n address[] memory assets = new address[](1);\n address[] memory pTokens = new address[](1);\n\n assets[0] = address(wrappedSonic);\n pTokens[0] = address(platformAddress);\n\n InitializableAbstractStrategy._initialize(\n rewardTokens,\n assets,\n pTokens\n );\n }\n\n /// @notice Returns the total value of Sonic (S) that is delegated validators.\n /// Wrapped Sonic (wS) deposits that are still to be delegated and any undelegated amounts\n /// still pending a withdrawal.\n /// @param _asset Address of Wrapped Sonic (wS) token\n /// @return balance Total value managed by the strategy\n function checkBalance(address _asset)\n external\n view\n virtual\n override\n returns (uint256 balance)\n {\n require(_asset == wrappedSonic, \"Unsupported asset\");\n\n // add the Wrapped Sonic (wS) in the strategy from deposits that are still to be delegated\n // and any undelegated amounts still pending a withdrawal\n balance =\n IERC20(wrappedSonic).balanceOf(address(this)) +\n pendingWithdrawals;\n\n // For each supported validator, get the staked amount and pending rewards\n uint256 validatorLen = supportedValidators.length;\n for (uint256 i = 0; i < validatorLen; i++) {\n uint256 validator = supportedValidators[i];\n balance += sfc.getStake(address(this), validator);\n balance += sfc.pendingRewards(address(this), validator);\n }\n }\n\n /**\n * @dev Delegate from this strategy to a specific Sonic validator. Called\n * automatically on asset deposit\n * @param _amount the amount of Sonic (S) to delegate.\n */\n function _delegate(uint256 _amount) internal {\n require(\n isSupportedValidator(defaultValidatorId),\n \"Validator not supported\"\n );\n\n // unwrap Wrapped Sonic (wS) to native Sonic (S)\n IWrappedSonic(wrappedSonic).withdraw(_amount);\n\n //slither-disable-next-line arbitrary-send-eth\n sfc.delegate{ value: _amount }(defaultValidatorId);\n\n emit Delegated(defaultValidatorId, _amount);\n }\n\n /**\n * @notice Undelegate from a specific Sonic validator.\n * This needs to be followed by a `withdrawFromSFC` two weeks later.\n * @param _validatorId The Sonic validator ID to undelegate from.\n * @param _undelegateAmount the amount of Sonic (S) to undelegate.\n * @return withdrawId The unique ID of the withdrawal request.\n */\n function undelegate(uint256 _validatorId, uint256 _undelegateAmount)\n external\n onlyRegistratorOrStrategist\n nonReentrant\n returns (uint256 withdrawId)\n {\n withdrawId = _undelegate(_validatorId, _undelegateAmount);\n }\n\n function _undelegate(uint256 _validatorId, uint256 _undelegateAmount)\n internal\n returns (uint256 withdrawId)\n {\n // Can still undelegate even if the validator is no longer supported\n require(_undelegateAmount > 0, \"Must undelegate something\");\n\n uint256 amountDelegated = sfc.getStake(address(this), _validatorId);\n require(\n _undelegateAmount <= amountDelegated,\n \"Insufficient delegation\"\n );\n\n withdrawId = nextWithdrawId++;\n\n withdrawals[withdrawId] = WithdrawRequest(\n _validatorId,\n _undelegateAmount,\n block.timestamp\n );\n pendingWithdrawals += _undelegateAmount;\n\n sfc.undelegate(_validatorId, withdrawId, _undelegateAmount);\n\n emit Undelegated(withdrawId, _validatorId, _undelegateAmount);\n }\n\n /**\n * @notice Withdraw native S from a previously undelegated validator.\n * The native S is wrapped wS and transferred to the Vault.\n * @param _withdrawId The unique withdraw ID used to `undelegate`\n * @return withdrawnAmount The amount of Sonic (S) withdrawn.\n * This can be less than the undelegated amount in the event of slashing.\n */\n function withdrawFromSFC(uint256 _withdrawId)\n external\n onlyRegistratorOrStrategist\n nonReentrant\n returns (uint256 withdrawnAmount)\n {\n require(_withdrawId < nextWithdrawId, \"Invalid withdrawId\");\n\n // Can still withdraw even if the validator is no longer supported\n // Load the withdrawal from storage into memory\n WithdrawRequest memory withdrawal = withdrawals[_withdrawId];\n require(!isWithdrawnFromSFC(_withdrawId), \"Already withdrawn\");\n\n withdrawals[_withdrawId].undelegatedAmount = 0;\n pendingWithdrawals -= withdrawal.undelegatedAmount;\n\n uint256 sBalanceBefore = address(this).balance;\n\n // Try to withdraw from SFC\n try sfc.withdraw(withdrawal.validatorId, _withdrawId) {\n // continue below\n } catch (bytes memory err) {\n bytes4 errorSelector = bytes4(err);\n\n // If the validator has been fully slashed, SFC's withdraw function will\n // revert with a StakeIsFullySlashed custom error.\n if (errorSelector == ISFC.StakeIsFullySlashed.selector) {\n // The validator was fully slashed, so all the delegated amounts were lost.\n // Will swallow the error as we still want to update the\n // withdrawals and pendingWithdrawals storage variables.\n\n // The return param defaults to zero but lets set it explicitly so it's clear\n withdrawnAmount = 0;\n\n emit Withdrawn(\n _withdrawId,\n withdrawal.validatorId,\n withdrawal.undelegatedAmount,\n withdrawnAmount\n );\n\n // Exit here as there is nothing to transfer to the Vault\n return withdrawnAmount;\n } else {\n // Bubble up any other SFC custom errors.\n // Inline assembly is currently the only way to generically rethrow the exact same custom error\n // from the raw bytes err in a catch block while preserving its original selector and parameters.\n // solhint-disable-next-line no-inline-assembly\n assembly {\n revert(add(32, err), mload(err))\n }\n }\n }\n\n // Set return parameter\n withdrawnAmount = address(this).balance - sBalanceBefore;\n\n // Wrap Sonic (S) to Wrapped Sonic (wS)\n IWrappedSonic(wrappedSonic).deposit{ value: withdrawnAmount }();\n\n // Transfer the Wrapped Sonic (wS) to the Vault\n _withdraw(vaultAddress, wrappedSonic, withdrawnAmount);\n\n // withdrawal.undelegatedAmount & withdrawnAmount can differ in case of slashing\n emit Withdrawn(\n _withdrawId,\n withdrawal.validatorId,\n withdrawal.undelegatedAmount,\n withdrawnAmount\n );\n }\n\n /// @notice returns a bool whether a withdrawalId has already been withdrawn or not\n /// @param _withdrawId The unique withdraw ID used to `undelegate`\n function isWithdrawnFromSFC(uint256 _withdrawId)\n public\n view\n returns (bool)\n {\n WithdrawRequest memory withdrawal = withdrawals[_withdrawId];\n require(withdrawal.validatorId > 0, \"Invalid withdrawId\");\n return withdrawal.undelegatedAmount == 0;\n }\n\n /**\n * @notice Restake any pending validator rewards for all supported validators\n * @param _validatorIds List of Sonic validator IDs to restake rewards\n */\n function restakeRewards(uint256[] calldata _validatorIds)\n external\n nonReentrant\n {\n for (uint256 i = 0; i < _validatorIds.length; ++i) {\n require(\n isSupportedValidator(_validatorIds[i]),\n \"Validator not supported\"\n );\n\n uint256 rewards = sfc.pendingRewards(\n address(this),\n _validatorIds[i]\n );\n\n if (rewards > 0) {\n sfc.restakeRewards(_validatorIds[i]);\n }\n }\n\n // The SFC contract will emit Delegated and RestakedRewards events.\n // The checkBalance function should not change as the pending rewards will moved to the staked amount.\n }\n\n /**\n * @notice Claim any pending rewards from validators\n * @param _validatorIds List of Sonic validator IDs to claim rewards\n */\n function collectRewards(uint256[] calldata _validatorIds)\n external\n onlyRegistratorOrStrategist\n nonReentrant\n {\n uint256 sBalanceBefore = address(this).balance;\n\n for (uint256 i = 0; i < _validatorIds.length; ++i) {\n uint256 rewards = sfc.pendingRewards(\n address(this),\n _validatorIds[i]\n );\n\n if (rewards > 0) {\n // The SFC contract will emit ClaimedRewards(delegator (this), validatorId, rewards)\n sfc.claimRewards(_validatorIds[i]);\n }\n }\n\n uint256 rewardsAmount = address(this).balance - sBalanceBefore;\n\n // Wrap Sonic (S) to Wrapped Sonic (wS)\n IWrappedSonic(wrappedSonic).deposit{ value: rewardsAmount }();\n\n // Transfer the Wrapped Sonic (wS) to the Vault\n _withdraw(vaultAddress, wrappedSonic, rewardsAmount);\n }\n\n /**\n * @notice To receive native S from SFC and Wrapped Sonic (wS)\n *\n * @dev This does not prevent donating S tokens to the contract\n * as wrappedSonic has a `withdrawTo` function where a third party\n * owner of wrappedSonic can withdraw to this contract.\n */\n receive() external payable {\n require(\n msg.sender == address(sfc) || msg.sender == wrappedSonic,\n \"S not from allowed contracts\"\n );\n }\n\n /***************************************\n Admin functions\n ****************************************/\n\n /// @notice Set the address of the Registrator which can undelegate, withdraw and collect rewards\n /// @param _validatorRegistrator The address of the Registrator\n function setRegistrator(address _validatorRegistrator)\n external\n onlyGovernor\n {\n validatorRegistrator = _validatorRegistrator;\n emit RegistratorChanged(_validatorRegistrator);\n }\n\n /// @notice Set the default validatorId to delegate to on deposit\n /// @param _validatorId The validator identifier. eg 18\n function setDefaultValidatorId(uint256 _validatorId)\n external\n onlyRegistratorOrStrategist\n {\n require(isSupportedValidator(_validatorId), \"Validator not supported\");\n defaultValidatorId = _validatorId;\n emit DefaultValidatorIdChanged(_validatorId);\n }\n\n /// @notice Allows a validator to be delegated to by the Registrator\n /// @param _validatorId The validator identifier. eg 18\n function supportValidator(uint256 _validatorId) external onlyGovernor {\n require(\n !isSupportedValidator(_validatorId),\n \"Validator already supported\"\n );\n\n supportedValidators.push(_validatorId);\n\n emit SupportedValidator(_validatorId);\n }\n\n /// @notice Removes a validator from the supported list.\n /// Unsupported validators can still be undelegated from, withdrawn from and rewards collected.\n /// @param _validatorId The validator identifier. eg 18\n function unsupportValidator(uint256 _validatorId) external onlyGovernor {\n require(isSupportedValidator(_validatorId), \"Validator not supported\");\n\n uint256 validatorLen = supportedValidators.length;\n for (uint256 i = 0; i < validatorLen; ++i) {\n if (supportedValidators[i] == _validatorId) {\n supportedValidators[i] = supportedValidators[validatorLen - 1];\n supportedValidators.pop();\n break;\n }\n }\n\n uint256 stake = sfc.getStake(address(this), _validatorId);\n\n // undelegate if validator still has funds staked\n if (stake > 0) {\n _undelegate(_validatorId, stake);\n }\n emit UnsupportedValidator(_validatorId);\n }\n\n /// @notice Returns the length of the supportedValidators array\n function supportedValidatorsLength() external view returns (uint256) {\n return supportedValidators.length;\n }\n\n /// @notice Returns whether a validator is supported by this strategy\n /// @param _validatorId The validator identifier\n function isSupportedValidator(uint256 _validatorId)\n public\n view\n returns (bool)\n {\n uint256 validatorLen = supportedValidators.length;\n for (uint256 i = 0; i < validatorLen; ++i) {\n if (supportedValidators[i] == _validatorId) {\n return true;\n }\n }\n return false;\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal virtual;\n}\n" + }, + "contracts/strategies/VaultValueChecker.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IOUSD } from \"../interfaces/IOUSD.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract VaultValueChecker {\n IVault public immutable vault;\n IOUSD public immutable ousd;\n // Snapshot expiration time in seconds.\n // Used to prevent accidental use of an old snapshot, but\n // is not zero to allow easy testing of strategist actions in fork testing\n uint256 constant SNAPSHOT_EXPIRES = 5 * 60;\n\n struct Snapshot {\n uint256 vaultValue;\n uint256 totalSupply;\n uint256 time;\n }\n // By doing per user snapshots, we prevent a reentrancy attack\n // from a third party that updates the snapshot in the middle\n // of an allocation process\n\n mapping(address => Snapshot) public snapshots;\n\n constructor(address _vault, address _ousd) {\n vault = IVault(_vault);\n ousd = IOUSD(_ousd);\n }\n\n function takeSnapshot() external {\n snapshots[msg.sender] = Snapshot({\n vaultValue: vault.totalValue(),\n totalSupply: ousd.totalSupply(),\n time: block.timestamp\n });\n }\n\n function checkDelta(\n int256 expectedProfit,\n int256 profitVariance,\n int256 expectedVaultChange,\n int256 vaultChangeVariance\n ) external {\n // Intentionaly not view so that this method shows up in TX builders\n Snapshot memory snapshot = snapshots[msg.sender];\n int256 vaultChange = toInt256(vault.totalValue()) -\n toInt256(snapshot.vaultValue);\n int256 supplyChange = toInt256(ousd.totalSupply()) -\n toInt256(snapshot.totalSupply);\n int256 profit = vaultChange - supplyChange;\n\n require(\n snapshot.time >= block.timestamp - SNAPSHOT_EXPIRES,\n \"Snapshot too old\"\n );\n require(snapshot.time <= block.timestamp, \"Snapshot too new\");\n require(profit >= expectedProfit - profitVariance, \"Profit too low\");\n require(profit <= expectedProfit + profitVariance, \"Profit too high\");\n require(\n vaultChange >= expectedVaultChange - vaultChangeVariance,\n \"Vault value change too low\"\n );\n require(\n vaultChange <= expectedVaultChange + vaultChangeVariance,\n \"Vault value change too high\"\n );\n }\n\n function toInt256(uint256 value) internal pure returns (int256) {\n // From openzeppelin math/SafeCast.sol\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(\n value <= uint256(type(int256).max),\n \"SafeCast: value doesn't fit in an int256\"\n );\n return int256(value);\n }\n}\n\ncontract OETHVaultValueChecker is VaultValueChecker {\n constructor(address _vault, address _ousd)\n VaultValueChecker(_vault, _ousd)\n {}\n}\n" + }, + "contracts/token/OETH.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { OUSD } from \"./OUSD.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\ncontract OETH is OUSD {\n function symbol() external pure override returns (string memory) {\n return \"OETH\";\n }\n\n function name() external pure override returns (string memory) {\n return \"Origin Ether\";\n }\n\n function decimals() external pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/token/OETHBase.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { OUSD } from \"./OUSD.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\ncontract OETHBase is OUSD {\n constructor() {\n // Nobody owns the implementation contract\n _setGovernor(address(0));\n }\n\n function symbol() external pure override returns (string memory) {\n return \"superOETHb\";\n }\n\n function name() external pure override returns (string memory) {\n return \"Super OETH\";\n }\n\n function decimals() external pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/token/OETHPlume.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { OUSD } from \"./OUSD.sol\";\n\n/**\n * @title Super OETH (Plume) Token Contract\n * @author Origin Protocol Inc\n */\ncontract OETHPlume is OUSD {\n constructor() {\n // Nobody owns the implementation contract\n _setGovernor(address(0));\n }\n\n function symbol() external pure override returns (string memory) {\n return \"superOETHp\";\n }\n\n function name() external pure override returns (string memory) {\n return \"Super OETH\";\n }\n\n function decimals() external pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/token/OSonic.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { OUSD } from \"./OUSD.sol\";\n\n/**\n * @title Origin Sonic (OS) token on Sonic\n * @author Origin Protocol Inc\n */\ncontract OSonic is OUSD {\n function symbol() external pure override returns (string memory) {\n return \"OS\";\n }\n\n function name() external pure override returns (string memory) {\n return \"Origin Sonic\";\n }\n}\n" + }, + "contracts/token/OUSD.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Token Contract\n * @dev ERC20 compatible contract for OUSD\n * @dev Implements an elastic supply\n * @author Origin Protocol Inc\n */\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\ncontract OUSD is Governable {\n using SafeCast for int256;\n using SafeCast for uint256;\n\n /// @dev Event triggered when the supply changes\n /// @param totalSupply Updated token total supply\n /// @param rebasingCredits Updated token rebasing credits\n /// @param rebasingCreditsPerToken Updated token rebasing credits per token\n event TotalSupplyUpdatedHighres(\n uint256 totalSupply,\n uint256 rebasingCredits,\n uint256 rebasingCreditsPerToken\n );\n /// @dev Event triggered when an account opts in for rebasing\n /// @param account Address of the account\n event AccountRebasingEnabled(address account);\n /// @dev Event triggered when an account opts out of rebasing\n /// @param account Address of the account\n event AccountRebasingDisabled(address account);\n /// @dev Emitted when `value` tokens are moved from one account `from` to\n /// another `to`.\n /// @param from Address of the account tokens are moved from\n /// @param to Address of the account tokens are moved to\n /// @param value Amount of tokens transferred\n event Transfer(address indexed from, address indexed to, uint256 value);\n /// @dev Emitted when the allowance of a `spender` for an `owner` is set by\n /// a call to {approve}. `value` is the new allowance.\n /// @param owner Address of the owner approving allowance\n /// @param spender Address of the spender allowance is granted to\n /// @param value Amount of tokens spender can transfer\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n /// @dev Yield resulting from {changeSupply} that a `source` account would\n /// receive is directed to `target` account.\n /// @param source Address of the source forwarding the yield\n /// @param target Address of the target receiving the yield\n event YieldDelegated(address source, address target);\n /// @dev Yield delegation from `source` account to the `target` account is\n /// suspended.\n /// @param source Address of the source suspending yield forwarding\n /// @param target Address of the target no longer receiving yield from `source`\n /// account\n event YieldUndelegated(address source, address target);\n\n enum RebaseOptions {\n NotSet,\n StdNonRebasing,\n StdRebasing,\n YieldDelegationSource,\n YieldDelegationTarget\n }\n\n uint256[154] private _gap; // Slots to align with deployed contract\n uint256 private constant MAX_SUPPLY = type(uint128).max;\n /// @dev The amount of tokens in existence\n uint256 public totalSupply;\n mapping(address => mapping(address => uint256)) private allowances;\n /// @dev The vault with privileges to execute {mint}, {burn}\n /// and {changeSupply}\n address public vaultAddress;\n mapping(address => uint256) internal creditBalances;\n // the 2 storage variables below need trailing underscores to not name collide with public functions\n uint256 private rebasingCredits_; // Sum of all rebasing credits (creditBalances for rebasing accounts)\n uint256 private rebasingCreditsPerToken_;\n /// @dev The amount of tokens that are not rebasing - receiving yield\n uint256 public nonRebasingSupply;\n mapping(address => uint256) internal alternativeCreditsPerToken;\n /// @dev A map of all addresses and their respective RebaseOptions\n mapping(address => RebaseOptions) public rebaseState;\n mapping(address => uint256) private __deprecated_isUpgraded;\n /// @dev A map of addresses that have yields forwarded to. This is an\n /// inverse mapping of {yieldFrom}\n /// Key Account forwarding yield\n /// Value Account receiving yield\n mapping(address => address) public yieldTo;\n /// @dev A map of addresses that are receiving the yield. This is an\n /// inverse mapping of {yieldTo}\n /// Key Account receiving yield\n /// Value Account forwarding yield\n mapping(address => address) public yieldFrom;\n\n uint256 private constant RESOLUTION_INCREASE = 1e9;\n uint256[34] private __gap; // including below gap totals up to 200\n\n /// @dev Verifies that the caller is the Governor or Strategist.\n modifier onlyGovernorOrStrategist() {\n require(\n isGovernor() || msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n /// @dev Initializes the contract and sets necessary variables.\n /// @param _vaultAddress Address of the vault contract\n /// @param _initialCreditsPerToken The starting rebasing credits per token.\n function initialize(address _vaultAddress, uint256 _initialCreditsPerToken)\n external\n onlyGovernor\n {\n require(_vaultAddress != address(0), \"Zero vault address\");\n require(vaultAddress == address(0), \"Already initialized\");\n\n rebasingCreditsPerToken_ = _initialCreditsPerToken;\n vaultAddress = _vaultAddress;\n }\n\n /// @dev Returns the symbol of the token, a shorter version\n /// of the name.\n function symbol() external pure virtual returns (string memory) {\n return \"OUSD\";\n }\n\n /// @dev Returns the name of the token.\n function name() external pure virtual returns (string memory) {\n return \"Origin Dollar\";\n }\n\n /// @dev Returns the number of decimals used to get its user representation.\n function decimals() external pure virtual returns (uint8) {\n return 18;\n }\n\n /**\n * @dev Verifies that the caller is the Vault contract\n */\n modifier onlyVault() {\n require(vaultAddress == msg.sender, \"Caller is not the Vault\");\n _;\n }\n\n /**\n * @return High resolution rebasingCreditsPerToken\n */\n function rebasingCreditsPerTokenHighres() external view returns (uint256) {\n return rebasingCreditsPerToken_;\n }\n\n /**\n * @return Low resolution rebasingCreditsPerToken\n */\n function rebasingCreditsPerToken() external view returns (uint256) {\n return rebasingCreditsPerToken_ / RESOLUTION_INCREASE;\n }\n\n /**\n * @return High resolution total number of rebasing credits\n */\n function rebasingCreditsHighres() external view returns (uint256) {\n return rebasingCredits_;\n }\n\n /**\n * @return Low resolution total number of rebasing credits\n */\n function rebasingCredits() external view returns (uint256) {\n return rebasingCredits_ / RESOLUTION_INCREASE;\n }\n\n /**\n * @notice Gets the balance of the specified address.\n * @param _account Address to query the balance of.\n * @return A uint256 representing the amount of base units owned by the\n * specified address.\n */\n function balanceOf(address _account) public view returns (uint256) {\n RebaseOptions state = rebaseState[_account];\n if (state == RebaseOptions.YieldDelegationSource) {\n // Saves a slot read when transferring to or from a yield delegating source\n // since we know creditBalances equals the balance.\n return creditBalances[_account];\n }\n uint256 baseBalance = (creditBalances[_account] * 1e18) /\n _creditsPerToken(_account);\n if (state == RebaseOptions.YieldDelegationTarget) {\n // creditBalances of yieldFrom accounts equals token balances\n return baseBalance - creditBalances[yieldFrom[_account]];\n }\n return baseBalance;\n }\n\n /**\n * @notice Gets the credits balance of the specified address.\n * @dev Backwards compatible with old low res credits per token.\n * @param _account The address to query the balance of.\n * @return (uint256, uint256) Credit balance and credits per token of the\n * address\n */\n function creditsBalanceOf(address _account)\n external\n view\n returns (uint256, uint256)\n {\n uint256 cpt = _creditsPerToken(_account);\n if (cpt == 1e27) {\n // For a period before the resolution upgrade, we created all new\n // contract accounts at high resolution. Since they are not changing\n // as a result of this upgrade, we will return their true values\n return (creditBalances[_account], cpt);\n } else {\n return (\n creditBalances[_account] / RESOLUTION_INCREASE,\n cpt / RESOLUTION_INCREASE\n );\n }\n }\n\n /**\n * @notice Gets the credits balance of the specified address.\n * @param _account The address to query the balance of.\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\n * address, and isUpgraded\n */\n function creditsBalanceOfHighres(address _account)\n external\n view\n returns (\n uint256,\n uint256,\n bool\n )\n {\n return (\n creditBalances[_account],\n _creditsPerToken(_account),\n true // all accounts have their resolution \"upgraded\"\n );\n }\n\n // Backwards compatible view\n function nonRebasingCreditsPerToken(address _account)\n external\n view\n returns (uint256)\n {\n return alternativeCreditsPerToken[_account];\n }\n\n /**\n * @notice Transfer tokens to a specified address.\n * @param _to the address to transfer to.\n * @param _value the amount to be transferred.\n * @return true on success.\n */\n function transfer(address _to, uint256 _value) external returns (bool) {\n require(_to != address(0), \"Transfer to zero address\");\n\n _executeTransfer(msg.sender, _to, _value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n /**\n * @notice Transfer tokens from one address to another.\n * @param _from The address you want to send tokens from.\n * @param _to The address you want to transfer to.\n * @param _value The amount of tokens to be transferred.\n * @return true on success.\n */\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool) {\n require(_to != address(0), \"Transfer to zero address\");\n uint256 userAllowance = allowances[_from][msg.sender];\n require(_value <= userAllowance, \"Allowance exceeded\");\n\n unchecked {\n allowances[_from][msg.sender] = userAllowance - _value;\n }\n\n _executeTransfer(_from, _to, _value);\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function _executeTransfer(\n address _from,\n address _to,\n uint256 _value\n ) internal {\n (\n int256 fromRebasingCreditsDiff,\n int256 fromNonRebasingSupplyDiff\n ) = _adjustAccount(_from, -_value.toInt256());\n (\n int256 toRebasingCreditsDiff,\n int256 toNonRebasingSupplyDiff\n ) = _adjustAccount(_to, _value.toInt256());\n\n _adjustGlobals(\n fromRebasingCreditsDiff + toRebasingCreditsDiff,\n fromNonRebasingSupplyDiff + toNonRebasingSupplyDiff\n );\n }\n\n function _adjustAccount(address _account, int256 _balanceChange)\n internal\n returns (int256 rebasingCreditsDiff, int256 nonRebasingSupplyDiff)\n {\n RebaseOptions state = rebaseState[_account];\n int256 currentBalance = balanceOf(_account).toInt256();\n if (currentBalance + _balanceChange < 0) {\n revert(\"Transfer amount exceeds balance\");\n }\n uint256 newBalance = (currentBalance + _balanceChange).toUint256();\n\n if (state == RebaseOptions.YieldDelegationSource) {\n address target = yieldTo[_account];\n uint256 targetOldBalance = balanceOf(target);\n uint256 targetNewCredits = _balanceToRebasingCredits(\n targetOldBalance + newBalance\n );\n rebasingCreditsDiff =\n targetNewCredits.toInt256() -\n creditBalances[target].toInt256();\n\n creditBalances[_account] = newBalance;\n creditBalances[target] = targetNewCredits;\n } else if (state == RebaseOptions.YieldDelegationTarget) {\n uint256 newCredits = _balanceToRebasingCredits(\n newBalance + creditBalances[yieldFrom[_account]]\n );\n rebasingCreditsDiff =\n newCredits.toInt256() -\n creditBalances[_account].toInt256();\n creditBalances[_account] = newCredits;\n } else {\n _autoMigrate(_account);\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\n _account\n ];\n if (alternativeCreditsPerTokenMem > 0) {\n nonRebasingSupplyDiff = _balanceChange;\n if (alternativeCreditsPerTokenMem != 1e18) {\n alternativeCreditsPerToken[_account] = 1e18;\n }\n creditBalances[_account] = newBalance;\n } else {\n uint256 newCredits = _balanceToRebasingCredits(newBalance);\n rebasingCreditsDiff =\n newCredits.toInt256() -\n creditBalances[_account].toInt256();\n creditBalances[_account] = newCredits;\n }\n }\n }\n\n function _adjustGlobals(\n int256 _rebasingCreditsDiff,\n int256 _nonRebasingSupplyDiff\n ) internal {\n if (_rebasingCreditsDiff != 0) {\n rebasingCredits_ = (rebasingCredits_.toInt256() +\n _rebasingCreditsDiff).toUint256();\n }\n if (_nonRebasingSupplyDiff != 0) {\n nonRebasingSupply = (nonRebasingSupply.toInt256() +\n _nonRebasingSupplyDiff).toUint256();\n }\n }\n\n /**\n * @notice Function to check the amount of tokens that _owner has allowed\n * to `_spender`.\n * @param _owner The address which owns the funds.\n * @param _spender The address which will spend the funds.\n * @return The number of tokens still available for the _spender.\n */\n function allowance(address _owner, address _spender)\n external\n view\n returns (uint256)\n {\n return allowances[_owner][_spender];\n }\n\n /**\n * @notice Approve the passed address to spend the specified amount of\n * tokens on behalf of msg.sender.\n * @param _spender The address which will spend the funds.\n * @param _value The amount of tokens to be spent.\n * @return true on success.\n */\n function approve(address _spender, uint256 _value) external returns (bool) {\n allowances[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n /**\n * @notice Creates `_amount` tokens and assigns them to `_account`,\n * increasing the total supply.\n */\n function mint(address _account, uint256 _amount) external onlyVault {\n require(_account != address(0), \"Mint to the zero address\");\n\n // Account\n (\n int256 toRebasingCreditsDiff,\n int256 toNonRebasingSupplyDiff\n ) = _adjustAccount(_account, _amount.toInt256());\n // Globals\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\n totalSupply = totalSupply + _amount;\n\n require(totalSupply < MAX_SUPPLY, \"Max supply\");\n emit Transfer(address(0), _account, _amount);\n }\n\n /**\n * @notice Destroys `_amount` tokens from `_account`,\n * reducing the total supply.\n */\n function burn(address _account, uint256 _amount) external onlyVault {\n require(_account != address(0), \"Burn from the zero address\");\n if (_amount == 0) {\n return;\n }\n\n // Account\n (\n int256 toRebasingCreditsDiff,\n int256 toNonRebasingSupplyDiff\n ) = _adjustAccount(_account, -_amount.toInt256());\n // Globals\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\n totalSupply = totalSupply - _amount;\n\n emit Transfer(_account, address(0), _amount);\n }\n\n /**\n * @dev Get the credits per token for an account. Returns a fixed amount\n * if the account is non-rebasing.\n * @param _account Address of the account.\n */\n function _creditsPerToken(address _account)\n internal\n view\n returns (uint256)\n {\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\n _account\n ];\n if (alternativeCreditsPerTokenMem != 0) {\n return alternativeCreditsPerTokenMem;\n } else {\n return rebasingCreditsPerToken_;\n }\n }\n\n /**\n * @dev Auto migrate contracts to be non rebasing,\n * unless they have opted into yield.\n * @param _account Address of the account.\n */\n function _autoMigrate(address _account) internal {\n uint256 codeLen = _account.code.length;\n bool isEOA = (codeLen == 0) ||\n (codeLen == 23 && bytes3(_account.code) == 0xef0100);\n // In previous code versions, contracts would not have had their\n // rebaseState[_account] set to RebaseOptions.NonRebasing when migrated\n // therefore we check the actual accounting used on the account as well.\n if (\n (!isEOA) &&\n rebaseState[_account] == RebaseOptions.NotSet &&\n alternativeCreditsPerToken[_account] == 0\n ) {\n _rebaseOptOut(_account);\n }\n }\n\n /**\n * @dev Calculates credits from contract's global rebasingCreditsPerToken_, and\n * also balance that corresponds to those credits. The latter is important\n * when adjusting the contract's global nonRebasingSupply to circumvent any\n * possible rounding errors.\n *\n * @param _balance Balance of the account.\n */\n function _balanceToRebasingCredits(uint256 _balance)\n internal\n view\n returns (uint256 rebasingCredits)\n {\n // Rounds up, because we need to ensure that accounts always have\n // at least the balance that they should have.\n // Note this should always be used on an absolute account value,\n // not on a possibly negative diff, because then the rounding would be wrong.\n return ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18;\n }\n\n /**\n * @notice The calling account will start receiving yield after a successful call.\n * @param _account Address of the account.\n */\n function governanceRebaseOptIn(address _account) external onlyGovernor {\n require(_account != address(0), \"Zero address not allowed\");\n _rebaseOptIn(_account);\n }\n\n /**\n * @notice The calling account will start receiving yield after a successful call.\n */\n function rebaseOptIn() external {\n _rebaseOptIn(msg.sender);\n }\n\n function _rebaseOptIn(address _account) internal {\n uint256 balance = balanceOf(_account);\n\n // prettier-ignore\n require(\n alternativeCreditsPerToken[_account] > 0 ||\n // Accounts may explicitly `rebaseOptIn` regardless of\n // accounting if they have a 0 balance.\n creditBalances[_account] == 0\n ,\n \"Account must be non-rebasing\"\n );\n RebaseOptions state = rebaseState[_account];\n // prettier-ignore\n require(\n state == RebaseOptions.StdNonRebasing ||\n state == RebaseOptions.NotSet,\n \"Only standard non-rebasing accounts can opt in\"\n );\n\n uint256 newCredits = _balanceToRebasingCredits(balance);\n\n // Account\n rebaseState[_account] = RebaseOptions.StdRebasing;\n alternativeCreditsPerToken[_account] = 0;\n creditBalances[_account] = newCredits;\n // Globals\n _adjustGlobals(newCredits.toInt256(), -balance.toInt256());\n\n emit AccountRebasingEnabled(_account);\n }\n\n /**\n * @notice The calling account will no longer receive yield\n */\n function rebaseOptOut() external {\n _rebaseOptOut(msg.sender);\n }\n\n function _rebaseOptOut(address _account) internal {\n require(\n alternativeCreditsPerToken[_account] == 0,\n \"Account must be rebasing\"\n );\n RebaseOptions state = rebaseState[_account];\n require(\n state == RebaseOptions.StdRebasing || state == RebaseOptions.NotSet,\n \"Only standard rebasing accounts can opt out\"\n );\n\n uint256 oldCredits = creditBalances[_account];\n uint256 balance = balanceOf(_account);\n\n // Account\n rebaseState[_account] = RebaseOptions.StdNonRebasing;\n alternativeCreditsPerToken[_account] = 1e18;\n creditBalances[_account] = balance;\n // Globals\n _adjustGlobals(-oldCredits.toInt256(), balance.toInt256());\n\n emit AccountRebasingDisabled(_account);\n }\n\n /**\n * @notice Distribute yield to users. This changes the exchange rate\n * between \"credits\" and OUSD tokens to change rebasing user's balances.\n * @param _newTotalSupply New total supply of OUSD.\n */\n function changeSupply(uint256 _newTotalSupply) external onlyVault {\n require(totalSupply > 0, \"Cannot increase 0 supply\");\n\n if (totalSupply == _newTotalSupply) {\n emit TotalSupplyUpdatedHighres(\n totalSupply,\n rebasingCredits_,\n rebasingCreditsPerToken_\n );\n return;\n }\n\n totalSupply = _newTotalSupply > MAX_SUPPLY\n ? MAX_SUPPLY\n : _newTotalSupply;\n\n uint256 rebasingSupply = totalSupply - nonRebasingSupply;\n // round up in the favour of the protocol\n rebasingCreditsPerToken_ =\n (rebasingCredits_ * 1e18 + rebasingSupply - 1) /\n rebasingSupply;\n\n require(rebasingCreditsPerToken_ > 0, \"Invalid change in supply\");\n\n emit TotalSupplyUpdatedHighres(\n totalSupply,\n rebasingCredits_,\n rebasingCreditsPerToken_\n );\n }\n\n /*\n * @notice Send the yield from one account to another account.\n * Each account keeps its own balances.\n */\n function delegateYield(address _from, address _to)\n external\n onlyGovernorOrStrategist\n {\n require(_from != address(0), \"Zero from address not allowed\");\n require(_to != address(0), \"Zero to address not allowed\");\n\n require(_from != _to, \"Cannot delegate to self\");\n require(\n yieldFrom[_to] == address(0) &&\n yieldTo[_to] == address(0) &&\n yieldFrom[_from] == address(0) &&\n yieldTo[_from] == address(0),\n \"Blocked by existing yield delegation\"\n );\n RebaseOptions stateFrom = rebaseState[_from];\n RebaseOptions stateTo = rebaseState[_to];\n\n require(\n stateFrom == RebaseOptions.NotSet ||\n stateFrom == RebaseOptions.StdNonRebasing ||\n stateFrom == RebaseOptions.StdRebasing,\n \"Invalid rebaseState from\"\n );\n\n require(\n stateTo == RebaseOptions.NotSet ||\n stateTo == RebaseOptions.StdNonRebasing ||\n stateTo == RebaseOptions.StdRebasing,\n \"Invalid rebaseState to\"\n );\n\n if (alternativeCreditsPerToken[_from] == 0) {\n _rebaseOptOut(_from);\n }\n if (alternativeCreditsPerToken[_to] > 0) {\n _rebaseOptIn(_to);\n }\n\n uint256 fromBalance = balanceOf(_from);\n uint256 toBalance = balanceOf(_to);\n uint256 oldToCredits = creditBalances[_to];\n uint256 newToCredits = _balanceToRebasingCredits(\n fromBalance + toBalance\n );\n\n // Set up the bidirectional links\n yieldTo[_from] = _to;\n yieldFrom[_to] = _from;\n\n // Local\n rebaseState[_from] = RebaseOptions.YieldDelegationSource;\n alternativeCreditsPerToken[_from] = 1e18;\n creditBalances[_from] = fromBalance;\n rebaseState[_to] = RebaseOptions.YieldDelegationTarget;\n creditBalances[_to] = newToCredits;\n\n // Global\n int256 creditsChange = newToCredits.toInt256() -\n oldToCredits.toInt256();\n _adjustGlobals(creditsChange, -(fromBalance).toInt256());\n emit YieldDelegated(_from, _to);\n }\n\n /*\n * @notice Stop sending the yield from one account to another account.\n */\n function undelegateYield(address _from) external onlyGovernorOrStrategist {\n // Require a delegation, which will also ensure a valid delegation\n require(yieldTo[_from] != address(0), \"Zero address not allowed\");\n\n address to = yieldTo[_from];\n uint256 fromBalance = balanceOf(_from);\n uint256 toBalance = balanceOf(to);\n uint256 oldToCredits = creditBalances[to];\n uint256 newToCredits = _balanceToRebasingCredits(toBalance);\n\n // Remove the bidirectional links\n yieldFrom[to] = address(0);\n yieldTo[_from] = address(0);\n\n // Local\n rebaseState[_from] = RebaseOptions.StdNonRebasing;\n // alternativeCreditsPerToken[from] already 1e18 from `delegateYield()`\n creditBalances[_from] = fromBalance;\n rebaseState[to] = RebaseOptions.StdRebasing;\n // alternativeCreditsPerToken[to] already 0 from `delegateYield()`\n creditBalances[to] = newToCredits;\n\n // Global\n int256 creditsChange = newToCredits.toInt256() -\n oldToCredits.toInt256();\n _adjustGlobals(creditsChange, fromBalance.toInt256());\n emit YieldUndelegated(_from, to);\n }\n}\n" + }, + "contracts/token/WOETH.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ERC4626 } from \"../../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { OETH } from \"./OETH.sol\";\n\n/**\n * @title Wrapped OETH Token Contract\n * @author Origin Protocol Inc\n *\n * @dev An important capability of this contract is that it isn't susceptible to changes of the\n * exchange rate of WOETH/OETH if/when someone sends the underlying asset (OETH) to the contract.\n * If OETH weren't rebasing this could be achieved by solely tracking the ERC20 transfers of the OETH\n * token on mint, deposit, redeem, withdraw. The issue is that OETH is rebasing and OETH balances\n * will change when the token rebases.\n * For that reason the contract logic checks the actual underlying OETH token balance only once\n * (either on a fresh contract creation or upgrade) and considering the WOETH supply and\n * rebasingCreditsPerToken calculates the _adjuster. Once the adjuster is calculated any donations\n * to the contract are ignored. The totalSupply (instead of querying OETH balance) works off of\n * adjuster the current WOETH supply and rebasingCreditsPerToken. This makes WOETH value accrual\n * completely follow OETH's value accrual.\n * WOETH is safe to use in lending markets as the VualtCore's _rebase contains safeguards preventing\n * any sudden large rebases.\n */\n\ncontract WOETH is ERC4626, Governable, Initializable {\n using SafeERC20 for IERC20;\n /* This is a 1e27 adjustment constant that expresses the difference in exchange rate between\n * OETH's rebase since inception (expressed with rebasingCreditsPerToken) and WOETH to OETH\n * conversion.\n *\n * If WOETH and OETH are deployed at the same time, the value of adjuster is a neutral 1e27\n */\n uint256 public adjuster;\n uint256[49] private __gap;\n\n // no need to set ERC20 name and symbol since they are overridden in WOETH & WOETHBase\n constructor(ERC20 underlying_) ERC20(\"\", \"\") ERC4626(underlying_) {}\n\n /**\n * @notice Enable OETH rebasing for this contract\n */\n function initialize() external onlyGovernor initializer {\n OETH(address(asset())).rebaseOptIn();\n\n initialize2();\n }\n\n /**\n * @notice secondary initializer that newly deployed contracts will execute as part\n * of primary initialize function and the existing contracts will have it called\n * as a governance operation.\n */\n function initialize2() public onlyGovernor {\n require(adjuster == 0, \"Initialize2 already called\");\n\n if (totalSupply() == 0) {\n adjuster = 1e27;\n } else {\n adjuster =\n (rebasingCreditsPerTokenHighres() *\n ERC20(asset()).balanceOf(address(this))) /\n totalSupply();\n }\n }\n\n function name()\n public\n view\n virtual\n override(ERC20, IERC20Metadata)\n returns (string memory)\n {\n return \"Wrapped OETH\";\n }\n\n function symbol()\n public\n view\n virtual\n override(ERC20, IERC20Metadata)\n returns (string memory)\n {\n return \"wOETH\";\n }\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends. Cannot transfer OETH\n * @param asset_ Address for the asset\n * @param amount_ Amount of the asset to transfer\n */\n function transferToken(address asset_, uint256 amount_)\n external\n onlyGovernor\n {\n require(asset_ != address(asset()), \"Cannot collect core asset\");\n IERC20(asset_).safeTransfer(governor(), amount_);\n }\n\n /// @inheritdoc ERC4626\n function convertToShares(uint256 assets)\n public\n view\n virtual\n override\n returns (uint256 shares)\n {\n return (assets * rebasingCreditsPerTokenHighres()) / adjuster;\n }\n\n /// @inheritdoc ERC4626\n function convertToAssets(uint256 shares)\n public\n view\n virtual\n override\n returns (uint256 assets)\n {\n return (shares * adjuster) / rebasingCreditsPerTokenHighres();\n }\n\n /// @inheritdoc ERC4626\n function totalAssets() public view override returns (uint256) {\n return (totalSupply() * adjuster) / rebasingCreditsPerTokenHighres();\n }\n\n function rebasingCreditsPerTokenHighres() internal view returns (uint256) {\n return OETH(asset()).rebasingCreditsPerTokenHighres();\n }\n}\n" + }, + "contracts/token/WOETHBase.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { WOETH } from \"./WOETH.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\n\ncontract WOETHBase is WOETH {\n constructor(ERC20 underlying_) WOETH(underlying_) {}\n\n function name() public view virtual override returns (string memory) {\n return \"Wrapped Super OETH\";\n }\n\n function symbol() public view virtual override returns (string memory) {\n return \"wsuperOETHb\";\n }\n}\n" + }, + "contracts/token/WOETHPlume.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { WOETH } from \"./WOETH.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\n/**\n * @title wOETH (Plume) Token Contract\n * @author Origin Protocol Inc\n */\n\ncontract WOETHPlume is WOETH {\n constructor(ERC20 underlying_) WOETH(underlying_) {}\n\n function name() public view virtual override returns (string memory) {\n return \"Wrapped Super OETH\";\n }\n\n function symbol() public view virtual override returns (string memory) {\n return \"wsuperOETHp\";\n }\n}\n" + }, + "contracts/token/WOSonic.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { WOETH } from \"./WOETH.sol\";\n\n/**\n * @title Wrapped Origin Sonic (wOS) token on Sonic\n * @author Origin Protocol Inc\n */\ncontract WOSonic is WOETH {\n constructor(ERC20 underlying_) WOETH(underlying_) {}\n\n function name()\n public\n view\n virtual\n override(WOETH)\n returns (string memory)\n {\n return \"Wrapped OS\";\n }\n\n function symbol()\n public\n view\n virtual\n override(WOETH)\n returns (string memory)\n {\n return \"wOS\";\n }\n}\n" + }, + "contracts/token/WrappedOusd.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { WOETH } from \"./WOETH.sol\";\n\n/**\n * @title Wrapped OUSD Token Contract\n * @author Origin Protocol Inc\n */\ncontract WrappedOusd is WOETH {\n constructor(ERC20 underlying_) WOETH(underlying_) {}\n\n function name()\n public\n view\n virtual\n override(WOETH)\n returns (string memory)\n {\n return \"Wrapped OUSD\";\n }\n\n function symbol()\n public\n view\n virtual\n override(WOETH)\n returns (string memory)\n {\n return \"WOUSD\";\n }\n}\n" + }, + "contracts/utils/BytesHelper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nuint256 constant UINT32_LENGTH = 4;\nuint256 constant UINT64_LENGTH = 8;\nuint256 constant UINT256_LENGTH = 32;\n// Address is 20 bytes, but we expect the data to be padded with 0s to 32 bytes\nuint256 constant ADDRESS_LENGTH = 32;\n\nlibrary BytesHelper {\n /**\n * @dev Extract a slice from bytes memory\n * @param data The bytes memory to slice\n * @param start The start index (inclusive)\n * @param end The end index (exclusive)\n * @return result A new bytes memory containing the slice\n */\n function extractSlice(\n bytes memory data,\n uint256 start,\n uint256 end\n ) internal pure returns (bytes memory) {\n require(end >= start, \"Invalid slice range\");\n require(end <= data.length, \"Slice end exceeds data length\");\n\n uint256 length = end - start;\n bytes memory result = new bytes(length);\n\n // Simple byte-by-byte copy\n for (uint256 i = 0; i < length; i++) {\n result[i] = data[start + i];\n }\n\n return result;\n }\n\n /**\n * @dev Decode a uint32 from a bytes memory\n * @param data The bytes memory to decode\n * @return uint32 The decoded uint32\n */\n function decodeUint32(bytes memory data) internal pure returns (uint32) {\n require(data.length == 4, \"Invalid data length\");\n return uint32(uint256(bytes32(data)) >> 224);\n }\n\n /**\n * @dev Extract a uint32 from a bytes memory\n * @param data The bytes memory to extract from\n * @param start The start index (inclusive)\n * @return uint32 The extracted uint32\n */\n function extractUint32(bytes memory data, uint256 start)\n internal\n pure\n returns (uint32)\n {\n return decodeUint32(extractSlice(data, start, start + UINT32_LENGTH));\n }\n\n /**\n * @dev Decode an address from a bytes memory.\n * Expects the data to be padded with 0s to 32 bytes.\n * @param data The bytes memory to decode\n * @return address The decoded address\n */\n function decodeAddress(bytes memory data) internal pure returns (address) {\n // We expect the data to be padded with 0s, so length is 32 not 20\n require(data.length == 32, \"Invalid data length\");\n return abi.decode(data, (address));\n }\n\n /**\n * @dev Extract an address from a bytes memory\n * @param data The bytes memory to extract from\n * @param start The start index (inclusive)\n * @return address The extracted address\n */\n function extractAddress(bytes memory data, uint256 start)\n internal\n pure\n returns (address)\n {\n return decodeAddress(extractSlice(data, start, start + ADDRESS_LENGTH));\n }\n\n /**\n * @dev Decode a uint256 from a bytes memory\n * @param data The bytes memory to decode\n * @return uint256 The decoded uint256\n */\n function decodeUint256(bytes memory data) internal pure returns (uint256) {\n require(data.length == 32, \"Invalid data length\");\n return abi.decode(data, (uint256));\n }\n\n /**\n * @dev Extract a uint256 from a bytes memory\n * @param data The bytes memory to extract from\n * @param start The start index (inclusive)\n * @return uint256 The extracted uint256\n */\n function extractUint256(bytes memory data, uint256 start)\n internal\n pure\n returns (uint256)\n {\n return decodeUint256(extractSlice(data, start, start + UINT256_LENGTH));\n }\n}\n" + }, + "contracts/utils/Helpers.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IBasicToken } from \"../interfaces/IBasicToken.sol\";\n\nlibrary Helpers {\n /**\n * @notice Fetch the `symbol()` from an ERC20 token\n * @dev Grabs the `symbol()` from a contract\n * @param _token Address of the ERC20 token\n * @return string Symbol of the ERC20 token\n */\n function getSymbol(address _token) internal view returns (string memory) {\n string memory symbol = IBasicToken(_token).symbol();\n return symbol;\n }\n\n /**\n * @notice Fetch the `decimals()` from an ERC20 token\n * @dev Grabs the `decimals()` from a contract and fails if\n * the decimal value does not live within a certain range\n * @param _token Address of the ERC20 token\n * @return uint256 Decimals of the ERC20 token\n */\n function getDecimals(address _token) internal view returns (uint256) {\n uint256 decimals = IBasicToken(_token).decimals();\n require(\n decimals >= 4 && decimals <= 18,\n \"Token must have sufficient decimal places\"\n );\n\n return decimals;\n }\n}\n" + }, + "contracts/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Base contract any contracts that need to initialize state after deployment.\n * @author Origin Protocol Inc\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private initializing;\n\n /**\n * @dev Modifier to protect an initializer function from being invoked twice.\n */\n modifier initializer() {\n require(\n initializing || !initialized,\n \"Initializable: contract is already initialized\"\n );\n\n bool isTopLevelCall = !initializing;\n if (isTopLevelCall) {\n initializing = true;\n initialized = true;\n }\n\n _;\n\n if (isTopLevelCall) {\n initializing = false;\n }\n }\n\n uint256[50] private ______gap;\n}\n" + }, + "contracts/utils/InitializableAbstractStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Base contract for vault strategies.\n * @author Origin Protocol Inc\n */\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nabstract contract InitializableAbstractStrategy is Initializable, Governable {\n using SafeERC20 for IERC20;\n\n event PTokenAdded(address indexed _asset, address _pToken);\n event PTokenRemoved(address indexed _asset, address _pToken);\n event Deposit(address indexed _asset, address _pToken, uint256 _amount);\n event Withdrawal(address indexed _asset, address _pToken, uint256 _amount);\n event RewardTokenCollected(\n address recipient,\n address rewardToken,\n uint256 amount\n );\n event RewardTokenAddressesUpdated(\n address[] _oldAddresses,\n address[] _newAddresses\n );\n event HarvesterAddressesUpdated(\n address _oldHarvesterAddress,\n address _newHarvesterAddress\n );\n\n /// @notice Address of the underlying platform\n address public immutable platformAddress;\n /// @notice Address of the OToken vault\n address public immutable vaultAddress;\n\n /// @dev Replaced with an immutable variable\n // slither-disable-next-line constable-states\n address private _deprecated_platformAddress;\n\n /// @dev Replaced with an immutable\n // slither-disable-next-line constable-states\n address private _deprecated_vaultAddress;\n\n /// @notice asset => pToken (Platform Specific Token Address)\n mapping(address => address) public assetToPToken;\n\n /// @notice Full list of all assets supported by the strategy\n address[] internal assetsMapped;\n\n // Deprecated: Reward token address\n // slither-disable-next-line constable-states\n address private _deprecated_rewardTokenAddress;\n\n // Deprecated: now resides in Harvester's rewardTokenConfigs\n // slither-disable-next-line constable-states\n uint256 private _deprecated_rewardLiquidationThreshold;\n\n /// @notice Address of the Harvester contract allowed to collect reward tokens\n address public harvesterAddress;\n\n /// @notice Address of the reward tokens. eg CRV, BAL, CVX, AURA\n address[] public rewardTokenAddresses;\n\n /* Reserved for future expansion. Used to be 100 storage slots\n * and has decreased to accommodate:\n * - harvesterAddress\n * - rewardTokenAddresses\n */\n int256[98] private _reserved;\n\n struct BaseStrategyConfig {\n address platformAddress; // Address of the underlying platform\n address vaultAddress; // Address of the OToken's Vault\n }\n\n /**\n * @dev Verifies that the caller is the Governor or Strategist.\n */\n modifier onlyGovernorOrStrategist() virtual {\n require(\n isGovernor() || msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n /**\n * @param _config The platform and OToken vault addresses\n */\n constructor(BaseStrategyConfig memory _config) {\n platformAddress = _config.platformAddress;\n vaultAddress = _config.vaultAddress;\n }\n\n /**\n * @dev Internal initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function _initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) internal {\n rewardTokenAddresses = _rewardTokenAddresses;\n\n uint256 assetCount = _assets.length;\n require(assetCount == _pTokens.length, \"Invalid input arrays\");\n for (uint256 i = 0; i < assetCount; ++i) {\n _setPTokenAddress(_assets[i], _pTokens[i]);\n }\n }\n\n /**\n * @notice Collect accumulated reward token and send to Vault.\n * No-ops when the harvester address is not set.\n */\n function collectRewardTokens()\n external\n virtual\n onlyHarvesterOrStrategist\n nonReentrant\n {\n if (harvesterAddress == address(0)) {\n return;\n }\n _collectRewardTokens();\n }\n\n /**\n * @dev Default implementation that transfers reward tokens to the Harvester.\n * Implementing strategies need to add custom logic to collect the rewards.\n */\n function _collectRewardTokens() internal virtual {\n if (harvesterAddress == address(0)) {\n return;\n }\n uint256 rewardTokenCount = rewardTokenAddresses.length;\n for (uint256 i = 0; i < rewardTokenCount; ++i) {\n IERC20 rewardToken = IERC20(rewardTokenAddresses[i]);\n uint256 balance = rewardToken.balanceOf(address(this));\n if (balance > 0) {\n emit RewardTokenCollected(\n harvesterAddress,\n address(rewardToken),\n balance\n );\n rewardToken.safeTransfer(harvesterAddress, balance);\n }\n }\n }\n\n /**\n * @dev Verifies that the caller is the Vault.\n */\n modifier onlyVault() {\n require(msg.sender == vaultAddress, \"Caller is not the Vault\");\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Harvester or Strategist.\n */\n modifier onlyHarvesterOrStrategist() {\n require(\n msg.sender == harvesterAddress ||\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Harvester or Strategist\"\n );\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Vault or Governor.\n */\n modifier onlyVaultOrGovernor() {\n require(\n msg.sender == vaultAddress || msg.sender == governor(),\n \"Caller is not the Vault or Governor\"\n );\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Vault, Governor, or Strategist.\n */\n modifier onlyVaultOrGovernorOrStrategist() {\n require(\n msg.sender == vaultAddress ||\n msg.sender == governor() ||\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Vault, Governor, or Strategist\"\n );\n _;\n }\n\n /**\n * @notice Set the reward token addresses. Any old addresses will be overwritten.\n * @param _rewardTokenAddresses Array of reward token addresses\n */\n function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\n external\n onlyGovernor\n {\n uint256 rewardTokenCount = _rewardTokenAddresses.length;\n for (uint256 i = 0; i < rewardTokenCount; ++i) {\n require(\n _rewardTokenAddresses[i] != address(0),\n \"Can not set an empty address as a reward token\"\n );\n }\n\n emit RewardTokenAddressesUpdated(\n rewardTokenAddresses,\n _rewardTokenAddresses\n );\n rewardTokenAddresses = _rewardTokenAddresses;\n }\n\n /**\n * @notice Get the reward token addresses.\n * @return address[] the reward token addresses.\n */\n function getRewardTokenAddresses()\n external\n view\n returns (address[] memory)\n {\n return rewardTokenAddresses;\n }\n\n /**\n * @notice Provide support for asset by passing its pToken address.\n * This method can only be called by the system Governor\n * @param _asset Address for the asset\n * @param _pToken Address for the corresponding platform token\n */\n function setPTokenAddress(address _asset, address _pToken)\n external\n virtual\n onlyGovernor\n {\n _setPTokenAddress(_asset, _pToken);\n }\n\n /**\n * @notice Remove a supported asset by passing its index.\n * This method can only be called by the system Governor\n * @param _assetIndex Index of the asset to be removed\n */\n function removePToken(uint256 _assetIndex) external virtual onlyGovernor {\n require(_assetIndex < assetsMapped.length, \"Invalid index\");\n address asset = assetsMapped[_assetIndex];\n address pToken = assetToPToken[asset];\n\n if (_assetIndex < assetsMapped.length - 1) {\n assetsMapped[_assetIndex] = assetsMapped[assetsMapped.length - 1];\n }\n assetsMapped.pop();\n assetToPToken[asset] = address(0);\n\n emit PTokenRemoved(asset, pToken);\n }\n\n /**\n * @notice Provide support for asset by passing its pToken address.\n * Add to internal mappings and execute the platform specific,\n * abstract method `_abstractSetPToken`\n * @param _asset Address for the asset\n * @param _pToken Address for the corresponding platform token\n */\n function _setPTokenAddress(address _asset, address _pToken) internal {\n require(assetToPToken[_asset] == address(0), \"pToken already set\");\n require(\n _asset != address(0) && _pToken != address(0),\n \"Invalid addresses\"\n );\n\n assetToPToken[_asset] = _pToken;\n assetsMapped.push(_asset);\n\n emit PTokenAdded(_asset, _pToken);\n\n _abstractSetPToken(_asset, _pToken);\n }\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * strategy contracts, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n public\n virtual\n onlyGovernor\n {\n require(!supportsAsset(_asset), \"Cannot transfer supported asset\");\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /**\n * @notice Set the Harvester contract that can collect rewards.\n * @param _harvesterAddress Address of the harvester contract.\n */\n function setHarvesterAddress(address _harvesterAddress)\n external\n onlyGovernorOrStrategist\n {\n emit HarvesterAddressesUpdated(harvesterAddress, _harvesterAddress);\n harvesterAddress = _harvesterAddress;\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n virtual;\n\n function safeApproveAllTokens() external virtual;\n\n /**\n * @notice Deposit an amount of assets into the platform\n * @param _asset Address for the asset\n * @param _amount Units of asset to deposit\n */\n function deposit(address _asset, uint256 _amount) external virtual;\n\n /**\n * @notice Deposit all supported assets in this strategy contract to the platform\n */\n function depositAll() external virtual;\n\n /**\n * @notice Withdraw an `amount` of assets from the platform and\n * send to the `_recipient`.\n * @param _recipient Address to which the asset should be sent\n * @param _asset Address of the asset\n * @param _amount Units of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external virtual;\n\n /**\n * @notice Withdraw all supported assets from platform and\n * sends to the OToken's Vault.\n */\n function withdrawAll() external virtual;\n\n /**\n * @notice Get the total asset value held in the platform.\n * This includes any interest that was generated since depositing.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n virtual\n returns (uint256 balance);\n\n /**\n * @notice Check if an asset is supported.\n * @param _asset Address of the asset\n * @return bool Whether asset is supported\n */\n function supportsAsset(address _asset) public view virtual returns (bool);\n}\n" + }, + "contracts/utils/PRBMath.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Copied from the PRBMath library\n// https://github.com/PaulRBerg/prb-math/blob/main/src/Common.sol\n\n/// @notice Calculates the square root of x using the Babylonian method.\n///\n/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n///\n/// Notes:\n/// - If x is not a perfect square, the result is rounded down.\n/// - Credits to OpenZeppelin for the explanations in comments below.\n///\n/// @param x The uint256 number for which to calculate the square root.\n/// @return result The result as a uint256.\n/// @custom:smtchecker abstract-function-nondet\nfunction sqrt(uint256 x) pure returns (uint256 result) {\n if (x == 0) {\n return 0;\n }\n\n // For our first guess, we calculate the biggest power of 2 which is smaller than the square root of x.\n //\n // We know that the \"msb\" (most significant bit) of x is a power of 2 such that we have:\n //\n // $$\n // msb(x) <= x <= 2*msb(x)$\n // $$\n //\n // We write $msb(x)$ as $2^k$, and we get:\n //\n // $$\n // k = log_2(x)\n // $$\n //\n // Thus, we can write the initial inequality as:\n //\n // $$\n // 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\\\\n // sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\\\\n // 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1}\n // $$\n //\n // Consequently, $2^{log_2(x) /2} is a good first approximation of sqrt(x) with at least one correct bit.\n uint256 xAux = uint256(x);\n result = 1;\n if (xAux >= 2**128) {\n xAux >>= 128;\n result <<= 64;\n }\n if (xAux >= 2**64) {\n xAux >>= 64;\n result <<= 32;\n }\n if (xAux >= 2**32) {\n xAux >>= 32;\n result <<= 16;\n }\n if (xAux >= 2**16) {\n xAux >>= 16;\n result <<= 8;\n }\n if (xAux >= 2**8) {\n xAux >>= 8;\n result <<= 4;\n }\n if (xAux >= 2**4) {\n xAux >>= 4;\n result <<= 2;\n }\n if (xAux >= 2**2) {\n result <<= 1;\n }\n\n // At this point, `result` is an estimation with at least one bit of precision. We know the true value has at\n // most 128 bits, since it is the square root of a uint256. Newton's method converges quadratically (precision\n // doubles at every iteration). We thus need at most 7 iteration to turn our partial result with one bit of\n // precision into the expected uint128 result.\n unchecked {\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n\n // If x is not a perfect square, round the result toward zero.\n uint256 roundedResult = x / result;\n if (result >= roundedResult) {\n result = roundedResult;\n }\n }\n}\n" + }, + "contracts/utils/StableMath.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\n// Based on StableMath from Stability Labs Pty. Ltd.\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\n\nlibrary StableMath {\n using SafeMath for uint256;\n\n /**\n * @dev Scaling unit for use in specific calculations,\n * where 1 * 10**18, or 1e18 represents a unit '1'\n */\n uint256 private constant FULL_SCALE = 1e18;\n\n /***************************************\n Helpers\n ****************************************/\n\n /**\n * @dev Adjust the scale of an integer\n * @param to Decimals to scale to\n * @param from Decimals to scale from\n */\n function scaleBy(\n uint256 x,\n uint256 to,\n uint256 from\n ) internal pure returns (uint256) {\n if (to > from) {\n x = x.mul(10**(to - from));\n } else if (to < from) {\n // slither-disable-next-line divide-before-multiply\n x = x.div(10**(from - to));\n }\n return x;\n }\n\n /***************************************\n Precise Arithmetic\n ****************************************/\n\n /**\n * @dev Multiplies two precise units, and then truncates by the full scale\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit\n */\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\n return mulTruncateScale(x, y, FULL_SCALE);\n }\n\n /**\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @param scale Scale unit\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit\n */\n function mulTruncateScale(\n uint256 x,\n uint256 y,\n uint256 scale\n ) internal pure returns (uint256) {\n // e.g. assume scale = fullScale\n // z = 10e18 * 9e17 = 9e36\n uint256 z = x.mul(y);\n // return 9e36 / 1e18 = 9e18\n return z.div(scale);\n }\n\n /**\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit, rounded up to the closest base unit.\n */\n function mulTruncateCeil(uint256 x, uint256 y)\n internal\n pure\n returns (uint256)\n {\n // e.g. 8e17 * 17268172638 = 138145381104e17\n uint256 scaled = x.mul(y);\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\n return ceil.div(FULL_SCALE);\n }\n\n /**\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\n * @param x Left hand input to division\n * @param y Right hand input to division\n * @return Result after multiplying the left operand by the scale, and\n * executing the division on the right hand input.\n */\n function divPrecisely(uint256 x, uint256 y)\n internal\n pure\n returns (uint256)\n {\n // e.g. 8e18 * 1e18 = 8e36\n uint256 z = x.mul(FULL_SCALE);\n // e.g. 8e36 / 10e18 = 8e17\n return z.div(y);\n }\n}\n" + }, + "contracts/vault/OETHBaseVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OETH Base VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OETHBaseVault is VaultAdmin {\n constructor(address _weth) VaultAdmin(_weth) {}\n}\n" + }, + "contracts/vault/OETHPlumeVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OETH Plume VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OETHPlumeVault is VaultAdmin {\n constructor(address _weth) VaultAdmin(_weth) {}\n\n // @inheritdoc VaultAdmin\n function _mint(\n address,\n uint256 _amount,\n uint256\n ) internal virtual {\n // Only Strategist or Governor can mint using the Vault for now.\n // This allows the strateigst to fund the Vault with WETH when\n // removing liquidi from wOETH strategy.\n require(\n msg.sender == strategistAddr || isGovernor(),\n \"Caller is not the Strategist or Governor\"\n );\n\n super._mint(_amount);\n }\n}\n" + }, + "contracts/vault/OETHVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OETH VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OETHVault is VaultAdmin {\n constructor(address _weth) VaultAdmin(_weth) {}\n}\n" + }, + "contracts/vault/OSVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title Origin Sonic VaultAdmin contract on Sonic\n * @author Origin Protocol Inc\n */\ncontract OSVault is VaultAdmin {\n constructor(address _wS) VaultAdmin(_wS) {}\n}\n" + }, + "contracts/vault/OUSDVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OUSD VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OUSDVault is VaultAdmin {\n constructor(address _usdc) VaultAdmin(_usdc) {}\n}\n" + }, + "contracts/vault/VaultAdmin.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultAdmin contract\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\n * @author Origin Protocol Inc\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport \"./VaultCore.sol\";\n\nabstract contract VaultAdmin is VaultCore {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n using SafeCast for uint256;\n\n /**\n * @dev Verifies that the caller is the Governor or Strategist.\n */\n modifier onlyGovernorOrStrategist() {\n require(\n msg.sender == strategistAddr || isGovernor(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n constructor(address _asset) VaultCore(_asset) {}\n\n /***************************************\n Configuration\n ****************************************/\n /**\n * @notice Set a buffer of asset to keep in the Vault to handle most\n * redemptions without needing to spend gas unwinding asset from a Strategy.\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\n */\n function setVaultBuffer(uint256 _vaultBuffer)\n external\n onlyGovernorOrStrategist\n {\n require(_vaultBuffer <= 1e18, \"Invalid value\");\n vaultBuffer = _vaultBuffer;\n emit VaultBufferUpdated(_vaultBuffer);\n }\n\n /**\n * @notice Sets the minimum amount of OTokens in a mint to trigger an\n * automatic allocation of funds afterwords.\n * @param _threshold OToken amount with 18 fixed decimals.\n */\n function setAutoAllocateThreshold(uint256 _threshold)\n external\n onlyGovernor\n {\n autoAllocateThreshold = _threshold;\n emit AllocateThresholdUpdated(_threshold);\n }\n\n /**\n * @notice Set address of Strategist\n * @param _address Address of Strategist\n */\n function setStrategistAddr(address _address) external onlyGovernor {\n strategistAddr = _address;\n emit StrategistUpdated(_address);\n }\n\n /**\n * @notice Set the address authorized to call `rebase()`.\n * @param _operator New operator address. May be set to the zero address\n * to disable operator-initiated rebases.\n */\n function setOperatorAddr(address _operator) external onlyGovernor {\n operatorAddr = _operator;\n emit OperatorUpdated(_operator);\n }\n\n /**\n * @notice Set the default Strategy for asset, i.e. the one which\n * the asset will be automatically allocated to and withdrawn from\n * @param _strategy Address of the Strategy\n */\n function setDefaultStrategy(address _strategy)\n external\n onlyGovernorOrStrategist\n {\n emit DefaultStrategyUpdated(_strategy);\n // If its a zero address being passed for the strategy we are removing\n // the default strategy\n if (_strategy != address(0)) {\n // Make sure the strategy meets some criteria\n require(strategies[_strategy].isSupported, \"Strategy not approved\");\n require(\n IStrategy(_strategy).supportsAsset(asset),\n \"Asset not supported by Strategy\"\n );\n }\n defaultStrategy = _strategy;\n }\n\n /**\n * @notice Changes the async withdrawal claim period for OETH & superOETHb\n * @param _delay Delay period (should be between 10 mins to 7 days).\n * Set to 0 to disable async withdrawals\n */\n function setWithdrawalClaimDelay(uint256 _delay) external onlyGovernor {\n require(\n _delay == 0 || (_delay >= 10 minutes && _delay <= 15 days),\n \"Invalid claim delay period\"\n );\n withdrawalClaimDelay = _delay;\n emit WithdrawalClaimDelayUpdated(_delay);\n }\n\n // slither-disable-start reentrancy-no-eth\n /**\n * @notice Set a yield streaming max rate. This spreads yield over\n * time if it is above the max rate. This is a per rebase APR which\n * due to compounding differs from the yearly APR. Governance should\n * consider this fact when picking a desired APR\n * @param apr in 1e18 notation. 3 * 1e18 = 3% APR\n */\n function setRebaseRateMax(uint256 apr) external onlyGovernorOrStrategist {\n // The old yield will be at the old rate\n _rebase();\n // Change the rate\n uint256 newPerSecond = apr / 100 / 365 days;\n require(newPerSecond <= MAX_REBASE_PER_SECOND, \"Rate too high\");\n rebasePerSecondMax = newPerSecond.toUint64();\n emit RebasePerSecondMaxChanged(newPerSecond);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n // slither-disable-start reentrancy-no-eth\n /**\n * @notice Set the drip duration period\n * @param _dripDuration Time in seconds to target a constant yield rate\n */\n function setDripDuration(uint256 _dripDuration)\n external\n onlyGovernorOrStrategist\n {\n // The old yield will be at the old rate\n _rebase();\n dripDuration = _dripDuration.toUint64();\n emit DripDurationChanged(_dripDuration);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /***************************************\n Strategy Config\n ****************************************/\n\n /**\n * @notice Add a strategy to the Vault.\n * @param _addr Address of the strategy to add\n */\n function approveStrategy(address _addr) external onlyGovernor {\n require(!strategies[_addr].isSupported, \"Strategy already approved\");\n require(\n IStrategy(_addr).supportsAsset(asset),\n \"Asset not supported by Strategy\"\n );\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\n allStrategies.push(_addr);\n emit StrategyApproved(_addr);\n }\n\n /**\n * @notice Remove a strategy from the Vault.\n * @param _addr Address of the strategy to remove\n */\n\n function removeStrategy(address _addr) external onlyGovernor {\n require(strategies[_addr].isSupported, \"Strategy not approved\");\n require(defaultStrategy != _addr, \"Strategy is default for asset\");\n\n // Initialize strategyIndex with out of bounds result so function will\n // revert if no valid index found\n uint256 stratCount = allStrategies.length;\n uint256 strategyIndex = stratCount;\n for (uint256 i = 0; i < stratCount; ++i) {\n if (allStrategies[i] == _addr) {\n strategyIndex = i;\n break;\n }\n }\n\n if (strategyIndex < stratCount) {\n allStrategies[strategyIndex] = allStrategies[stratCount - 1];\n allStrategies.pop();\n\n // Withdraw all assets BEFORE marking as unsupported so that AMO\n // strategies can call burnForStrategy/mintForStrategy during withdrawAll\n IStrategy strategy = IStrategy(_addr);\n // slither-disable-next-line reentrancy-no-eth\n strategy.withdrawAll();\n\n // Mark the strategy as not supported\n strategies[_addr].isSupported = false;\n isMintWhitelistedStrategy[_addr] = false;\n\n // 1e13 for 18 decimals. And 1e1(10) for 6 decimals\n uint256 maxDustBalance = uint256(1e13).scaleBy(assetDecimals, 18);\n\n /*\n * Some strategies are not able to withdraw all of their funds in a synchronous call.\n * Prevent the possible accidental removal of such strategies before their funds are withdrawn.\n */\n require(\n strategy.checkBalance(asset) < maxDustBalance,\n \"Strategy has funds\"\n );\n emit StrategyRemoved(_addr);\n }\n }\n\n /**\n * @notice Adds a strategy to the mint whitelist.\n * Reverts if strategy isn't approved on Vault.\n * @param strategyAddr Strategy address\n */\n function addStrategyToMintWhitelist(address strategyAddr)\n external\n onlyGovernor\n {\n require(strategies[strategyAddr].isSupported, \"Strategy not approved\");\n\n require(\n !isMintWhitelistedStrategy[strategyAddr],\n \"Already whitelisted\"\n );\n\n isMintWhitelistedStrategy[strategyAddr] = true;\n\n emit StrategyAddedToMintWhitelist(strategyAddr);\n }\n\n /**\n * @notice Removes a strategy from the mint whitelist.\n * @param strategyAddr Strategy address\n */\n function removeStrategyFromMintWhitelist(address strategyAddr)\n external\n onlyGovernor\n {\n // Intentionally skipping `strategies.isSupported` check since\n // we may wanna remove an address even after removing the strategy\n\n require(isMintWhitelistedStrategy[strategyAddr], \"Not whitelisted\");\n\n isMintWhitelistedStrategy[strategyAddr] = false;\n\n emit StrategyRemovedFromMintWhitelist(strategyAddr);\n }\n\n /***************************************\n Strategies\n ****************************************/\n\n /**\n * @notice Deposit multiple asset from the vault into the strategy.\n * @param _strategyToAddress Address of the Strategy to deposit asset into.\n * @param _assets Array of asset address that will be deposited into the strategy.\n * @param _amounts Array of amounts of each corresponding asset to deposit.\n */\n function depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external onlyGovernorOrStrategist nonReentrant {\n _depositToStrategy(_strategyToAddress, _assets, _amounts);\n }\n\n function _depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) internal virtual {\n require(\n strategies[_strategyToAddress].isSupported,\n \"Invalid to Strategy\"\n );\n require(\n _assets.length == 1 && _amounts.length == 1 && _assets[0] == asset,\n \"Only asset is supported\"\n );\n\n // Check the there is enough asset to transfer once the backing\n // asset reserved for the withdrawal queue is accounted for\n require(\n _amounts[0] <= _assetAvailable(),\n \"Not enough assets available\"\n );\n\n // Send required amount of funds to the strategy\n IERC20(asset).safeTransfer(_strategyToAddress, _amounts[0]);\n\n // Deposit all the funds that have been sent to the strategy\n IStrategy(_strategyToAddress).depositAll();\n }\n\n /**\n * @notice Withdraw multiple asset from the strategy to the vault.\n * @param _strategyFromAddress Address of the Strategy to withdraw asset from.\n * @param _assets Array of asset address that will be withdrawn from the strategy.\n * @param _amounts Array of amounts of each corresponding asset to withdraw.\n */\n function withdrawFromStrategy(\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external onlyGovernorOrStrategist nonReentrant {\n _withdrawFromStrategy(\n address(this),\n _strategyFromAddress,\n _assets,\n _amounts\n );\n }\n\n /**\n * @param _recipient can either be a strategy or the Vault\n */\n function _withdrawFromStrategy(\n address _recipient,\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) internal virtual {\n require(\n strategies[_strategyFromAddress].isSupported,\n \"Invalid from Strategy\"\n );\n require(_assets.length == _amounts.length, \"Parameter length mismatch\");\n\n uint256 assetCount = _assets.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n // Withdraw from Strategy to the recipient\n IStrategy(_strategyFromAddress).withdraw(\n _recipient,\n _assets[i],\n _amounts[i]\n );\n }\n\n _addWithdrawalQueueLiquidity();\n }\n\n /**\n * @notice Sets the maximum allowable difference between\n * total supply and asset' value.\n */\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\n maxSupplyDiff = _maxSupplyDiff;\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\n }\n\n /**\n * @notice Sets the trusteeAddress that can receive a portion of yield.\n * Setting to the zero address disables this feature.\n */\n function setTrusteeAddress(address _address) external onlyGovernor {\n trusteeAddress = _address;\n emit TrusteeAddressChanged(_address);\n }\n\n /**\n * @notice Sets the TrusteeFeeBps to the percentage of yield that should be\n * received in basis points.\n */\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\n require(_basis <= 5000, \"basis cannot exceed 50%\");\n trusteeFeeBps = _basis;\n emit TrusteeFeeBpsChanged(_basis);\n }\n\n /***************************************\n Pause\n ****************************************/\n\n /**\n * @notice Set the deposit paused flag to true to prevent rebasing.\n */\n function pauseRebase() external onlyGovernorOrStrategist {\n rebasePaused = true;\n emit RebasePaused();\n }\n\n /**\n * @notice Set the deposit paused flag to true to allow rebasing.\n */\n function unpauseRebase() external onlyGovernorOrStrategist {\n rebasePaused = false;\n emit RebaseUnpaused();\n }\n\n /**\n * @notice Set the deposit paused flag to true to prevent capital movement.\n */\n function pauseCapital() external onlyGovernorOrStrategist {\n capitalPaused = true;\n emit CapitalPaused();\n }\n\n /**\n * @notice Set the deposit paused flag to false to enable capital movement.\n */\n function unpauseCapital() external onlyGovernorOrStrategist {\n capitalPaused = false;\n emit CapitalUnpaused();\n }\n\n /***************************************\n Utils\n ****************************************/\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n require(asset != _asset, \"Only unsupported asset\");\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /***************************************\n Strategies Admin\n ****************************************/\n\n /**\n * @notice Withdraws all asset from the strategy and sends asset to the Vault.\n * @param _strategyAddr Strategy address.\n */\n function withdrawAllFromStrategy(address _strategyAddr)\n external\n onlyGovernorOrStrategist\n {\n _withdrawAllFromStrategy(_strategyAddr);\n }\n\n function _withdrawAllFromStrategy(address _strategyAddr) internal virtual {\n require(\n strategies[_strategyAddr].isSupported,\n \"Strategy is not supported\"\n );\n IStrategy strategy = IStrategy(_strategyAddr);\n strategy.withdrawAll();\n _addWithdrawalQueueLiquidity();\n }\n\n /**\n * @notice Withdraws all asset from all the strategies and sends asset to the Vault.\n */\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\n _withdrawAllFromStrategies();\n }\n\n function _withdrawAllFromStrategies() internal virtual {\n uint256 stratCount = allStrategies.length;\n for (uint256 i = 0; i < stratCount; ++i) {\n IStrategy(allStrategies[i]).withdrawAll();\n }\n _addWithdrawalQueueLiquidity();\n }\n}\n" + }, + "contracts/vault/VaultCore.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultCore contract\n * @notice The Vault contract stores asset. On a deposit, OTokens will be minted\n and sent to the depositor. On a withdrawal, OTokens will be burned and\n asset will be sent to the withdrawer. The Vault accepts deposits of\n interest from yield bearing strategies which will modify the supply\n of OTokens.\n * @author Origin Protocol Inc\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\n\nimport \"./VaultInitializer.sol\";\n\nabstract contract VaultCore is VaultInitializer {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n /**\n * @dev Verifies that the rebasing is not paused.\n */\n modifier whenNotRebasePaused() {\n require(!rebasePaused, \"Rebasing paused\");\n _;\n }\n\n /**\n * @dev Verifies that the deposits are not paused.\n */\n modifier whenNotCapitalPaused() {\n require(!capitalPaused, \"Capital paused\");\n _;\n }\n\n constructor(address _asset) VaultInitializer(_asset) {}\n\n ////////////////////////////////////////////////////\n /// MINT / BURN ///\n ////////////////////////////////////////////////////\n /**\n * @notice Deposit a supported asset and mint OTokens.\n * @dev Deprecated: use `mint(uint256 _amount)` instead.\n * @dev Deprecated: param _asset Address of the asset being deposited\n * @param _amount Amount of the asset being deposited\n * @dev Deprecated: param _minimumOusdAmount Minimum OTokens to mint\n */\n function mint(\n address,\n uint256 _amount,\n uint256\n ) external whenNotCapitalPaused nonReentrant {\n _mint(_amount);\n }\n\n /**\n * @notice Deposit a supported asset and mint OTokens.\n * @param _amount Amount of the asset being deposited\n */\n function mint(uint256 _amount) external whenNotCapitalPaused nonReentrant {\n _mint(_amount);\n }\n\n // slither-disable-start reentrancy-no-eth\n /**\n * @dev Deposit a supported asset and mint OTokens.\n * @param _amount Amount of the asset being deposited\n */\n function _mint(uint256 _amount) internal virtual {\n require(_amount > 0, \"Amount must be greater than 0\");\n\n // Scale amount to 18 decimals\n uint256 scaledAmount = _amount.scaleBy(18, assetDecimals);\n\n emit Mint(msg.sender, scaledAmount);\n\n // Mint oTokens\n oToken.mint(msg.sender, scaledAmount);\n\n IERC20(asset).safeTransferFrom(msg.sender, address(this), _amount);\n\n // Give priority to the withdrawal queue for the new asset liquidity\n _addWithdrawalQueueLiquidity();\n\n // Auto-allocate if necessary\n if (scaledAmount >= autoAllocateThreshold) {\n _allocate();\n }\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /**\n * @notice Mint OTokens for an allowed Strategy\n * @param _amount Amount of OToken to mint\n *\n * Notice: can't use `nonReentrant` modifier since the `mint` function can\n * call `allocate`, and that can trigger an AMO strategy to call this function\n * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision.\n *\n * Also important to understand is that this is a limitation imposed by the test suite.\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\n * that are moving funds between the Vault and end user wallets can influence strategies\n * utilizing this function.\n */\n function mintForStrategy(uint256 _amount)\n external\n virtual\n whenNotCapitalPaused\n {\n require(\n strategies[msg.sender].isSupported == true,\n \"Unsupported strategy\"\n );\n require(\n isMintWhitelistedStrategy[msg.sender] == true,\n \"Not whitelisted strategy\"\n );\n\n emit Mint(msg.sender, _amount);\n // Mint matching amount of OTokens\n oToken.mint(msg.sender, _amount);\n }\n\n /**\n * @notice Burn OTokens for an allowed Strategy\n * @param _amount Amount of OToken to burn\n *\n * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could\n * require withdrawal on an AMO strategy and that one can call `burnForStrategy`\n * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision.\n *\n * Also important to understand is that this is a limitation imposed by the test suite.\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\n * that are moving funds between the Vault and end user wallets can influence strategies\n * utilizing this function.\n */\n function burnForStrategy(uint256 _amount)\n external\n virtual\n whenNotCapitalPaused\n {\n require(\n strategies[msg.sender].isSupported == true,\n \"Unsupported strategy\"\n );\n require(\n isMintWhitelistedStrategy[msg.sender] == true,\n \"Not whitelisted strategy\"\n );\n\n emit Redeem(msg.sender, _amount);\n\n // Burn OTokens\n oToken.burn(msg.sender, _amount);\n }\n\n ////////////////////////////////////////////////////\n /// ASYNC WITHDRAWALS ///\n ////////////////////////////////////////////////////\n /**\n * @notice Request an asynchronous withdrawal of asset in exchange for OToken.\n * The OToken is burned on request and the asset is transferred to the withdrawer on claim.\n * This request can be claimed once the withdrawal queue's `claimable` amount\n * is greater than or equal this request's `queued` amount.\n * There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs\n * enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue.\n * OToken is converted to asset at 1:1.\n * @param _amount Amount of OToken to burn.\n * @return requestId Unique ID for the withdrawal request\n * @return queued Cumulative total of all asset queued including already claimed requests.\n */\n function requestWithdrawal(uint256 _amount)\n external\n virtual\n whenNotCapitalPaused\n nonReentrant\n returns (uint256 requestId, uint256 queued)\n {\n require(_amount > 0, \"Amount must be greater than 0\");\n require(withdrawalClaimDelay > 0, \"Async withdrawals not enabled\");\n\n // The check that the requester has enough OToken is done in to later burn call\n\n requestId = withdrawalQueueMetadata.nextWithdrawalIndex;\n queued =\n withdrawalQueueMetadata.queued +\n _amount.scaleBy(assetDecimals, 18);\n\n // Store the next withdrawal request\n withdrawalQueueMetadata.nextWithdrawalIndex = SafeCast.toUint128(\n requestId + 1\n );\n // Store the updated queued amount which reserves asset in the withdrawal queue\n // and reduces the vault's total asset\n withdrawalQueueMetadata.queued = SafeCast.toUint128(queued);\n // Store the user's withdrawal request\n // `queued` is in asset decimals, while `amount` is in OToken decimals (18)\n withdrawalRequests[requestId] = WithdrawalRequest({\n withdrawer: msg.sender,\n claimed: false,\n timestamp: uint40(block.timestamp),\n amount: SafeCast.toUint128(_amount),\n queued: SafeCast.toUint128(queued)\n });\n\n // Burn the user's OToken\n oToken.burn(msg.sender, _amount);\n\n // Prevent withdrawal if the vault is solvent by more than the allowed percentage\n _postRedeem();\n\n emit WithdrawalRequested(msg.sender, requestId, _amount, queued);\n }\n\n // slither-disable-start reentrancy-no-eth\n /**\n * @notice Claim a previously requested withdrawal once it is claimable.\n * This request can be claimed once the withdrawal queue's `claimable` amount\n * is greater than or equal this request's `queued` amount and 10 minutes has passed.\n * If the requests is not claimable, the transaction will revert with `Queue pending liquidity`.\n * If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`.\n * OToken is converted to asset at 1:1.\n * @param _requestId Unique ID for the withdrawal request\n * @return amount Amount of asset transferred to the withdrawer\n */\n function claimWithdrawal(uint256 _requestId)\n external\n virtual\n whenNotCapitalPaused\n nonReentrant\n returns (uint256 amount)\n {\n // Try and get more liquidity if there is not enough available\n if (\n withdrawalRequests[_requestId].queued >\n withdrawalQueueMetadata.claimable\n ) {\n // Add any asset to the withdrawal queue\n // this needs to remain here as:\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\n // - funds can be withdrawn from a strategy\n //\n // Those funds need to be added to withdrawal queue liquidity\n _addWithdrawalQueueLiquidity();\n }\n\n // Scale amount to asset decimals\n amount = _claimWithdrawal(_requestId);\n\n // transfer asset from the vault to the withdrawer\n IERC20(asset).safeTransfer(msg.sender, amount);\n\n // Prevent insolvency\n _postRedeem();\n }\n\n // slither-disable-end reentrancy-no-eth\n /**\n * @notice Claim a previously requested withdrawals once they are claimable.\n * This requests can be claimed once the withdrawal queue's `claimable` amount\n * is greater than or equal each request's `queued` amount and 10 minutes has passed.\n * If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`.\n * If one of the requests is not older than 10 minutes,\n * the whole transaction will revert with `Claim delay not met`.\n * @param _requestIds Unique ID of each withdrawal request\n * @return amounts Amount of asset received for each request\n * @return totalAmount Total amount of asset transferred to the withdrawer\n */\n function claimWithdrawals(uint256[] calldata _requestIds)\n external\n virtual\n whenNotCapitalPaused\n nonReentrant\n returns (uint256[] memory amounts, uint256 totalAmount)\n {\n // Add any asset to the withdrawal queue\n // this needs to remain here as:\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\n // - funds can be withdrawn from a strategy\n //\n // Those funds need to be added to withdrawal queue liquidity\n _addWithdrawalQueueLiquidity();\n\n amounts = new uint256[](_requestIds.length);\n for (uint256 i; i < _requestIds.length; ++i) {\n // Scale all amounts to asset decimals, thus totalAmount is also in asset decimals\n amounts[i] = _claimWithdrawal(_requestIds[i]);\n totalAmount += amounts[i];\n }\n\n // transfer all the claimed asset from the vault to the withdrawer\n IERC20(asset).safeTransfer(msg.sender, totalAmount);\n\n // Prevent insolvency\n _postRedeem();\n\n return (amounts, totalAmount);\n }\n\n function _claimWithdrawal(uint256 requestId)\n internal\n returns (uint256 amount)\n {\n require(withdrawalClaimDelay > 0, \"Async withdrawals not enabled\");\n\n // Load the structs from storage into memory\n WithdrawalRequest memory request = withdrawalRequests[requestId];\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n require(\n request.timestamp + withdrawalClaimDelay <= block.timestamp,\n \"Claim delay not met\"\n );\n // If there isn't enough reserved liquidity in the queue to claim\n require(request.queued <= queue.claimable, \"Queue pending liquidity\");\n require(request.withdrawer == msg.sender, \"Not requester\");\n require(request.claimed == false, \"Already claimed\");\n\n // Store the request as claimed\n withdrawalRequests[requestId].claimed = true;\n // Store the updated claimed amount\n withdrawalQueueMetadata.claimed =\n queue.claimed +\n SafeCast.toUint128(\n StableMath.scaleBy(request.amount, assetDecimals, 18)\n );\n\n emit WithdrawalClaimed(msg.sender, requestId, request.amount);\n\n return StableMath.scaleBy(request.amount, assetDecimals, 18);\n }\n\n function _postRedeem() internal view {\n // Until we can prove that we won't affect the prices of our asset\n // by withdrawing them, this should be here.\n // It's possible that a strategy was off on its asset total, perhaps\n // a reward token sold for more or for less than anticipated.\n uint256 totalUnits = _totalValue();\n\n // Check that the OTokens are backed by enough asset\n if (maxSupplyDiff > 0) {\n // If there are more outstanding withdrawal requests than asset in the vault and strategies\n // then the available asset will be negative and totalUnits will be rounded up to zero.\n // As we don't know the exact shortfall amount, we will reject all redeem and withdrawals\n require(totalUnits > 0, \"Too many outstanding requests\");\n\n // Allow a max difference of maxSupplyDiff% between\n // asset value and OUSD total supply\n uint256 diff = oToken.totalSupply().divPrecisely(totalUnits);\n require(\n (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,\n \"Backing supply liquidity error\"\n );\n }\n }\n\n /**\n * @notice Allocate unallocated funds on Vault to strategies.\n */\n function allocate() external virtual whenNotCapitalPaused nonReentrant {\n // Add any unallocated asset to the withdrawal queue first\n _addWithdrawalQueueLiquidity();\n\n _allocate();\n }\n\n /**\n * @dev Allocate asset (eg. WETH or USDC) to the default asset strategy\n * if there is excess to the Vault buffer.\n * This is called from either `mint` or `allocate` and assumes `_addWithdrawalQueueLiquidity`\n * has been called before this function.\n */\n function _allocate() internal virtual {\n // No need to do anything if no default strategy for asset\n address depositStrategyAddr = defaultStrategy;\n if (depositStrategyAddr == address(0)) return;\n\n uint256 assetAvailableInVault = _assetAvailable();\n // No need to do anything if there isn't any asset in the vault to allocate\n if (assetAvailableInVault == 0) return;\n\n // Calculate the target buffer for the vault using the total supply\n uint256 totalSupply = oToken.totalSupply();\n // Scaled to asset decimals\n uint256 targetBuffer = totalSupply.mulTruncate(vaultBuffer).scaleBy(\n assetDecimals,\n 18\n );\n\n // If available asset in the Vault is below or equal the target buffer then there's nothing to allocate\n if (assetAvailableInVault <= targetBuffer) return;\n\n // The amount of asset to allocate to the default strategy\n uint256 allocateAmount = assetAvailableInVault - targetBuffer;\n\n IStrategy strategy = IStrategy(depositStrategyAddr);\n // Transfer asset to the strategy and call the strategy's deposit function\n IERC20(asset).safeTransfer(address(strategy), allocateAmount);\n strategy.deposit(asset, allocateAmount);\n\n emit AssetAllocated(asset, depositStrategyAddr, allocateAmount);\n }\n\n /**\n * @notice Calculate the total value of asset held by the Vault and all\n * strategies and update the supply of OTokens.\n * @dev Restricted to the Operator, Strategist or Governor.\n */\n function rebase() external virtual nonReentrant {\n require(\n msg.sender == operatorAddr ||\n msg.sender == strategistAddr ||\n isGovernor(),\n \"Caller not authorized\"\n );\n _rebase();\n }\n\n /**\n * @dev Calculate the total value of asset held by the Vault and all\n * strategies and update the supply of OTokens, optionally sending a\n * portion of the yield to the trustee.\n * @return totalUnits Total balance of Vault in units\n */\n function _rebase() internal whenNotRebasePaused returns (uint256) {\n uint256 supply = oToken.totalSupply();\n uint256 vaultValue = _totalValue();\n // If no supply yet, do not rebase\n if (supply == 0) {\n return vaultValue;\n }\n\n // Calculate yield and new supply\n (uint256 yield, uint256 targetRate) = _nextYield(supply, vaultValue);\n uint256 newSupply = supply + yield;\n // Only rebase upwards and if we have enough backing funds\n if (newSupply <= supply || newSupply > vaultValue) {\n return vaultValue;\n }\n\n rebasePerSecondTarget = uint64(_min(targetRate, type(uint64).max));\n lastRebase = uint64(block.timestamp); // Intentional cast\n\n // Fee collection on yield\n address _trusteeAddress = trusteeAddress; // gas savings\n uint256 fee = 0;\n if (_trusteeAddress != address(0)) {\n fee = (yield * trusteeFeeBps) / 1e4;\n if (fee > 0) {\n require(fee < yield, \"Fee must not be greater than yield\");\n oToken.mint(_trusteeAddress, fee);\n }\n }\n emit YieldDistribution(_trusteeAddress, yield, fee);\n\n // Only ratchet OToken supply upwards\n // Final check uses latest totalSupply\n if (newSupply > oToken.totalSupply()) {\n oToken.changeSupply(newSupply);\n }\n return vaultValue;\n }\n\n /**\n * @notice Calculates the amount that would rebase at next rebase.\n * This is before any fees.\n * @return yield amount of expected yield\n */\n function previewYield() external view returns (uint256 yield) {\n (yield, ) = _nextYield(oToken.totalSupply(), _totalValue());\n return yield;\n }\n\n /**\n * @dev Calculates the amount that would rebase at next rebase.\n * See this Readme for detailed explanation:\n * contracts/contracts/vault/README - Yield Limits.md\n */\n function _nextYield(uint256 supply, uint256 vaultValue)\n internal\n view\n virtual\n returns (uint256 yield, uint256 targetRate)\n {\n uint256 nonRebasing = oToken.nonRebasingSupply();\n uint256 rebasing = supply - nonRebasing;\n uint256 elapsed = block.timestamp - lastRebase;\n targetRate = rebasePerSecondTarget;\n\n if (\n elapsed == 0 || // Yield only once per block.\n rebasing == 0 || // No yield if there are no rebasing tokens to give it to.\n supply > vaultValue || // No yield if we do not have yield to give.\n block.timestamp >= type(uint64).max // No yield if we are too far in the future to calculate it correctly.\n ) {\n return (0, targetRate);\n }\n\n // Start with the full difference available\n yield = vaultValue - supply;\n\n // Cap via optional automatic duration smoothing\n uint256 _dripDuration = dripDuration;\n if (_dripDuration > 1) {\n // If we are able to sustain an increased drip rate for\n // double the duration, then increase the target drip rate\n targetRate = _max(targetRate, yield / (_dripDuration * 2));\n // If we cannot sustain the target rate any more,\n // then rebase what we can, and reduce the target\n targetRate = _min(targetRate, yield / _dripDuration);\n // drip at the new target rate\n yield = _min(yield, targetRate * elapsed);\n }\n\n // Cap per second. elapsed is not 1e18 denominated\n yield = _min(yield, (rebasing * elapsed * rebasePerSecondMax) / 1e18);\n\n // Cap at a hard max per rebase, to avoid long durations resulting in huge rebases\n yield = _min(yield, (rebasing * MAX_REBASE) / 1e18);\n\n return (yield, targetRate);\n }\n\n /**\n * @notice Determine the total value of asset held by the vault and its\n * strategies.\n * @return value Total value in USD/ETH (1e18)\n */\n function totalValue() external view virtual returns (uint256 value) {\n value = _totalValue();\n }\n\n /**\n * @dev Internal Calculate the total value of the asset held by the\n * vault and its strategies.\n * @dev The total value of all WETH held by the vault and all its strategies\n * less any WETH that is reserved for the withdrawal queue.\n * If there is not enough WETH in the vault and all strategies to cover\n * all outstanding withdrawal requests then return a total value of 0.\n * @return value Total value in USD/ETH (1e18)\n */\n function _totalValue() internal view virtual returns (uint256 value) {\n // As asset is the only asset, just return the asset balance\n value = _checkBalance(asset).scaleBy(18, assetDecimals);\n }\n\n /**\n * @notice Get the balance of an asset held in Vault and all strategies.\n * @param _asset Address of asset\n * @return uint256 Balance of asset in decimals of asset\n */\n function checkBalance(address _asset) external view returns (uint256) {\n return _checkBalance(_asset);\n }\n\n /**\n * @notice Get the balance of an asset held in Vault and all strategies.\n * @dev Get the balance of an asset held in Vault and all strategies\n * less any asset that is reserved for the withdrawal queue.\n * BaseAsset is the only asset that can return a non-zero balance.\n * All other asset will return 0 even if there is some dust amounts left in the Vault.\n * For example, there is 1 wei left of stETH (or USDC) in the OETH (or OUSD) Vault but\n * will return 0 in this function.\n *\n * If there is not enough asset in the vault and all strategies to cover all outstanding\n * withdrawal requests then return a asset balance of 0\n * @param _asset Address of asset\n * @return balance Balance of asset in decimals of asset\n */\n function _checkBalance(address _asset)\n internal\n view\n virtual\n returns (uint256 balance)\n {\n if (_asset != asset) return 0;\n\n // Get the asset in the vault and the strategies\n IERC20 asset = IERC20(_asset);\n balance = asset.balanceOf(address(this));\n uint256 stratCount = allStrategies.length;\n for (uint256 i = 0; i < stratCount; ++i) {\n IStrategy strategy = IStrategy(allStrategies[i]);\n if (strategy.supportsAsset(_asset)) {\n balance = balance + strategy.checkBalance(_asset);\n }\n }\n\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // If the vault becomes insolvent enough that the total value in the vault and all strategies\n // is less than the outstanding withdrawals.\n // For example, there was a mass slashing event and most users request a withdrawal.\n if (balance + queue.claimed < queue.queued) {\n return 0;\n }\n\n // Need to remove asset that is reserved for the withdrawal queue\n return balance + queue.claimed - queue.queued;\n }\n\n /**\n * @notice Adds WETH to the withdrawal queue if there is a funding shortfall.\n * @dev is called from the Native Staking strategy when validator withdrawals are processed.\n * It also called before any WETH is allocated to a strategy.\n */\n function addWithdrawalQueueLiquidity() external {\n _addWithdrawalQueueLiquidity();\n }\n\n /**\n * @dev Adds asset (eg. WETH or USDC) to the withdrawal queue if there is a funding shortfall.\n * This assumes 1 asset equal 1 corresponding OToken.\n */\n function _addWithdrawalQueueLiquidity()\n internal\n returns (uint256 addedClaimable)\n {\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // Check if the claimable asset is less than the queued amount\n uint256 queueShortfall = queue.queued - queue.claimable;\n\n // No need to do anything is the withdrawal queue is full funded\n if (queueShortfall == 0) {\n return 0;\n }\n\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\n\n // Of the claimable withdrawal requests, how much is unclaimed?\n // That is, the amount of asset that is currently allocated for the withdrawal queue\n uint256 allocatedBaseAsset = queue.claimable - queue.claimed;\n\n // If there is no unallocated asset then there is nothing to add to the queue\n if (assetBalance <= allocatedBaseAsset) {\n return 0;\n }\n\n uint256 unallocatedBaseAsset = assetBalance - allocatedBaseAsset;\n // the new claimable amount is the smaller of the queue shortfall or unallocated asset\n addedClaimable = queueShortfall < unallocatedBaseAsset\n ? queueShortfall\n : unallocatedBaseAsset;\n uint256 newClaimable = queue.claimable + addedClaimable;\n\n // Store the new claimable amount back to storage\n withdrawalQueueMetadata.claimable = SafeCast.toUint128(newClaimable);\n\n // emit a WithdrawalClaimable event\n emit WithdrawalClaimable(newClaimable, addedClaimable);\n }\n\n /**\n * @dev Calculate how much asset (eg. WETH or USDC) in the vault is not reserved for the withdrawal queue.\n * That is, it is available to be redeemed or deposited into a strategy.\n */\n function _assetAvailable() internal view returns (uint256 assetAvailable) {\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // The amount of asset that is still to be claimed in the withdrawal queue\n uint256 outstandingWithdrawals = queue.queued - queue.claimed;\n\n // The amount of sitting in asset in the vault\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\n // If there is not enough asset in the vault to cover the outstanding withdrawals\n if (assetBalance <= outstandingWithdrawals) return 0;\n\n return assetBalance - outstandingWithdrawals;\n }\n\n /***************************************\n Utils\n ****************************************/\n\n /**\n * @notice Return the number of asset supported by the Vault.\n */\n function getAssetCount() public view returns (uint256) {\n return 1;\n }\n\n /**\n * @notice Return all vault asset addresses in order\n */\n function getAllAssets() external view returns (address[] memory) {\n address[] memory a = new address[](1);\n a[0] = asset;\n return a;\n }\n\n /**\n * @notice Return the number of strategies active on the Vault.\n */\n function getStrategyCount() external view returns (uint256) {\n return allStrategies.length;\n }\n\n /**\n * @notice Return the array of all strategies\n */\n function getAllStrategies() external view returns (address[] memory) {\n return allStrategies;\n }\n\n /**\n * @notice Returns whether the vault supports the asset\n * @param _asset address of the asset\n * @return true if supported\n */\n function isSupportedAsset(address _asset) external view returns (bool) {\n return asset == _asset;\n }\n\n function _min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n function _max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n}\n" + }, + "contracts/vault/VaultInitializer.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultInitializer contract\n * @notice The Vault contract initializes the vault.\n * @author Origin Protocol Inc\n */\n\nimport \"./VaultStorage.sol\";\n\nabstract contract VaultInitializer is VaultStorage {\n constructor(address _asset) VaultStorage(_asset) {}\n\n function initialize(address _oToken) external onlyGovernor initializer {\n require(_oToken != address(0), \"oToken address is zero\");\n\n oToken = OUSD(_oToken);\n\n rebasePaused = false;\n capitalPaused = true;\n\n // Initial Vault buffer of 0%\n vaultBuffer = 0;\n // Initial allocate threshold of 25,000 OUSD\n autoAllocateThreshold = 25000e18;\n // Initialize all strategies\n allStrategies = new address[](0);\n // Start with drip duration: 7 days\n dripDuration = 604800;\n }\n}\n" + }, + "contracts/vault/VaultStorage.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultStorage contract\n * @notice The VaultStorage contract defines the storage for the Vault contracts\n * @author Origin Protocol Inc\n */\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { OUSD } from \"../token/OUSD.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport \"../utils/Helpers.sol\";\n\nabstract contract VaultStorage is Initializable, Governable {\n using SafeERC20 for IERC20;\n\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\n event StrategyApproved(address _addr);\n event StrategyRemoved(address _addr);\n event Mint(address _addr, uint256 _value);\n event Redeem(address _addr, uint256 _value);\n event CapitalPaused();\n event CapitalUnpaused();\n event DefaultStrategyUpdated(address _strategy);\n event RebasePaused();\n event RebaseUnpaused();\n event VaultBufferUpdated(uint256 _vaultBuffer);\n event AllocateThresholdUpdated(uint256 _threshold);\n event StrategistUpdated(address _address);\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\n event TrusteeFeeBpsChanged(uint256 _basis);\n event TrusteeAddressChanged(address _address);\n event StrategyAddedToMintWhitelist(address indexed strategy);\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\n event DripDurationChanged(uint256 dripDuration);\n event OperatorUpdated(address newOperator);\n event WithdrawalRequested(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount,\n uint256 _queued\n );\n event WithdrawalClaimed(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount\n );\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\n\n // Since we are proxy, all state should be uninitalized.\n // Since this storage contract does not have logic directly on it\n // we should not be checking for to see if these variables can be constant.\n // slither-disable-start uninitialized-state\n // slither-disable-start constable-states\n\n /// @dev mapping of supported vault assets to their configuration\n uint256 private _deprecated_assets;\n /// @dev list of all assets supported by the vault.\n address[] private _deprecated_allAssets;\n\n // Strategies approved for use by the Vault\n struct Strategy {\n bool isSupported;\n uint256 _deprecated; // Deprecated storage slot\n }\n /// @dev mapping of strategy contracts to their configuration\n mapping(address => Strategy) public strategies;\n /// @dev list of all vault strategies\n address[] internal allStrategies;\n\n /// @notice Address of the Oracle price provider contract\n address private _deprecated_priceProvider;\n /// @notice pause rebasing if true\n bool public rebasePaused;\n /// @notice pause operations that change the OToken supply.\n /// eg mint, redeem, allocate, mint/burn for strategy\n bool public capitalPaused;\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\n uint256 private _deprecated_redeemFeeBps;\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\n uint256 public vaultBuffer;\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\n uint256 public autoAllocateThreshold;\n /// @dev Deprecated. Was the auto-rebase trigger threshold for mint/redeem.\n /// Storage slot retained for proxy compatibility; no longer read or written.\n uint256 internal __deprecatedRebaseThreshold;\n\n /// @dev Address of the OToken token. eg OUSD or OETH.\n OUSD public oToken;\n\n /// @dev Address of the contract responsible for post rebase syncs with AMMs\n address private _deprecated_rebaseHooksAddr = address(0);\n\n /// @dev Deprecated: Address of Uniswap\n address private _deprecated_uniswapAddr = address(0);\n\n /// @notice Address of the Strategist\n address public strategistAddr = address(0);\n\n /// @notice Mapping of asset address to the Strategy that they should automatically\n // be allocated to\n uint256 private _deprecated_assetDefaultStrategies;\n\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\n uint256 public maxSupplyDiff;\n\n /// @notice Trustee contract that can collect a percentage of yield\n address public trusteeAddress;\n\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\n uint256 public trusteeFeeBps;\n\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\n address[] private _deprecated_swapTokens;\n\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\n\n address private _deprecated_ousdMetaStrategy;\n\n /// @notice How much OTokens are currently minted by the strategy\n int256 private _deprecated_netOusdMintedForStrategy;\n\n /// @notice How much net total OTokens are allowed to be minted by all strategies\n uint256 private _deprecated_netOusdMintForStrategyThreshold;\n\n uint256 private _deprecated_swapConfig;\n\n // List of strategies that can mint oTokens directly\n // Used in OETHBaseVaultCore\n mapping(address => bool) public isMintWhitelistedStrategy;\n\n /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\n /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\n address private _deprecated_dripper;\n\n /// Withdrawal Queue Storage /////\n\n struct WithdrawalQueueMetadata {\n // cumulative total of all withdrawal requests included the ones that have already been claimed\n uint128 queued;\n // cumulative total of all the requests that can be claimed including the ones that have already been claimed\n uint128 claimable;\n // total of all the requests that have been claimed\n uint128 claimed;\n // index of the next withdrawal request starting at 0\n uint128 nextWithdrawalIndex;\n }\n\n /// @notice Global metadata for the withdrawal queue including:\n /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed\n /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed\n /// claimed - total of all the requests that have been claimed\n /// nextWithdrawalIndex - index of the next withdrawal request starting at 0\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\n\n struct WithdrawalRequest {\n address withdrawer;\n bool claimed;\n uint40 timestamp; // timestamp of the withdrawal request\n // Amount of oTokens to redeem. eg OETH\n uint128 amount;\n // cumulative total of all withdrawal requests including this one.\n // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\n uint128 queued;\n }\n\n /// @notice Mapping of withdrawal request indices to the user withdrawal request data\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\n\n /// @notice Sets a minimum delay that is required to elapse between\n /// requesting async withdrawals and claiming the request.\n /// When set to 0 async withdrawals are disabled.\n uint256 public withdrawalClaimDelay;\n\n /// @notice Time in seconds that the vault last rebased yield.\n uint64 public lastRebase;\n\n /// @notice Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\n uint64 public dripDuration;\n\n /// @notice max rebase percentage per second\n /// Can be used to set maximum yield of the protocol,\n /// spreading out yield over time\n uint64 public rebasePerSecondMax;\n\n /// @notice target rebase rate limit, based on past rates and funds available.\n uint64 public rebasePerSecondTarget;\n\n uint256 internal constant MAX_REBASE = 0.02 ether;\n uint256 internal constant MAX_REBASE_PER_SECOND =\n uint256(0.05 ether) / 1 days;\n\n /// @notice Default strategy for asset\n address public defaultStrategy;\n\n /// @notice Address authorized to call `rebase()` directly. The Governor\n /// and Strategist are always allowed in addition to this address.\n address public operatorAddr;\n\n // For future use\n uint256[41] private __gap;\n\n /// @notice Index of WETH asset in allAssets array\n /// Legacy OETHVaultCore code, relocated here for vault consistency.\n uint256 private _deprecated_wethAssetIndex;\n\n /// @dev Address of the asset (eg. WETH or USDC)\n address public immutable asset;\n uint8 internal immutable assetDecimals;\n\n // slither-disable-end constable-states\n // slither-disable-end uninitialized-state\n\n constructor(address _asset) {\n uint8 _decimals = IERC20Metadata(_asset).decimals();\n require(_decimals <= 18, \"invalid asset decimals\");\n asset = _asset;\n assetDecimals = _decimals;\n }\n\n /// @notice Deprecated: use `oToken()` instead.\n function oUSD() external view returns (OUSD) {\n return oToken;\n }\n}\n" + }, + "contracts/zapper/AbstractOTokenZapper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\n\nabstract contract AbstractOTokenZapper {\n IERC20 public immutable oToken;\n IERC4626 public immutable wOToken;\n IVault public immutable vault;\n\n IWETH9 public immutable weth;\n\n address private constant ETH_MARKER =\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n event Zap(address indexed minter, address indexed asset, uint256 amount);\n\n constructor(\n address _oToken,\n address _wOToken,\n address _vault,\n address _weth\n ) {\n oToken = IERC20(_oToken);\n wOToken = IERC4626(_wOToken);\n vault = IVault(_vault);\n weth = IWETH9(_weth);\n\n IWETH9(_weth).approve(address(_vault), type(uint256).max);\n IERC20(_oToken).approve(_wOToken, type(uint256).max);\n }\n\n /**\n * @dev Deposit ETH and receive OToken in return.\n * Will verify that the user is sent 1:1 for ETH.\n */\n receive() external payable {\n deposit();\n }\n\n /**\n * @dev Deposit ETH and receive OToken in return\n * Will verify that the user is sent 1:1 for ETH.\n * @return Amount of OETH sent to user\n */\n function deposit() public payable returns (uint256) {\n uint256 balance = address(this).balance;\n\n emit Zap(msg.sender, ETH_MARKER, balance);\n\n // Wrap ETH\n weth.deposit{ value: balance }();\n\n // Mint with WETH\n return _mint(balance, msg.sender);\n }\n\n /**\n * @dev Deposit ETH and receive superOETHb in return\n * @param minReceived min amount of wsuperOETHb to receive\n * @return Amount of wsuperOETHb sent to user\n */\n function depositETHForWrappedTokens(uint256 minReceived)\n external\n payable\n returns (uint256)\n {\n // slither-disable-start reentrancy-balance\n uint256 balance = address(this).balance;\n\n emit Zap(msg.sender, ETH_MARKER, balance);\n\n // Wrap ETH\n weth.deposit{ value: balance }();\n\n // Mint with WETH\n uint256 mintedOToken = _mint(balance, address(this));\n\n // Wrap OToken into wOToken\n uint256 mintedWOToken = wOToken.deposit(mintedOToken, msg.sender);\n\n require(mintedWOToken >= minReceived, \"Zapper: not enough minted\");\n\n // slither-disable-end reentrancy-balance\n return mintedWOToken;\n }\n\n /**\n * @dev Deposit WETH and receive OToken in return\n * @param wethAmount Amount of WETH to deposit\n * @param minReceived min amount of wsuperOETHb to receive\n * @return Amount of wsuperOETHb sent to user\n */\n function depositWETHForWrappedTokens(\n uint256 wethAmount,\n uint256 minReceived\n ) external returns (uint256) {\n // slither-disable-start reentrancy-balance\n // slither-disable-next-line unchecked-transfer unused-return\n weth.transferFrom(msg.sender, address(this), wethAmount);\n\n emit Zap(msg.sender, address(weth), wethAmount);\n\n // Mint with WETH\n uint256 mintedOToken = _mint(wethAmount, address(this));\n\n // Wrap OToken into wOToken\n uint256 mintedWOToken = wOToken.deposit(mintedOToken, msg.sender);\n\n require(mintedWOToken >= minReceived, \"Zapper: not enough minted\");\n\n // slither-disable-end reentrancy-balance\n return mintedWOToken;\n }\n\n /**\n * @dev Internal function to mint superOETHb with WETH\n * @param minOToken Minimum amount of OToken to for user to receive\n * @param recipient Address that receives the tokens\n * @return Amount of OToken sent to user\n */\n function _mint(uint256 minOToken, address recipient)\n internal\n returns (uint256)\n {\n uint256 toMint = weth.balanceOf(address(this));\n vault.mint(toMint);\n uint256 mintedAmount = oToken.balanceOf(address(this));\n require(mintedAmount >= minOToken, \"Zapper: not enough minted\");\n\n if (recipient != address(this)) {\n require(oToken.transfer(recipient, mintedAmount));\n }\n\n return mintedAmount;\n }\n}\n" + }, + "contracts/zapper/OETHBaseZapper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractOTokenZapper } from \"./AbstractOTokenZapper.sol\";\n\ncontract OETHBaseZapper is AbstractOTokenZapper {\n constructor(\n address _oethb,\n address _woethb,\n address _vault\n )\n AbstractOTokenZapper(\n _oethb,\n _woethb,\n _vault,\n 0x4200000000000000000000000000000000000006\n )\n {}\n}\n" + }, + "contracts/zapper/OETHZapper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractOTokenZapper } from \"./AbstractOTokenZapper.sol\";\n\ncontract OETHZapper is AbstractOTokenZapper {\n constructor(\n address _oeth,\n address _woeth,\n address _vault,\n address _weth\n ) AbstractOTokenZapper(_oeth, _woeth, _vault, _weth) {}\n}\n" + }, + "contracts/zapper/OSonicZapper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IWrappedSonic } from \"../interfaces/sonic/IWrappedSonic.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\n\n/**\n * @title Zapper for Origin Sonic (OS) tokens\n * @author Origin Protocol Inc\n */\ncontract OSonicZapper {\n IERC20 public immutable OS;\n IERC4626 public immutable wOS;\n IVault public immutable vault;\n\n IWrappedSonic public constant wS =\n IWrappedSonic(0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38);\n address private constant ETH_MARKER =\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n event Zap(address indexed minter, address indexed asset, uint256 amount);\n\n constructor(\n address _OS,\n address _wOS,\n address _vault\n ) {\n OS = IERC20(_OS);\n wOS = IERC4626(_wOS);\n vault = IVault(_vault);\n\n wS.approve(address(_vault), type(uint256).max);\n IERC20(_OS).approve(_wOS, type(uint256).max);\n }\n\n /**\n * @dev Deposit native S currency and receive Origin Sonic (OS) tokens in return.\n * Will verify that the user is sent 1:1 for S.\n */\n receive() external payable {\n deposit();\n }\n\n /**\n * @dev Deposit native S currency and receive Origin Sonic (OS) tokens in return.\n * Will verify that the user is sent 1:1 for S.\n * @return Amount of Origin Sonic (OS) tokens sent to user\n */\n function deposit() public payable returns (uint256) {\n uint256 balance = address(this).balance;\n\n emit Zap(msg.sender, ETH_MARKER, balance);\n\n // Wrap native S\n wS.deposit{ value: balance }();\n\n // Mint Origin Sonic (OS) with Wrapped Sonic (wS)\n return _mint(balance, msg.sender);\n }\n\n /**\n * @dev Deposit S and receive Wrapped Origin Sonic (wOS) in return\n * @param minReceived min amount of Wrapped Origin Sonic (wOS) to receive\n * @return Amount of Wrapped Origin Sonic (wOS) tokens sent to user\n */\n function depositSForWrappedTokens(uint256 minReceived)\n external\n payable\n returns (uint256)\n {\n // slither-disable-start reentrancy-balance\n uint256 balance = address(this).balance;\n\n emit Zap(msg.sender, ETH_MARKER, balance);\n\n // Wrap S\n wS.deposit{ value: balance }();\n\n // Mint with Wrapped Sonic\n uint256 mintOS = _mint(balance, address(this));\n\n // Wrap Origin Sonic (OS) into Wrapped Origin Sonic (wOS)\n uint256 mintedWOS = wOS.deposit(mintOS, msg.sender);\n\n require(mintedWOS >= minReceived, \"Zapper: not enough minted\");\n\n // slither-disable-end reentrancy-balance\n return mintedWOS;\n }\n\n /**\n * @dev Deposit Wrapped Sonic (wS) tokens and receive Wrapped Origin Sonic (wOS) tokens in return\n * @param wSAmount Amount of Wrapped Sonic (wS) to deposit\n * @param minReceived min amount of Wrapped Origin Sonic (wOS) token to receive\n * @return Amount of Wrapped Origin Sonic (wOS) tokens sent to user\n */\n function depositWSForWrappedTokens(uint256 wSAmount, uint256 minReceived)\n external\n returns (uint256)\n {\n // slither-disable-start reentrancy-balance\n // slither-disable-next-line unchecked-transfer unused-return\n wS.transferFrom(msg.sender, address(this), wSAmount);\n\n emit Zap(msg.sender, address(wS), wSAmount);\n\n // Mint with Wrapped Sonic (wS)\n uint256 mintedOS = _mint(wSAmount, address(this));\n\n // Wrap Origin Sonic (OS) tokens into Wrapped Origin Sonic (wOS) tokens\n uint256 mintedWOS = wOS.deposit(mintedOS, msg.sender);\n\n require(mintedWOS >= minReceived, \"Zapper: not enough minted\");\n\n // slither-disable-end reentrancy-balance\n return mintedWOS;\n }\n\n /**\n * @dev Internal function to mint Origin Sonic (OS) with Wrapped S (wS)\n * @param minOS Minimum amount of Origin Sonic (OS) tokens the user can receive\n * @param recipient Address that receives the tokens\n * @return Amount of Origin Sonic (OS) tokens sent to the recipient\n */\n function _mint(uint256 minOS, address recipient)\n internal\n returns (uint256)\n {\n uint256 toMint = wS.balanceOf(address(this));\n vault.mint(toMint);\n uint256 mintedAmount = OS.balanceOf(address(this));\n require(mintedAmount >= minOS, \"Zapper: not enough minted\");\n\n if (recipient != address(this)) {\n require(OS.transfer(recipient, mintedAmount));\n }\n\n return mintedAmount;\n }\n}\n" + }, + "hardhat/console.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.22 <0.9.0;\n\nlibrary console {\n address constant CONSOLE_ADDRESS =\n 0x000000000000000000636F6e736F6c652e6c6f67;\n\n function _sendLogPayloadImplementation(bytes memory payload) internal view {\n address consoleAddress = CONSOLE_ADDRESS;\n /// @solidity memory-safe-assembly\n assembly {\n pop(\n staticcall(\n gas(),\n consoleAddress,\n add(payload, 32),\n mload(payload),\n 0,\n 0\n )\n )\n }\n }\n\n function _castToPure(\n function(bytes memory) internal view fnIn\n ) internal pure returns (function(bytes memory) pure fnOut) {\n assembly {\n fnOut := fnIn\n }\n }\n\n function _sendLogPayload(bytes memory payload) internal pure {\n _castToPure(_sendLogPayloadImplementation)(payload);\n }\n\n function log() internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log()\"));\n }\n\n function logInt(int256 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(int256)\", p0));\n }\n\n function logUint(uint256 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256)\", p0));\n }\n\n function logString(string memory p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n }\n\n function logBool(bool p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n }\n\n function logAddress(address p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n }\n\n function logBytes(bytes memory p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes)\", p0));\n }\n\n function logBytes1(bytes1 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes1)\", p0));\n }\n\n function logBytes2(bytes2 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes2)\", p0));\n }\n\n function logBytes3(bytes3 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes3)\", p0));\n }\n\n function logBytes4(bytes4 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes4)\", p0));\n }\n\n function logBytes5(bytes5 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes5)\", p0));\n }\n\n function logBytes6(bytes6 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes6)\", p0));\n }\n\n function logBytes7(bytes7 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes7)\", p0));\n }\n\n function logBytes8(bytes8 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes8)\", p0));\n }\n\n function logBytes9(bytes9 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes9)\", p0));\n }\n\n function logBytes10(bytes10 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes10)\", p0));\n }\n\n function logBytes11(bytes11 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes11)\", p0));\n }\n\n function logBytes12(bytes12 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes12)\", p0));\n }\n\n function logBytes13(bytes13 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes13)\", p0));\n }\n\n function logBytes14(bytes14 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes14)\", p0));\n }\n\n function logBytes15(bytes15 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes15)\", p0));\n }\n\n function logBytes16(bytes16 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes16)\", p0));\n }\n\n function logBytes17(bytes17 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes17)\", p0));\n }\n\n function logBytes18(bytes18 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes18)\", p0));\n }\n\n function logBytes19(bytes19 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes19)\", p0));\n }\n\n function logBytes20(bytes20 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes20)\", p0));\n }\n\n function logBytes21(bytes21 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes21)\", p0));\n }\n\n function logBytes22(bytes22 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes22)\", p0));\n }\n\n function logBytes23(bytes23 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes23)\", p0));\n }\n\n function logBytes24(bytes24 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes24)\", p0));\n }\n\n function logBytes25(bytes25 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes25)\", p0));\n }\n\n function logBytes26(bytes26 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes26)\", p0));\n }\n\n function logBytes27(bytes27 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes27)\", p0));\n }\n\n function logBytes28(bytes28 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes28)\", p0));\n }\n\n function logBytes29(bytes29 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes29)\", p0));\n }\n\n function logBytes30(bytes30 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes30)\", p0));\n }\n\n function logBytes31(bytes31 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes31)\", p0));\n }\n\n function logBytes32(bytes32 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes32)\", p0));\n }\n\n function log(uint256 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256)\", p0));\n }\n\n function log(string memory p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n }\n\n function log(bool p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n }\n\n function log(address p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n }\n\n function log(uint256 p0, uint256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256)\", p0, p1));\n }\n\n function log(uint256 p0, string memory p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string)\", p0, p1));\n }\n\n function log(uint256 p0, bool p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool)\", p0, p1));\n }\n\n function log(uint256 p0, address p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address)\", p0, p1));\n }\n\n function log(string memory p0, uint256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256)\", p0, p1));\n }\n\n function log(string memory p0, string memory p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string)\", p0, p1));\n }\n\n function log(string memory p0, bool p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool)\", p0, p1));\n }\n\n function log(string memory p0, address p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address)\", p0, p1));\n }\n\n function log(bool p0, uint256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256)\", p0, p1));\n }\n\n function log(bool p0, string memory p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string)\", p0, p1));\n }\n\n function log(bool p0, bool p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool)\", p0, p1));\n }\n\n function log(bool p0, address p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address)\", p0, p1));\n }\n\n function log(address p0, uint256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256)\", p0, p1));\n }\n\n function log(address p0, string memory p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string)\", p0, p1));\n }\n\n function log(address p0, bool p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool)\", p0, p1));\n }\n\n function log(address p0, address p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address)\", p0, p1));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256)\", p0, p1, p2));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string)\", p0, p1, p2));\n }\n\n function log(uint256 p0, uint256 p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool)\", p0, p1, p2));\n }\n\n function log(uint256 p0, uint256 p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address)\", p0, p1, p2));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256)\", p0, p1, p2));\n }\n\n function log(uint256 p0, string memory p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string)\", p0, p1, p2));\n }\n\n function log(uint256 p0, string memory p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool)\", p0, p1, p2));\n }\n\n function log(uint256 p0, string memory p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address)\", p0, p1, p2));\n }\n\n function log(uint256 p0, bool p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256)\", p0, p1, p2));\n }\n\n function log(uint256 p0, bool p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string)\", p0, p1, p2));\n }\n\n function log(uint256 p0, bool p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool)\", p0, p1, p2));\n }\n\n function log(uint256 p0, bool p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address)\", p0, p1, p2));\n }\n\n function log(uint256 p0, address p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256)\", p0, p1, p2));\n }\n\n function log(uint256 p0, address p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string)\", p0, p1, p2));\n }\n\n function log(uint256 p0, address p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool)\", p0, p1, p2));\n }\n\n function log(uint256 p0, address p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address)\", p0, p1, p2));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256)\", p0, p1, p2));\n }\n\n function log(string memory p0, uint256 p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string)\", p0, p1, p2));\n }\n\n function log(string memory p0, uint256 p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool)\", p0, p1, p2));\n }\n\n function log(string memory p0, uint256 p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address)\", p0, p1, p2));\n }\n\n function log(string memory p0, string memory p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256)\", p0, p1, p2));\n }\n\n function log(string memory p0, string memory p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string)\", p0, p1, p2));\n }\n\n function log(string memory p0, string memory p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool)\", p0, p1, p2));\n }\n\n function log(string memory p0, string memory p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address)\", p0, p1, p2));\n }\n\n function log(string memory p0, bool p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256)\", p0, p1, p2));\n }\n\n function log(string memory p0, bool p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string)\", p0, p1, p2));\n }\n\n function log(string memory p0, bool p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool)\", p0, p1, p2));\n }\n\n function log(string memory p0, bool p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address)\", p0, p1, p2));\n }\n\n function log(string memory p0, address p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256)\", p0, p1, p2));\n }\n\n function log(string memory p0, address p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string)\", p0, p1, p2));\n }\n\n function log(string memory p0, address p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool)\", p0, p1, p2));\n }\n\n function log(string memory p0, address p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address)\", p0, p1, p2));\n }\n\n function log(bool p0, uint256 p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256)\", p0, p1, p2));\n }\n\n function log(bool p0, uint256 p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string)\", p0, p1, p2));\n }\n\n function log(bool p0, uint256 p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool)\", p0, p1, p2));\n }\n\n function log(bool p0, uint256 p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address)\", p0, p1, p2));\n }\n\n function log(bool p0, string memory p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256)\", p0, p1, p2));\n }\n\n function log(bool p0, string memory p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string)\", p0, p1, p2));\n }\n\n function log(bool p0, string memory p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool)\", p0, p1, p2));\n }\n\n function log(bool p0, string memory p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address)\", p0, p1, p2));\n }\n\n function log(bool p0, bool p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256)\", p0, p1, p2));\n }\n\n function log(bool p0, bool p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string)\", p0, p1, p2));\n }\n\n function log(bool p0, bool p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool)\", p0, p1, p2));\n }\n\n function log(bool p0, bool p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address)\", p0, p1, p2));\n }\n\n function log(bool p0, address p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256)\", p0, p1, p2));\n }\n\n function log(bool p0, address p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string)\", p0, p1, p2));\n }\n\n function log(bool p0, address p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool)\", p0, p1, p2));\n }\n\n function log(bool p0, address p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address)\", p0, p1, p2));\n }\n\n function log(address p0, uint256 p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256)\", p0, p1, p2));\n }\n\n function log(address p0, uint256 p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string)\", p0, p1, p2));\n }\n\n function log(address p0, uint256 p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool)\", p0, p1, p2));\n }\n\n function log(address p0, uint256 p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address)\", p0, p1, p2));\n }\n\n function log(address p0, string memory p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256)\", p0, p1, p2));\n }\n\n function log(address p0, string memory p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string)\", p0, p1, p2));\n }\n\n function log(address p0, string memory p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool)\", p0, p1, p2));\n }\n\n function log(address p0, string memory p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address)\", p0, p1, p2));\n }\n\n function log(address p0, bool p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256)\", p0, p1, p2));\n }\n\n function log(address p0, bool p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string)\", p0, p1, p2));\n }\n\n function log(address p0, bool p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool)\", p0, p1, p2));\n }\n\n function log(address p0, bool p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address)\", p0, p1, p2));\n }\n\n function log(address p0, address p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256)\", p0, p1, p2));\n }\n\n function log(address p0, address p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string)\", p0, p1, p2));\n }\n\n function log(address p0, address p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool)\", p0, p1, p2));\n }\n\n function log(address p0, address p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address)\", p0, p1, p2));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,address)\", p0, p1, p2, p3));\n }\n}\n" + }, + "lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IERC4626 } from \"../../../../interfaces/IERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n// From Open Zeppelin draft PR commit:\n// fac43034dca85ff539db3fc8aa2a7084b843d454\n// https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171\n\nabstract contract ERC4626 is ERC20, IERC4626 {\n IERC20Metadata private immutable _asset;\n\n constructor(IERC20Metadata __asset) {\n _asset = __asset;\n }\n\n /** @dev See {IERC4262-asset} */\n function asset() public view virtual override returns (address) {\n return address(_asset);\n }\n\n /** @dev See {IERC4262-totalAssets} */\n function totalAssets() public view virtual override returns (uint256) {\n return _asset.balanceOf(address(this));\n }\n\n /**\n * @dev See {IERC4262-convertToShares}\n *\n * Will revert if asserts > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset\n * would represent an infinite amout of shares.\n */\n function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) {\n uint256 supply = totalSupply();\n\n return\n (assets == 0 || supply == 0)\n ? (assets * 10**decimals()) / 10**_asset.decimals()\n : (assets * supply) / totalAssets();\n }\n\n /** @dev See {IERC4262-convertToAssets} */\n function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) {\n uint256 supply = totalSupply();\n\n return (supply == 0) ? (shares * 10**_asset.decimals()) / 10**decimals() : (shares * totalAssets()) / supply;\n }\n\n /** @dev See {IERC4262-maxDeposit} */\n function maxDeposit(address) public view virtual override returns (uint256) {\n return type(uint256).max;\n }\n\n /** @dev See {IERC4262-maxMint} */\n function maxMint(address) public view virtual override returns (uint256) {\n return type(uint256).max;\n }\n\n /** @dev See {IERC4262-maxWithdraw} */\n function maxWithdraw(address owner) public view virtual override returns (uint256) {\n return convertToAssets(balanceOf(owner));\n }\n\n /** @dev See {IERC4262-maxRedeem} */\n function maxRedeem(address owner) public view virtual override returns (uint256) {\n return balanceOf(owner);\n }\n\n /** @dev See {IERC4262-previewDeposit} */\n function previewDeposit(uint256 assets) public view virtual override returns (uint256) {\n return convertToShares(assets);\n }\n\n /** @dev See {IERC4262-previewMint} */\n function previewMint(uint256 shares) public view virtual override returns (uint256) {\n uint256 assets = convertToAssets(shares);\n return assets + (convertToShares(assets) < shares ? 1 : 0);\n }\n\n /** @dev See {IERC4262-previewWithdraw} */\n function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {\n uint256 shares = convertToShares(assets);\n return shares + (convertToAssets(shares) < assets ? 1 : 0);\n }\n\n /** @dev See {IERC4262-previewRedeem} */\n function previewRedeem(uint256 shares) public view virtual override returns (uint256) {\n return convertToAssets(shares);\n }\n\n /** @dev See {IERC4262-deposit} */\n function deposit(uint256 assets, address receiver) public virtual override returns (uint256) {\n require(assets <= maxDeposit(receiver), \"ERC4626: deposit more then max\");\n\n address caller = _msgSender();\n uint256 shares = previewDeposit(assets);\n\n // if _asset is ERC777, transferFrom can call reenter BEFORE the transfer happens through\n // the tokensToSend hook, so we need to transfer before we mint to keep the invariants.\n SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n _mint(receiver, shares);\n\n emit Deposit(caller, receiver, assets, shares);\n\n return shares;\n }\n\n /** @dev See {IERC4262-mint} */\n function mint(uint256 shares, address receiver) public virtual override returns (uint256) {\n require(shares <= maxMint(receiver), \"ERC4626: mint more then max\");\n\n address caller = _msgSender();\n uint256 assets = previewMint(shares);\n\n // if _asset is ERC777, transferFrom can call reenter BEFORE the transfer happens through\n // the tokensToSend hook, so we need to transfer before we mint to keep the invariants.\n SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n _mint(receiver, shares);\n\n emit Deposit(caller, receiver, assets, shares);\n\n return assets;\n }\n\n /** @dev See {IERC4262-withdraw} */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) public virtual override returns (uint256) {\n require(assets <= maxWithdraw(owner), \"ERC4626: withdraw more then max\");\n\n address caller = _msgSender();\n uint256 shares = previewWithdraw(assets);\n\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n\n // if _asset is ERC777, transfer can call reenter AFTER the transfer happens through\n // the tokensReceived hook, so we need to transfer after we burn to keep the invariants.\n _burn(owner, shares);\n SafeERC20.safeTransfer(_asset, receiver, assets);\n\n emit Withdraw(caller, receiver, owner, assets, shares);\n\n return shares;\n }\n\n /** @dev See {IERC4262-redeem} */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) public virtual override returns (uint256) {\n require(shares <= maxRedeem(owner), \"ERC4626: redeem more then max\");\n\n address caller = _msgSender();\n uint256 assets = previewRedeem(shares);\n\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n\n // if _asset is ERC777, transfer can call reenter AFTER the transfer happens through\n // the tokensReceived hook, so we need to transfer after we burn to keep the invariants.\n _burn(owner, shares);\n SafeERC20.safeTransfer(_asset, receiver, assets);\n\n emit Withdraw(caller, receiver, owner, assets, shares);\n\n return assets;\n }\n\n // Included here, since this method was not yet present in\n // the version of Open Zeppelin ERC20 code we use.\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n}" + }, + "lib/openzeppelin/interfaces/IERC4626.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IERC4626 is IERC20, IERC20Metadata {\n event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);\n\n event Withdraw(\n address indexed caller,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) external returns (uint256 assets);\n}" + }, + "solidity-bytes-utils/contracts/BytesLib.sol": { + "content": "// SPDX-License-Identifier: Unlicense\n/*\n * @title Solidity Bytes Arrays Utils\n * @author Gonçalo Sá \n *\n * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.\n * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.\n */\npragma solidity >=0.8.0 <0.9.0;\n\n\nlibrary BytesLib {\n function concat(\n bytes memory _preBytes,\n bytes memory _postBytes\n )\n internal\n pure\n returns (bytes memory)\n {\n bytes memory tempBytes;\n\n assembly {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // Store the length of the first bytes array at the beginning of\n // the memory for tempBytes.\n let length := mload(_preBytes)\n mstore(tempBytes, length)\n\n // Maintain a memory counter for the current write location in the\n // temp bytes array by adding the 32 bytes for the array length to\n // the starting location.\n let mc := add(tempBytes, 0x20)\n // Stop copying when the memory counter reaches the length of the\n // first bytes array.\n let end := add(mc, length)\n\n for {\n // Initialize a copy counter to the start of the _preBytes data,\n // 32 bytes into its memory.\n let cc := add(_preBytes, 0x20)\n } lt(mc, end) {\n // Increase both counters by 32 bytes each iteration.\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // Write the _preBytes data into the tempBytes memory 32 bytes\n // at a time.\n mstore(mc, mload(cc))\n }\n\n // Add the length of _postBytes to the current length of tempBytes\n // and store it as the new length in the first 32 bytes of the\n // tempBytes memory.\n length := mload(_postBytes)\n mstore(tempBytes, add(length, mload(tempBytes)))\n\n // Move the memory counter back from a multiple of 0x20 to the\n // actual end of the _preBytes data.\n mc := end\n // Stop copying when the memory counter reaches the new combined\n // length of the arrays.\n end := add(mc, length)\n\n for {\n let cc := add(_postBytes, 0x20)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n mstore(mc, mload(cc))\n }\n\n // Update the free-memory pointer by padding our last write location\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\n // next 32 byte block, then round down to the nearest multiple of\n // 32. If the sum of the length of the two arrays is zero then add\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\n mstore(0x40, and(\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\n not(31) // Round down to the nearest 32 bytes.\n ))\n }\n\n return tempBytes;\n }\n\n function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {\n assembly {\n // Read the first 32 bytes of _preBytes storage, which is the length\n // of the array. (We don't need to use the offset into the slot\n // because arrays use the entire slot.)\n let fslot := sload(_preBytes.slot)\n // Arrays of 31 bytes or less have an even value in their slot,\n // while longer arrays have an odd value. The actual length is\n // the slot divided by two for odd values, and the lowest order\n // byte divided by two for even values.\n // If the slot is even, bitwise and the slot with 255 and divide by\n // two to get the length. If the slot is odd, bitwise and the slot\n // with -1 and divide by two.\n let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n let mlength := mload(_postBytes)\n let newlength := add(slength, mlength)\n // slength can contain both the length and contents of the array\n // if length < 32 bytes so let's prepare for that\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n switch add(lt(slength, 32), lt(newlength, 32))\n case 2 {\n // Since the new array still fits in the slot, we just need to\n // update the contents of the slot.\n // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\n sstore(\n _preBytes.slot,\n // all the modifications to the slot are inside this\n // next block\n add(\n // we can just add to the slot contents because the\n // bytes we want to change are the LSBs\n fslot,\n add(\n mul(\n div(\n // load the bytes from memory\n mload(add(_postBytes, 0x20)),\n // zero all bytes to the right\n exp(0x100, sub(32, mlength))\n ),\n // and now shift left the number of bytes to\n // leave space for the length in the slot\n exp(0x100, sub(32, newlength))\n ),\n // increase length by the double of the memory\n // bytes length\n mul(mlength, 2)\n )\n )\n )\n }\n case 1 {\n // The stored value fits in the slot, but the combined value\n // will exceed it.\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n // save new length\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n // The contents of the _postBytes array start 32 bytes into\n // the structure. Our first read should obtain the `submod`\n // bytes that can fit into the unused space in the last word\n // of the stored array. To get this, we read 32 bytes starting\n // from `submod`, so the data we read overlaps with the array\n // contents by `submod` bytes. Masking the lowest-order\n // `submod` bytes allows us to add that value directly to the\n // stored value.\n\n let submod := sub(32, slength)\n let mc := add(_postBytes, submod)\n let end := add(_postBytes, mlength)\n let mask := sub(exp(0x100, submod), 1)\n\n sstore(\n sc,\n add(\n and(\n fslot,\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00\n ),\n and(mload(mc), mask)\n )\n )\n\n for {\n mc := add(mc, 0x20)\n sc := add(sc, 1)\n } lt(mc, end) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n sstore(sc, mload(mc))\n }\n\n mask := exp(0x100, sub(mc, end))\n\n sstore(sc, mul(div(mload(mc), mask), mask))\n }\n default {\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n // Start copying to the last used word of the stored array.\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n // save new length\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n // Copy over the first `submod` bytes of the new data as in\n // case 1 above.\n let slengthmod := mod(slength, 32)\n let mlengthmod := mod(mlength, 32)\n let submod := sub(32, slengthmod)\n let mc := add(_postBytes, submod)\n let end := add(_postBytes, mlength)\n let mask := sub(exp(0x100, submod), 1)\n\n sstore(sc, add(sload(sc), and(mload(mc), mask)))\n\n for {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } lt(mc, end) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n sstore(sc, mload(mc))\n }\n\n mask := exp(0x100, sub(mc, end))\n\n sstore(sc, mul(div(mload(mc), mask), mask))\n }\n }\n }\n\n function slice(\n bytes memory _bytes,\n uint256 _start,\n uint256 _length\n )\n internal\n pure\n returns (bytes memory)\n {\n // We're using the unchecked block below because otherwise execution ends \n // with the native overflow error code.\n unchecked {\n require(_length + 31 >= _length, \"slice_overflow\");\n }\n require(_bytes.length >= _start + _length, \"slice_outOfBounds\");\n\n bytes memory tempBytes;\n\n assembly {\n switch iszero(_length)\n case 0 {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // The first word of the slice result is potentially a partial\n // word read from the original array. To read it, we calculate\n // the length of that partial word and start copying that many\n // bytes into the array. The first word we copy will start with\n // data we don't care about, but the last `lengthmod` bytes will\n // land at the beginning of the contents of the new array. When\n // we're done copying, we overwrite the full first word with\n // the actual length of the slice.\n let lengthmod := and(_length, 31)\n\n // The multiplication in the next line is necessary\n // because when slicing multiples of 32 bytes (lengthmod == 0)\n // the following copy loop was copying the origin's length\n // and then ending prematurely not copying everything it should.\n let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n let end := add(mc, _length)\n\n for {\n // The multiplication in the next line has the same exact purpose\n // as the one above.\n let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n mstore(mc, mload(cc))\n }\n\n mstore(tempBytes, _length)\n\n //update free-memory pointer\n //allocating the array padded to 32 bytes like the compiler does now\n mstore(0x40, and(add(mc, 31), not(31)))\n }\n //if we want a zero-length slice let's just return a zero-length array\n default {\n tempBytes := mload(0x40)\n //zero out the 32 bytes slice we are about to return\n //we need to do it because Solidity does not garbage collect\n mstore(tempBytes, 0)\n\n mstore(0x40, add(tempBytes, 0x20))\n }\n }\n\n return tempBytes;\n }\n\n function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {\n require(_bytes.length >= _start + 20, \"toAddress_outOfBounds\");\n address tempAddress;\n\n assembly {\n tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)\n }\n\n return tempAddress;\n }\n\n function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {\n require(_bytes.length >= _start + 1 , \"toUint8_outOfBounds\");\n uint8 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x1), _start))\n }\n\n return tempUint;\n }\n\n function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {\n require(_bytes.length >= _start + 2, \"toUint16_outOfBounds\");\n uint16 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x2), _start))\n }\n\n return tempUint;\n }\n\n function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {\n require(_bytes.length >= _start + 4, \"toUint32_outOfBounds\");\n uint32 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x4), _start))\n }\n\n return tempUint;\n }\n\n function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {\n require(_bytes.length >= _start + 8, \"toUint64_outOfBounds\");\n uint64 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x8), _start))\n }\n\n return tempUint;\n }\n\n function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {\n require(_bytes.length >= _start + 12, \"toUint96_outOfBounds\");\n uint96 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0xc), _start))\n }\n\n return tempUint;\n }\n\n function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {\n require(_bytes.length >= _start + 16, \"toUint128_outOfBounds\");\n uint128 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x10), _start))\n }\n\n return tempUint;\n }\n\n function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {\n require(_bytes.length >= _start + 32, \"toUint256_outOfBounds\");\n uint256 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempUint;\n }\n\n function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {\n require(_bytes.length >= _start + 32, \"toBytes32_outOfBounds\");\n bytes32 tempBytes32;\n\n assembly {\n tempBytes32 := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempBytes32;\n }\n\n function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {\n bool success = true;\n\n assembly {\n let length := mload(_preBytes)\n\n // if lengths don't match the arrays are not equal\n switch eq(length, mload(_postBytes))\n case 1 {\n // cb is a circuit breaker in the for loop since there's\n // no said feature for inline assembly loops\n // cb = 1 - don't breaker\n // cb = 0 - break\n let cb := 1\n\n let mc := add(_preBytes, 0x20)\n let end := add(mc, length)\n\n for {\n let cc := add(_postBytes, 0x20)\n // the next line is the loop condition:\n // while(uint256(mc < end) + cb == 2)\n } eq(add(lt(mc, end), cb), 2) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // if any of these checks fails then arrays are not equal\n if iszero(eq(mload(mc), mload(cc))) {\n // unsuccess:\n success := 0\n cb := 0\n }\n }\n }\n default {\n // unsuccess:\n success := 0\n }\n }\n\n return success;\n }\n\n function equalStorage(\n bytes storage _preBytes,\n bytes memory _postBytes\n )\n internal\n view\n returns (bool)\n {\n bool success = true;\n\n assembly {\n // we know _preBytes_offset is 0\n let fslot := sload(_preBytes.slot)\n // Decode the length of the stored array like in concatStorage().\n let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n let mlength := mload(_postBytes)\n\n // if lengths don't match the arrays are not equal\n switch eq(slength, mlength)\n case 1 {\n // slength can contain both the length and contents of the array\n // if length < 32 bytes so let's prepare for that\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n if iszero(iszero(slength)) {\n switch lt(slength, 32)\n case 1 {\n // blank the last byte which is the length\n fslot := mul(div(fslot, 0x100), 0x100)\n\n if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\n // unsuccess:\n success := 0\n }\n }\n default {\n // cb is a circuit breaker in the for loop since there's\n // no said feature for inline assembly loops\n // cb = 1 - don't breaker\n // cb = 0 - break\n let cb := 1\n\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n let sc := keccak256(0x0, 0x20)\n\n let mc := add(_postBytes, 0x20)\n let end := add(mc, mlength)\n\n // the next line is the loop condition:\n // while(uint256(mc < end) + cb == 2)\n for {} eq(add(lt(mc, end), cb), 2) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n if iszero(eq(sload(sc), mload(mc))) {\n // unsuccess:\n success := 0\n cb := 0\n }\n }\n }\n }\n }\n default {\n // unsuccess:\n success := 0\n }\n }\n\n return success;\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "evmVersion": "paris", + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/contracts/deployments/sonic/.migrations.json b/contracts/deployments/sonic/.migrations.json index 45a53ef9ff..565b38b739 100644 --- a/contracts/deployments/sonic/.migrations.json +++ b/contracts/deployments/sonic/.migrations.json @@ -1,3 +1,4 @@ { - "028_permissioned_rebase_module": 1778096823 + "028_permissioned_rebase_module": 1778096823, + "029_vault_permissioned_rebase": 1778496677 } \ No newline at end of file diff --git a/contracts/deployments/sonic/OSVault.json b/contracts/deployments/sonic/OSVault.json new file mode 100644 index 0000000000..b260d79084 --- /dev/null +++ b/contracts/deployments/sonic/OSVault.json @@ -0,0 +1,2327 @@ +{ + "address": "0xF66886e242e20cAb2496AF1d411eBcFb73440270", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_wS", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_threshold", + "type": "uint256" + } + ], + "name": "AllocateThresholdUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_strategy", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "AssetAllocated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "CapitalPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "CapitalUnpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_strategy", + "type": "address" + } + ], + "name": "DefaultStrategyUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dripDuration", + "type": "uint256" + } + ], + "name": "DripDurationChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousGovernor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newGovernor", + "type": "address" + } + ], + "name": "GovernorshipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "maxSupplyDiff", + "type": "uint256" + } + ], + "name": "MaxSupplyDiffChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_addr", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_value", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newOperator", + "type": "address" + } + ], + "name": "OperatorUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousGovernor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newGovernor", + "type": "address" + } + ], + "name": "PendingGovernorshipTransfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "RebasePaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "rebaseRatePerSecond", + "type": "uint256" + } + ], + "name": "RebasePerSecondMaxChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "RebaseUnpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_addr", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_value", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "name": "StrategistUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "strategy", + "type": "address" + } + ], + "name": "StrategyAddedToMintWhitelist", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_addr", + "type": "address" + } + ], + "name": "StrategyApproved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_addr", + "type": "address" + } + ], + "name": "StrategyRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "strategy", + "type": "address" + } + ], + "name": "StrategyRemovedFromMintWhitelist", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "name": "TrusteeAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_basis", + "type": "uint256" + } + ], + "name": "TrusteeFeeBpsChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_vaultBuffer", + "type": "uint256" + } + ], + "name": "VaultBufferUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_newDelay", + "type": "uint256" + } + ], + "name": "WithdrawalClaimDelayUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_claimable", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newClaimable", + "type": "uint256" + } + ], + "name": "WithdrawalClaimable", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_withdrawer", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "WithdrawalClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_withdrawer", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_queued", + "type": "uint256" + } + ], + "name": "WithdrawalRequested", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_yield", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_fee", + "type": "uint256" + } + ], + "name": "YieldDistribution", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "strategyAddr", + "type": "address" + } + ], + "name": "addStrategyToMintWhitelist", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "addWithdrawalQueueLiquidity", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "allocate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_addr", + "type": "address" + } + ], + "name": "approveStrategy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "asset", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "autoAllocateThreshold", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "burnForStrategy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "capitalPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_asset", + "type": "address" + } + ], + "name": "checkBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_requestId", + "type": "uint256" + } + ], + "name": "claimWithdrawal", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_requestIds", + "type": "uint256[]" + } + ], + "name": "claimWithdrawals", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "totalAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "defaultStrategy", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_strategyToAddress", + "type": "address" + }, + { + "internalType": "address[]", + "name": "_assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_amounts", + "type": "uint256[]" + } + ], + "name": "depositToStrategy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "dripDuration", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAllAssets", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAllStrategies", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAssetCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getStrategyCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "governor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_oToken", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "isGovernor", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isMintWhitelistedStrategy", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_asset", + "type": "address" + } + ], + "name": "isSupportedAsset", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastRebase", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxSupplyDiff", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "mintForStrategy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "oToken", + "outputs": [ + { + "internalType": "contract OUSD", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "oUSD", + "outputs": [ + { + "internalType": "contract OUSD", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "operatorAddr", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pauseCapital", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "pauseRebase", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "previewYield", + "outputs": [ + { + "internalType": "uint256", + "name": "yield", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rebase", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "rebasePaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rebasePerSecondMax", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rebasePerSecondTarget", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_addr", + "type": "address" + } + ], + "name": "removeStrategy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "strategyAddr", + "type": "address" + } + ], + "name": "removeStrategyFromMintWhitelist", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "requestWithdrawal", + "outputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "queued", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_threshold", + "type": "uint256" + } + ], + "name": "setAutoAllocateThreshold", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_strategy", + "type": "address" + } + ], + "name": "setDefaultStrategy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dripDuration", + "type": "uint256" + } + ], + "name": "setDripDuration", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxSupplyDiff", + "type": "uint256" + } + ], + "name": "setMaxSupplyDiff", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_operator", + "type": "address" + } + ], + "name": "setOperatorAddr", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "apr", + "type": "uint256" + } + ], + "name": "setRebaseRateMax", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "name": "setStrategistAddr", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "name": "setTrusteeAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_basis", + "type": "uint256" + } + ], + "name": "setTrusteeFeeBps", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_vaultBuffer", + "type": "uint256" + } + ], + "name": "setVaultBuffer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_delay", + "type": "uint256" + } + ], + "name": "setWithdrawalClaimDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "strategies", + "outputs": [ + { + "internalType": "bool", + "name": "isSupported", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "_deprecated", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "strategistAddr", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalValue", + "outputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newGovernor", + "type": "address" + } + ], + "name": "transferGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "transferToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "trusteeAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "trusteeFeeBps", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "unpauseCapital", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpauseRebase", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "vaultBuffer", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawAllFromStrategies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_strategyAddr", + "type": "address" + } + ], + "name": "withdrawAllFromStrategy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_strategyFromAddress", + "type": "address" + }, + { + "internalType": "address[]", + "name": "_assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_amounts", + "type": "uint256[]" + } + ], + "name": "withdrawFromStrategy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawalClaimDelay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawalQueueMetadata", + "outputs": [ + { + "internalType": "uint128", + "name": "queued", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "claimable", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "claimed", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "nextWithdrawalIndex", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "withdrawalRequests", + "outputs": [ + { + "internalType": "address", + "name": "withdrawer", + "type": "address" + }, + { + "internalType": "bool", + "name": "claimed", + "type": "bool" + }, + { + "internalType": "uint40", + "name": "timestamp", + "type": "uint40" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "queued", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x085fd7086883b97aeb4f8e4297527e79bcaf6b2ed00f602c8036422df45d83a2", + "receipt": { + "to": null, + "from": "0x58890A9cB27586E83Cb51d2d26bbE18a1a647245", + "contractAddress": "0xF66886e242e20cAb2496AF1d411eBcFb73440270", + "transactionIndex": 2, + "gasUsed": "4585472", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x236d1c967024b0daae0aa074b6876d8173263d461ba75d621202970c94c71b26", + "transactionHash": "0x085fd7086883b97aeb4f8e4297527e79bcaf6b2ed00f602c8036422df45d83a2", + "logs": [], + "blockNumber": 70201738, + "cumulativeGasUsed": "4627472", + "status": 1, + "byzantium": true + }, + "args": [ + "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38" + ], + "numDeployments": 1, + "solcInputHash": "f4384e86fd2a870879603d18d53c5b16", + "metadata": "{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_wS\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"AllocateThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"AssetAllocated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"DefaultStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dripDuration\",\"type\":\"uint256\"}],\"name\":\"DripDurationChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"MaxSupplyDiffChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newOperator\",\"type\":\"address\"}],\"name\":\"OperatorUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebasePaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rebaseRatePerSecond\",\"type\":\"uint256\"}],\"name\":\"RebasePerSecondMaxChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebaseUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"StrategistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyAddedToMintWhitelist\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"strategy\",\"type\":\"address\"}],\"name\":\"StrategyRemovedFromMintWhitelist\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"TrusteeAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"TrusteeFeeBpsChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"VaultBufferUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newDelay\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_claimable\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newClaimable\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimable\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_queued\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_yield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"YieldDistribution\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddr\",\"type\":\"address\"}],\"name\":\"addStrategyToMintWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"addWithdrawalQueueLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"allocate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"approveStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"asset\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"autoAllocateThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"burnForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capitalPaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"claimWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_requestIds\",\"type\":\"uint256[]\"}],\"name\":\"claimWithdrawals\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"totalAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultStrategy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyToAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"depositToStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dripDuration\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAssets\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllStrategies\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAssetCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStrategyCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_oToken\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isMintWhitelistedStrategy\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"isSupportedAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRebase\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxSupplyDiff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mintForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oToken\",\"outputs\":[{\"internalType\":\"contract OUSD\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oUSD\",\"outputs\":[{\"internalType\":\"contract OUSD\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatorAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previewYield\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"yield\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePerSecondMax\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePerSecondTarget\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"removeStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddr\",\"type\":\"address\"}],\"name\":\"removeStrategyFromMintWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"requestWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"queued\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setAutoAllocateThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"setDefaultStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dripDuration\",\"type\":\"uint256\"}],\"name\":\"setDripDuration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"setMaxSupplyDiff\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_operator\",\"type\":\"address\"}],\"name\":\"setOperatorAddr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"apr\",\"type\":\"uint256\"}],\"name\":\"setRebaseRateMax\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setStrategistAddr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setTrusteeAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"setTrusteeFeeBps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"setVaultBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_delay\",\"type\":\"uint256\"}],\"name\":\"setWithdrawalClaimDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"strategies\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isSupported\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"_deprecated\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategistAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"transferToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAllFromStrategies\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"}],\"name\":\"withdrawAllFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyFromAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"withdrawFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalClaimDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalQueueMetadata\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimable\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimed\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"nextWithdrawalIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"withdrawalRequests\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"claimed\",\"type\":\"bool\"},{\"internalType\":\"uint40\",\"name\":\"timestamp\",\"type\":\"uint40\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"addStrategyToMintWhitelist(address)\":{\"params\":{\"strategyAddr\":\"Strategy address\"}},\"addWithdrawalQueueLiquidity()\":{\"details\":\"is called from the Native Staking strategy when validator withdrawals are processed. It also called before any WETH is allocated to a strategy.\"},\"approveStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to add\"}},\"burnForStrategy(uint256)\":{\"details\":\"Notice: can't use `nonReentrant` modifier since the `redeem` function could require withdrawal on an AMO strategy and that one can call `burnForStrategy` while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\",\"params\":{\"_amount\":\"Amount of OToken to burn\"}},\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of asset\"},\"returns\":{\"_0\":\"uint256 Balance of asset in decimals of asset\"}},\"claimWithdrawal(uint256)\":{\"params\":{\"_requestId\":\"Unique ID for the withdrawal request\"},\"returns\":{\"amount\":\"Amount of asset transferred to the withdrawer\"}},\"claimWithdrawals(uint256[])\":{\"params\":{\"_requestIds\":\"Unique ID of each withdrawal request\"},\"returns\":{\"amounts\":\"Amount of asset received for each request\",\"totalAmount\":\"Total amount of asset transferred to the withdrawer\"}},\"depositToStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to deposit.\",\"_assets\":\"Array of asset address that will be deposited into the strategy.\",\"_strategyToAddress\":\"Address of the Strategy to deposit asset into.\"}},\"isSupportedAsset(address)\":{\"params\":{\"_asset\":\"address of the asset\"},\"returns\":{\"_0\":\"true if supported\"}},\"mint(address,uint256,uint256)\":{\"details\":\"Deprecated: use `mint(uint256 _amount)` instead.Deprecated: param _asset Address of the asset being depositedDeprecated: param _minimumOusdAmount Minimum OTokens to mint\",\"params\":{\"_amount\":\"Amount of the asset being deposited\"}},\"mint(uint256)\":{\"params\":{\"_amount\":\"Amount of the asset being deposited\"}},\"mintForStrategy(uint256)\":{\"params\":{\"_amount\":\"Amount of OToken to mint Notice: can't use `nonReentrant` modifier since the `mint` function can call `allocate`, and that can trigger an AMO strategy to call this function while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\"}},\"previewYield()\":{\"returns\":{\"yield\":\"amount of expected yield\"}},\"rebase()\":{\"details\":\"Restricted to the Operator, Strategist or Governor.\"},\"removeStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to remove\"}},\"removeStrategyFromMintWhitelist(address)\":{\"params\":{\"strategyAddr\":\"Strategy address\"}},\"requestWithdrawal(uint256)\":{\"params\":{\"_amount\":\"Amount of OToken to burn.\"},\"returns\":{\"queued\":\"Cumulative total of all asset queued including already claimed requests.\",\"requestId\":\"Unique ID for the withdrawal request\"}},\"setAutoAllocateThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setDefaultStrategy(address)\":{\"params\":{\"_strategy\":\"Address of the Strategy\"}},\"setDripDuration(uint256)\":{\"params\":{\"_dripDuration\":\"Time in seconds to target a constant yield rate\"}},\"setOperatorAddr(address)\":{\"params\":{\"_operator\":\"New operator address. May be set to the zero address to disable operator-initiated rebases.\"}},\"setRebaseRateMax(uint256)\":{\"params\":{\"apr\":\"in 1e18 notation. 3 * 1e18 = 3% APR\"}},\"setStrategistAddr(address)\":{\"params\":{\"_address\":\"Address of Strategist\"}},\"setVaultBuffer(uint256)\":{\"params\":{\"_vaultBuffer\":\"Percentage using 18 decimals. 100% = 1e18.\"}},\"setWithdrawalClaimDelay(uint256)\":{\"params\":{\"_delay\":\"Delay period (should be between 10 mins to 7 days). Set to 0 to disable async withdrawals\"}},\"totalValue()\":{\"returns\":{\"value\":\"Total value in USD/ETH (1e18)\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"transferToken(address,uint256)\":{\"params\":{\"_amount\":\"Amount of the asset to transfer\",\"_asset\":\"Address for the asset\"}},\"withdrawAllFromStrategy(address)\":{\"params\":{\"_strategyAddr\":\"Strategy address.\"}},\"withdrawFromStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to withdraw.\",\"_assets\":\"Array of asset address that will be withdrawn from the strategy.\",\"_strategyFromAddress\":\"Address of the Strategy to withdraw asset from.\"}}},\"title\":\"Origin Sonic VaultAdmin contract on Sonic\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"addStrategyToMintWhitelist(address)\":{\"notice\":\"Adds a strategy to the mint whitelist. Reverts if strategy isn't approved on Vault.\"},\"addWithdrawalQueueLiquidity()\":{\"notice\":\"Adds WETH to the withdrawal queue if there is a funding shortfall.\"},\"allocate()\":{\"notice\":\"Allocate unallocated funds on Vault to strategies.\"},\"approveStrategy(address)\":{\"notice\":\"Add a strategy to the Vault.\"},\"autoAllocateThreshold()\":{\"notice\":\"OToken mints over this amount automatically allocate funds. 18 decimals.\"},\"burnForStrategy(uint256)\":{\"notice\":\"Burn OTokens for an allowed Strategy\"},\"capitalPaused()\":{\"notice\":\"pause operations that change the OToken supply. eg mint, redeem, allocate, mint/burn for strategy\"},\"checkBalance(address)\":{\"notice\":\"Get the balance of an asset held in Vault and all strategies.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"claimWithdrawal(uint256)\":{\"notice\":\"Claim a previously requested withdrawal once it is claimable. This request can be claimed once the withdrawal queue's `claimable` amount is greater than or equal this request's `queued` amount and 10 minutes has passed. If the requests is not claimable, the transaction will revert with `Queue pending liquidity`. If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`. OToken is converted to asset at 1:1.\"},\"claimWithdrawals(uint256[])\":{\"notice\":\"Claim a previously requested withdrawals once they are claimable. This requests can be claimed once the withdrawal queue's `claimable` amount is greater than or equal each request's `queued` amount and 10 minutes has passed. If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`. If one of the requests is not older than 10 minutes, the whole transaction will revert with `Claim delay not met`.\"},\"defaultStrategy()\":{\"notice\":\"Default strategy for asset\"},\"depositToStrategy(address,address[],uint256[])\":{\"notice\":\"Deposit multiple asset from the vault into the strategy.\"},\"dripDuration()\":{\"notice\":\"Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\"},\"getAllAssets()\":{\"notice\":\"Return all vault asset addresses in order\"},\"getAllStrategies()\":{\"notice\":\"Return the array of all strategies\"},\"getAssetCount()\":{\"notice\":\"Return the number of asset supported by the Vault.\"},\"getStrategyCount()\":{\"notice\":\"Return the number of strategies active on the Vault.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"isSupportedAsset(address)\":{\"notice\":\"Returns whether the vault supports the asset\"},\"lastRebase()\":{\"notice\":\"Time in seconds that the vault last rebased yield.\"},\"maxSupplyDiff()\":{\"notice\":\"Max difference between total supply and total value of assets. 18 decimals.\"},\"mint(address,uint256,uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mint(uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mintForStrategy(uint256)\":{\"notice\":\"Mint OTokens for an allowed Strategy\"},\"oUSD()\":{\"notice\":\"Deprecated: use `oToken()` instead.\"},\"operatorAddr()\":{\"notice\":\"Address authorized to call `rebase()` directly. The Governor and Strategist are always allowed in addition to this address.\"},\"pauseCapital()\":{\"notice\":\"Set the deposit paused flag to true to prevent capital movement.\"},\"pauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to prevent rebasing.\"},\"previewYield()\":{\"notice\":\"Calculates the amount that would rebase at next rebase. This is before any fees.\"},\"rebase()\":{\"notice\":\"Calculate the total value of asset held by the Vault and all strategies and update the supply of OTokens.\"},\"rebasePaused()\":{\"notice\":\"pause rebasing if true\"},\"rebasePerSecondMax()\":{\"notice\":\"max rebase percentage per second Can be used to set maximum yield of the protocol, spreading out yield over time\"},\"rebasePerSecondTarget()\":{\"notice\":\"target rebase rate limit, based on past rates and funds available.\"},\"removeStrategy(address)\":{\"notice\":\"Remove a strategy from the Vault.\"},\"removeStrategyFromMintWhitelist(address)\":{\"notice\":\"Removes a strategy from the mint whitelist.\"},\"requestWithdrawal(uint256)\":{\"notice\":\"Request an asynchronous withdrawal of asset in exchange for OToken. The OToken is burned on request and the asset is transferred to the withdrawer on claim. This request can be claimed once the withdrawal queue's `claimable` amount is greater than or equal this request's `queued` amount. There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue. OToken is converted to asset at 1:1.\"},\"setAutoAllocateThreshold(uint256)\":{\"notice\":\"Sets the minimum amount of OTokens in a mint to trigger an automatic allocation of funds afterwords.\"},\"setDefaultStrategy(address)\":{\"notice\":\"Set the default Strategy for asset, i.e. the one which the asset will be automatically allocated to and withdrawn from\"},\"setDripDuration(uint256)\":{\"notice\":\"Set the drip duration period\"},\"setMaxSupplyDiff(uint256)\":{\"notice\":\"Sets the maximum allowable difference between total supply and asset' value.\"},\"setOperatorAddr(address)\":{\"notice\":\"Set the address authorized to call `rebase()`.\"},\"setRebaseRateMax(uint256)\":{\"notice\":\"Set a yield streaming max rate. This spreads yield over time if it is above the max rate. This is a per rebase APR which due to compounding differs from the yearly APR. Governance should consider this fact when picking a desired APR\"},\"setStrategistAddr(address)\":{\"notice\":\"Set address of Strategist\"},\"setTrusteeAddress(address)\":{\"notice\":\"Sets the trusteeAddress that can receive a portion of yield. Setting to the zero address disables this feature.\"},\"setTrusteeFeeBps(uint256)\":{\"notice\":\"Sets the TrusteeFeeBps to the percentage of yield that should be received in basis points.\"},\"setVaultBuffer(uint256)\":{\"notice\":\"Set a buffer of asset to keep in the Vault to handle most redemptions without needing to spend gas unwinding asset from a Strategy.\"},\"setWithdrawalClaimDelay(uint256)\":{\"notice\":\"Changes the async withdrawal claim period for OETH & superOETHb\"},\"strategistAddr()\":{\"notice\":\"Address of the Strategist\"},\"totalValue()\":{\"notice\":\"Determine the total value of asset held by the vault and its strategies.\"},\"transferGovernance(address)\":{\"notice\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\"},\"transferToken(address,uint256)\":{\"notice\":\"Transfer token to governor. Intended for recovering tokens stuck in contract, i.e. mistaken sends.\"},\"trusteeAddress()\":{\"notice\":\"Trustee contract that can collect a percentage of yield\"},\"trusteeFeeBps()\":{\"notice\":\"Amount of yield collected in basis points. eg 2000 = 20%\"},\"unpauseCapital()\":{\"notice\":\"Set the deposit paused flag to false to enable capital movement.\"},\"unpauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to allow rebasing.\"},\"vaultBuffer()\":{\"notice\":\"Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\"},\"withdrawAllFromStrategies()\":{\"notice\":\"Withdraws all asset from all the strategies and sends asset to the Vault.\"},\"withdrawAllFromStrategy(address)\":{\"notice\":\"Withdraws all asset from the strategy and sends asset to the Vault.\"},\"withdrawFromStrategy(address,address[],uint256[])\":{\"notice\":\"Withdraw multiple asset from the strategy to the vault.\"},\"withdrawalClaimDelay()\":{\"notice\":\"Sets a minimum delay that is required to elapse between requesting async withdrawals and claiming the request. When set to 0 async withdrawals are disabled.\"},\"withdrawalQueueMetadata()\":{\"notice\":\"Global metadata for the withdrawal queue including: queued - cumulative total of all withdrawal requests included the ones that have already been claimed claimable - cumulative total of all the requests that can be claimed including the ones already claimed claimed - total of all the requests that have been claimed nextWithdrawalIndex - index of the next withdrawal request starting at 0\"},\"withdrawalRequests(uint256)\":{\"notice\":\"Mapping of withdrawal request indices to the user withdrawal request data\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/vault/OSVault.sol\":\"OSVault\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0x61437cb513a887a1bbad006e7b1c8b414478427d33de47c5600af3c748f108da\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeCast.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\\n * checks.\\n *\\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\\n * easily result in undesired exploitation or bugs, since developers usually\\n * assume that overflows raise errors. `SafeCast` restores this intuition by\\n * reverting the transaction when such an operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n *\\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\\n * all math on `uint256` and `int256` and then downcasting.\\n */\\nlibrary SafeCast {\\n /**\\n * @dev Returns the downcasted uint224 from uint256, reverting on\\n * overflow (when the input is greater than largest uint224).\\n *\\n * Counterpart to Solidity's `uint224` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 224 bits\\n */\\n function toUint224(uint256 value) internal pure returns (uint224) {\\n require(value <= type(uint224).max, \\\"SafeCast: value doesn't fit in 224 bits\\\");\\n return uint224(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint128 from uint256, reverting on\\n * overflow (when the input is greater than largest uint128).\\n *\\n * Counterpart to Solidity's `uint128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n */\\n function toUint128(uint256 value) internal pure returns (uint128) {\\n require(value <= type(uint128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return uint128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint96 from uint256, reverting on\\n * overflow (when the input is greater than largest uint96).\\n *\\n * Counterpart to Solidity's `uint96` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 96 bits\\n */\\n function toUint96(uint256 value) internal pure returns (uint96) {\\n require(value <= type(uint96).max, \\\"SafeCast: value doesn't fit in 96 bits\\\");\\n return uint96(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint64 from uint256, reverting on\\n * overflow (when the input is greater than largest uint64).\\n *\\n * Counterpart to Solidity's `uint64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n */\\n function toUint64(uint256 value) internal pure returns (uint64) {\\n require(value <= type(uint64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return uint64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint32 from uint256, reverting on\\n * overflow (when the input is greater than largest uint32).\\n *\\n * Counterpart to Solidity's `uint32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n */\\n function toUint32(uint256 value) internal pure returns (uint32) {\\n require(value <= type(uint32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return uint32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint16 from uint256, reverting on\\n * overflow (when the input is greater than largest uint16).\\n *\\n * Counterpart to Solidity's `uint16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n */\\n function toUint16(uint256 value) internal pure returns (uint16) {\\n require(value <= type(uint16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return uint16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint8 from uint256, reverting on\\n * overflow (when the input is greater than largest uint8).\\n *\\n * Counterpart to Solidity's `uint8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits.\\n */\\n function toUint8(uint256 value) internal pure returns (uint8) {\\n require(value <= type(uint8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return uint8(value);\\n }\\n\\n /**\\n * @dev Converts a signed int256 into an unsigned uint256.\\n *\\n * Requirements:\\n *\\n * - input must be greater than or equal to 0.\\n */\\n function toUint256(int256 value) internal pure returns (uint256) {\\n require(value >= 0, \\\"SafeCast: value must be positive\\\");\\n return uint256(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int128 from int256, reverting on\\n * overflow (when the input is less than smallest int128 or\\n * greater than largest int128).\\n *\\n * Counterpart to Solidity's `int128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt128(int256 value) internal pure returns (int128) {\\n require(value >= type(int128).min && value <= type(int128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return int128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int64 from int256, reverting on\\n * overflow (when the input is less than smallest int64 or\\n * greater than largest int64).\\n *\\n * Counterpart to Solidity's `int64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt64(int256 value) internal pure returns (int64) {\\n require(value >= type(int64).min && value <= type(int64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return int64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int32 from int256, reverting on\\n * overflow (when the input is less than smallest int32 or\\n * greater than largest int32).\\n *\\n * Counterpart to Solidity's `int32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt32(int256 value) internal pure returns (int32) {\\n require(value >= type(int32).min && value <= type(int32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return int32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int16 from int256, reverting on\\n * overflow (when the input is less than smallest int16 or\\n * greater than largest int16).\\n *\\n * Counterpart to Solidity's `int16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt16(int256 value) internal pure returns (int16) {\\n require(value >= type(int16).min && value <= type(int16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return int16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int8 from int256, reverting on\\n * overflow (when the input is less than smallest int8 or\\n * greater than largest int8).\\n *\\n * Counterpart to Solidity's `int8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits.\\n *\\n * _Available since v3.1._\\n */\\n function toInt8(int256 value) internal pure returns (int8) {\\n require(value >= type(int8).min && value <= type(int8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return int8(value);\\n }\\n\\n /**\\n * @dev Converts an unsigned uint256 into a signed int256.\\n *\\n * Requirements:\\n *\\n * - input must be less than or equal to maxInt256.\\n */\\n function toInt256(uint256 value) internal pure returns (int256) {\\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\\n require(value <= uint256(type(int256).max), \\\"SafeCast: value doesn't fit in an int256\\\");\\n return int256(value);\\n }\\n}\\n\",\"keccak256\":\"0x5c6caab697d302ad7eb59c234a4d2dbc965c1bae87709bd2850060b7695b28c7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa2f576be637946f767aa56601c26d717f48a0aff44f82e46f13807eea1009a21\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @notice Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @notice Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n emit GovernorshipTransferred(_governor(), newGovernor);\\n\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0xf32f873c8bfbacf2e5f01d0cf37bc7f54fbd5aa656e95c8a599114229946f107\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xa562062698aa12572123b36dfd2072f1a39e44fed2031cc19c2c9fd522f96ec2\",\"license\":\"MIT\"},\"contracts/interfaces/IStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\\n */\\ninterface IStrategy {\\n /**\\n * @dev Deposit the given asset to platform\\n * @param _asset asset address\\n * @param _amount Amount to deposit\\n */\\n function deposit(address _asset, uint256 _amount) external;\\n\\n /**\\n * @dev Deposit the entire balance of all supported assets in the Strategy\\n * to the platform\\n */\\n function depositAll() external;\\n\\n /**\\n * @dev Withdraw given asset from Lending platform\\n */\\n function withdraw(\\n address _recipient,\\n address _asset,\\n uint256 _amount\\n ) external;\\n\\n /**\\n * @dev Liquidate all assets in strategy and return them to Vault.\\n */\\n function withdrawAll() external;\\n\\n /**\\n * @dev Returns the current balance of the given asset.\\n */\\n function checkBalance(address _asset)\\n external\\n view\\n returns (uint256 balance);\\n\\n /**\\n * @dev Returns bool indicating whether strategy supports asset.\\n */\\n function supportsAsset(address _asset) external view returns (bool);\\n\\n /**\\n * @dev Collect reward tokens from the Strategy.\\n */\\n function collectRewardTokens() external;\\n\\n /**\\n * @dev The address array of the reward tokens for the Strategy.\\n */\\n function getRewardTokenAddresses() external view returns (address[] memory);\\n\\n function harvesterAddress() external view returns (address);\\n\\n function transferToken(address token, uint256 amount) external;\\n\\n function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\\n external;\\n}\\n\",\"keccak256\":\"0x79ca47defb3b5a56bba13f14c440838152fd1c1aa640476154516a16da4da8ba\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/IVault.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { VaultStorage } from \\\"../vault/VaultStorage.sol\\\";\\n\\ninterface IVault {\\n // slither-disable-start constable-states\\n\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event DefaultStrategyUpdated(address _strategy);\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\\n event DripDurationChanged(uint256 dripDuration);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\\n\\n // Governable.sol\\n function transferGovernance(address _newGovernor) external;\\n\\n function claimGovernance() external;\\n\\n function governor() external view returns (address);\\n\\n // VaultAdmin.sol\\n function setVaultBuffer(uint256 _vaultBuffer) external;\\n\\n function vaultBuffer() external view returns (uint256);\\n\\n function setAutoAllocateThreshold(uint256 _threshold) external;\\n\\n function autoAllocateThreshold() external view returns (uint256);\\n\\n function setStrategistAddr(address _address) external;\\n\\n function strategistAddr() external view returns (address);\\n\\n function setOperatorAddr(address _operator) external;\\n\\n function operatorAddr() external view returns (address);\\n\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\\n\\n function maxSupplyDiff() external view returns (uint256);\\n\\n function setTrusteeAddress(address _address) external;\\n\\n function trusteeAddress() external view returns (address);\\n\\n function setTrusteeFeeBps(uint256 _basis) external;\\n\\n function trusteeFeeBps() external view returns (uint256);\\n\\n function approveStrategy(address _addr) external;\\n\\n function removeStrategy(address _addr) external;\\n\\n function setDefaultStrategy(address _strategy) external;\\n\\n function defaultStrategy() external view returns (address);\\n\\n function pauseRebase() external;\\n\\n function unpauseRebase() external;\\n\\n function rebasePaused() external view returns (bool);\\n\\n function pauseCapital() external;\\n\\n function unpauseCapital() external;\\n\\n function capitalPaused() external view returns (bool);\\n\\n function transferToken(address _asset, uint256 _amount) external;\\n\\n function withdrawAllFromStrategy(address _strategyAddr) external;\\n\\n function withdrawAllFromStrategies() external;\\n\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n // VaultCore.sol\\n function mint(uint256 _amount) external;\\n\\n function mintForStrategy(uint256 _amount) external;\\n\\n function burnForStrategy(uint256 _amount) external;\\n\\n function allocate() external;\\n\\n function rebase() external;\\n\\n function totalValue() external view returns (uint256 value);\\n\\n function checkBalance(address _asset) external view returns (uint256);\\n\\n function getAssetCount() external view returns (uint256);\\n\\n function getAllAssets() external view returns (address[] memory);\\n\\n function getStrategyCount() external view returns (uint256);\\n\\n function getAllStrategies() external view returns (address[] memory);\\n\\n function strategies(address _addr)\\n external\\n view\\n returns (VaultStorage.Strategy memory);\\n\\n /// @notice Deprecated: use `asset()` instead.\\n function isSupportedAsset(address _asset) external view returns (bool);\\n\\n function asset() external view returns (address);\\n\\n function oToken() external view returns (address);\\n\\n function initialize(address) external;\\n\\n function addWithdrawalQueueLiquidity() external;\\n\\n function requestWithdrawal(uint256 _amount)\\n external\\n returns (uint256 requestId, uint256 queued);\\n\\n function claimWithdrawal(uint256 requestId)\\n external\\n returns (uint256 amount);\\n\\n function claimWithdrawals(uint256[] memory requestIds)\\n external\\n returns (uint256[] memory amounts, uint256 totalAmount);\\n\\n function withdrawalQueueMetadata()\\n external\\n view\\n returns (VaultStorage.WithdrawalQueueMetadata memory);\\n\\n function withdrawalRequests(uint256 requestId)\\n external\\n view\\n returns (VaultStorage.WithdrawalRequest memory);\\n\\n function addStrategyToMintWhitelist(address strategyAddr) external;\\n\\n function removeStrategyFromMintWhitelist(address strategyAddr) external;\\n\\n function isMintWhitelistedStrategy(address strategyAddr)\\n external\\n view\\n returns (bool);\\n\\n function withdrawalClaimDelay() external view returns (uint256);\\n\\n function setWithdrawalClaimDelay(uint256 newDelay) external;\\n\\n function lastRebase() external view returns (uint64);\\n\\n function dripDuration() external view returns (uint64);\\n\\n function setDripDuration(uint256 _dripDuration) external;\\n\\n function rebasePerSecondMax() external view returns (uint64);\\n\\n function setRebaseRateMax(uint256 yearlyApr) external;\\n\\n function rebasePerSecondTarget() external view returns (uint64);\\n\\n function previewYield() external view returns (uint256 yield);\\n\\n // slither-disable-end constable-states\\n}\\n\",\"keccak256\":\"0x573ee781634813c659362ca2950f439711c2d2b1f79b285d22ecd14c8c32fb9d\",\"license\":\"BUSL-1.1\"},\"contracts/token/OUSD.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OUSD Token Contract\\n * @dev ERC20 compatible contract for OUSD\\n * @dev Implements an elastic supply\\n * @author Origin Protocol Inc\\n */\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\ncontract OUSD is Governable {\\n using SafeCast for int256;\\n using SafeCast for uint256;\\n\\n /// @dev Event triggered when the supply changes\\n /// @param totalSupply Updated token total supply\\n /// @param rebasingCredits Updated token rebasing credits\\n /// @param rebasingCreditsPerToken Updated token rebasing credits per token\\n event TotalSupplyUpdatedHighres(\\n uint256 totalSupply,\\n uint256 rebasingCredits,\\n uint256 rebasingCreditsPerToken\\n );\\n /// @dev Event triggered when an account opts in for rebasing\\n /// @param account Address of the account\\n event AccountRebasingEnabled(address account);\\n /// @dev Event triggered when an account opts out of rebasing\\n /// @param account Address of the account\\n event AccountRebasingDisabled(address account);\\n /// @dev Emitted when `value` tokens are moved from one account `from` to\\n /// another `to`.\\n /// @param from Address of the account tokens are moved from\\n /// @param to Address of the account tokens are moved to\\n /// @param value Amount of tokens transferred\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n /// @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n /// a call to {approve}. `value` is the new allowance.\\n /// @param owner Address of the owner approving allowance\\n /// @param spender Address of the spender allowance is granted to\\n /// @param value Amount of tokens spender can transfer\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 value\\n );\\n /// @dev Yield resulting from {changeSupply} that a `source` account would\\n /// receive is directed to `target` account.\\n /// @param source Address of the source forwarding the yield\\n /// @param target Address of the target receiving the yield\\n event YieldDelegated(address source, address target);\\n /// @dev Yield delegation from `source` account to the `target` account is\\n /// suspended.\\n /// @param source Address of the source suspending yield forwarding\\n /// @param target Address of the target no longer receiving yield from `source`\\n /// account\\n event YieldUndelegated(address source, address target);\\n\\n enum RebaseOptions {\\n NotSet,\\n StdNonRebasing,\\n StdRebasing,\\n YieldDelegationSource,\\n YieldDelegationTarget\\n }\\n\\n uint256[154] private _gap; // Slots to align with deployed contract\\n uint256 private constant MAX_SUPPLY = type(uint128).max;\\n /// @dev The amount of tokens in existence\\n uint256 public totalSupply;\\n mapping(address => mapping(address => uint256)) private allowances;\\n /// @dev The vault with privileges to execute {mint}, {burn}\\n /// and {changeSupply}\\n address public vaultAddress;\\n mapping(address => uint256) internal creditBalances;\\n // the 2 storage variables below need trailing underscores to not name collide with public functions\\n uint256 private rebasingCredits_; // Sum of all rebasing credits (creditBalances for rebasing accounts)\\n uint256 private rebasingCreditsPerToken_;\\n /// @dev The amount of tokens that are not rebasing - receiving yield\\n uint256 public nonRebasingSupply;\\n mapping(address => uint256) internal alternativeCreditsPerToken;\\n /// @dev A map of all addresses and their respective RebaseOptions\\n mapping(address => RebaseOptions) public rebaseState;\\n mapping(address => uint256) private __deprecated_isUpgraded;\\n /// @dev A map of addresses that have yields forwarded to. This is an\\n /// inverse mapping of {yieldFrom}\\n /// Key Account forwarding yield\\n /// Value Account receiving yield\\n mapping(address => address) public yieldTo;\\n /// @dev A map of addresses that are receiving the yield. This is an\\n /// inverse mapping of {yieldTo}\\n /// Key Account receiving yield\\n /// Value Account forwarding yield\\n mapping(address => address) public yieldFrom;\\n\\n uint256 private constant RESOLUTION_INCREASE = 1e9;\\n uint256[34] private __gap; // including below gap totals up to 200\\n\\n /// @dev Verifies that the caller is the Governor or Strategist.\\n modifier onlyGovernorOrStrategist() {\\n require(\\n isGovernor() || msg.sender == IVault(vaultAddress).strategistAddr(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n /// @dev Initializes the contract and sets necessary variables.\\n /// @param _vaultAddress Address of the vault contract\\n /// @param _initialCreditsPerToken The starting rebasing credits per token.\\n function initialize(address _vaultAddress, uint256 _initialCreditsPerToken)\\n external\\n onlyGovernor\\n {\\n require(_vaultAddress != address(0), \\\"Zero vault address\\\");\\n require(vaultAddress == address(0), \\\"Already initialized\\\");\\n\\n rebasingCreditsPerToken_ = _initialCreditsPerToken;\\n vaultAddress = _vaultAddress;\\n }\\n\\n /// @dev Returns the symbol of the token, a shorter version\\n /// of the name.\\n function symbol() external pure virtual returns (string memory) {\\n return \\\"OUSD\\\";\\n }\\n\\n /// @dev Returns the name of the token.\\n function name() external pure virtual returns (string memory) {\\n return \\\"Origin Dollar\\\";\\n }\\n\\n /// @dev Returns the number of decimals used to get its user representation.\\n function decimals() external pure virtual returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev Verifies that the caller is the Vault contract\\n */\\n modifier onlyVault() {\\n require(vaultAddress == msg.sender, \\\"Caller is not the Vault\\\");\\n _;\\n }\\n\\n /**\\n * @return High resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerTokenHighres() external view returns (uint256) {\\n return rebasingCreditsPerToken_;\\n }\\n\\n /**\\n * @return Low resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerToken() external view returns (uint256) {\\n return rebasingCreditsPerToken_ / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return High resolution total number of rebasing credits\\n */\\n function rebasingCreditsHighres() external view returns (uint256) {\\n return rebasingCredits_;\\n }\\n\\n /**\\n * @return Low resolution total number of rebasing credits\\n */\\n function rebasingCredits() external view returns (uint256) {\\n return rebasingCredits_ / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @notice Gets the balance of the specified address.\\n * @param _account Address to query the balance of.\\n * @return A uint256 representing the amount of base units owned by the\\n * specified address.\\n */\\n function balanceOf(address _account) public view returns (uint256) {\\n RebaseOptions state = rebaseState[_account];\\n if (state == RebaseOptions.YieldDelegationSource) {\\n // Saves a slot read when transferring to or from a yield delegating source\\n // since we know creditBalances equals the balance.\\n return creditBalances[_account];\\n }\\n uint256 baseBalance = (creditBalances[_account] * 1e18) /\\n _creditsPerToken(_account);\\n if (state == RebaseOptions.YieldDelegationTarget) {\\n // creditBalances of yieldFrom accounts equals token balances\\n return baseBalance - creditBalances[yieldFrom[_account]];\\n }\\n return baseBalance;\\n }\\n\\n /**\\n * @notice Gets the credits balance of the specified address.\\n * @dev Backwards compatible with old low res credits per token.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256) Credit balance and credits per token of the\\n * address\\n */\\n function creditsBalanceOf(address _account)\\n external\\n view\\n returns (uint256, uint256)\\n {\\n uint256 cpt = _creditsPerToken(_account);\\n if (cpt == 1e27) {\\n // For a period before the resolution upgrade, we created all new\\n // contract accounts at high resolution. Since they are not changing\\n // as a result of this upgrade, we will return their true values\\n return (creditBalances[_account], cpt);\\n } else {\\n return (\\n creditBalances[_account] / RESOLUTION_INCREASE,\\n cpt / RESOLUTION_INCREASE\\n );\\n }\\n }\\n\\n /**\\n * @notice Gets the credits balance of the specified address.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\\n * address, and isUpgraded\\n */\\n function creditsBalanceOfHighres(address _account)\\n external\\n view\\n returns (\\n uint256,\\n uint256,\\n bool\\n )\\n {\\n return (\\n creditBalances[_account],\\n _creditsPerToken(_account),\\n true // all accounts have their resolution \\\"upgraded\\\"\\n );\\n }\\n\\n // Backwards compatible view\\n function nonRebasingCreditsPerToken(address _account)\\n external\\n view\\n returns (uint256)\\n {\\n return alternativeCreditsPerToken[_account];\\n }\\n\\n /**\\n * @notice Transfer tokens to a specified address.\\n * @param _to the address to transfer to.\\n * @param _value the amount to be transferred.\\n * @return true on success.\\n */\\n function transfer(address _to, uint256 _value) external returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n\\n _executeTransfer(msg.sender, _to, _value);\\n\\n emit Transfer(msg.sender, _to, _value);\\n return true;\\n }\\n\\n /**\\n * @notice Transfer tokens from one address to another.\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value The amount of tokens to be transferred.\\n * @return true on success.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n uint256 userAllowance = allowances[_from][msg.sender];\\n require(_value <= userAllowance, \\\"Allowance exceeded\\\");\\n\\n unchecked {\\n allowances[_from][msg.sender] = userAllowance - _value;\\n }\\n\\n _executeTransfer(_from, _to, _value);\\n\\n emit Transfer(_from, _to, _value);\\n return true;\\n }\\n\\n function _executeTransfer(\\n address _from,\\n address _to,\\n uint256 _value\\n ) internal {\\n (\\n int256 fromRebasingCreditsDiff,\\n int256 fromNonRebasingSupplyDiff\\n ) = _adjustAccount(_from, -_value.toInt256());\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_to, _value.toInt256());\\n\\n _adjustGlobals(\\n fromRebasingCreditsDiff + toRebasingCreditsDiff,\\n fromNonRebasingSupplyDiff + toNonRebasingSupplyDiff\\n );\\n }\\n\\n function _adjustAccount(address _account, int256 _balanceChange)\\n internal\\n returns (int256 rebasingCreditsDiff, int256 nonRebasingSupplyDiff)\\n {\\n RebaseOptions state = rebaseState[_account];\\n int256 currentBalance = balanceOf(_account).toInt256();\\n if (currentBalance + _balanceChange < 0) {\\n revert(\\\"Transfer amount exceeds balance\\\");\\n }\\n uint256 newBalance = (currentBalance + _balanceChange).toUint256();\\n\\n if (state == RebaseOptions.YieldDelegationSource) {\\n address target = yieldTo[_account];\\n uint256 targetOldBalance = balanceOf(target);\\n uint256 targetNewCredits = _balanceToRebasingCredits(\\n targetOldBalance + newBalance\\n );\\n rebasingCreditsDiff =\\n targetNewCredits.toInt256() -\\n creditBalances[target].toInt256();\\n\\n creditBalances[_account] = newBalance;\\n creditBalances[target] = targetNewCredits;\\n } else if (state == RebaseOptions.YieldDelegationTarget) {\\n uint256 newCredits = _balanceToRebasingCredits(\\n newBalance + creditBalances[yieldFrom[_account]]\\n );\\n rebasingCreditsDiff =\\n newCredits.toInt256() -\\n creditBalances[_account].toInt256();\\n creditBalances[_account] = newCredits;\\n } else {\\n _autoMigrate(_account);\\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\\n _account\\n ];\\n if (alternativeCreditsPerTokenMem > 0) {\\n nonRebasingSupplyDiff = _balanceChange;\\n if (alternativeCreditsPerTokenMem != 1e18) {\\n alternativeCreditsPerToken[_account] = 1e18;\\n }\\n creditBalances[_account] = newBalance;\\n } else {\\n uint256 newCredits = _balanceToRebasingCredits(newBalance);\\n rebasingCreditsDiff =\\n newCredits.toInt256() -\\n creditBalances[_account].toInt256();\\n creditBalances[_account] = newCredits;\\n }\\n }\\n }\\n\\n function _adjustGlobals(\\n int256 _rebasingCreditsDiff,\\n int256 _nonRebasingSupplyDiff\\n ) internal {\\n if (_rebasingCreditsDiff != 0) {\\n rebasingCredits_ = (rebasingCredits_.toInt256() +\\n _rebasingCreditsDiff).toUint256();\\n }\\n if (_nonRebasingSupplyDiff != 0) {\\n nonRebasingSupply = (nonRebasingSupply.toInt256() +\\n _nonRebasingSupplyDiff).toUint256();\\n }\\n }\\n\\n /**\\n * @notice Function to check the amount of tokens that _owner has allowed\\n * to `_spender`.\\n * @param _owner The address which owns the funds.\\n * @param _spender The address which will spend the funds.\\n * @return The number of tokens still available for the _spender.\\n */\\n function allowance(address _owner, address _spender)\\n external\\n view\\n returns (uint256)\\n {\\n return allowances[_owner][_spender];\\n }\\n\\n /**\\n * @notice Approve the passed address to spend the specified amount of\\n * tokens on behalf of msg.sender.\\n * @param _spender The address which will spend the funds.\\n * @param _value The amount of tokens to be spent.\\n * @return true on success.\\n */\\n function approve(address _spender, uint256 _value) external returns (bool) {\\n allowances[msg.sender][_spender] = _value;\\n emit Approval(msg.sender, _spender, _value);\\n return true;\\n }\\n\\n /**\\n * @notice Creates `_amount` tokens and assigns them to `_account`,\\n * increasing the total supply.\\n */\\n function mint(address _account, uint256 _amount) external onlyVault {\\n require(_account != address(0), \\\"Mint to the zero address\\\");\\n\\n // Account\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_account, _amount.toInt256());\\n // Globals\\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\\n totalSupply = totalSupply + _amount;\\n\\n require(totalSupply < MAX_SUPPLY, \\\"Max supply\\\");\\n emit Transfer(address(0), _account, _amount);\\n }\\n\\n /**\\n * @notice Destroys `_amount` tokens from `_account`,\\n * reducing the total supply.\\n */\\n function burn(address _account, uint256 _amount) external onlyVault {\\n require(_account != address(0), \\\"Burn from the zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n\\n // Account\\n (\\n int256 toRebasingCreditsDiff,\\n int256 toNonRebasingSupplyDiff\\n ) = _adjustAccount(_account, -_amount.toInt256());\\n // Globals\\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\\n totalSupply = totalSupply - _amount;\\n\\n emit Transfer(_account, address(0), _amount);\\n }\\n\\n /**\\n * @dev Get the credits per token for an account. Returns a fixed amount\\n * if the account is non-rebasing.\\n * @param _account Address of the account.\\n */\\n function _creditsPerToken(address _account)\\n internal\\n view\\n returns (uint256)\\n {\\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\\n _account\\n ];\\n if (alternativeCreditsPerTokenMem != 0) {\\n return alternativeCreditsPerTokenMem;\\n } else {\\n return rebasingCreditsPerToken_;\\n }\\n }\\n\\n /**\\n * @dev Auto migrate contracts to be non rebasing,\\n * unless they have opted into yield.\\n * @param _account Address of the account.\\n */\\n function _autoMigrate(address _account) internal {\\n uint256 codeLen = _account.code.length;\\n bool isEOA = (codeLen == 0) ||\\n (codeLen == 23 && bytes3(_account.code) == 0xef0100);\\n // In previous code versions, contracts would not have had their\\n // rebaseState[_account] set to RebaseOptions.NonRebasing when migrated\\n // therefore we check the actual accounting used on the account as well.\\n if (\\n (!isEOA) &&\\n rebaseState[_account] == RebaseOptions.NotSet &&\\n alternativeCreditsPerToken[_account] == 0\\n ) {\\n _rebaseOptOut(_account);\\n }\\n }\\n\\n /**\\n * @dev Calculates credits from contract's global rebasingCreditsPerToken_, and\\n * also balance that corresponds to those credits. The latter is important\\n * when adjusting the contract's global nonRebasingSupply to circumvent any\\n * possible rounding errors.\\n *\\n * @param _balance Balance of the account.\\n */\\n function _balanceToRebasingCredits(uint256 _balance)\\n internal\\n view\\n returns (uint256 rebasingCredits)\\n {\\n // Rounds up, because we need to ensure that accounts always have\\n // at least the balance that they should have.\\n // Note this should always be used on an absolute account value,\\n // not on a possibly negative diff, because then the rounding would be wrong.\\n return ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18;\\n }\\n\\n /**\\n * @notice The calling account will start receiving yield after a successful call.\\n * @param _account Address of the account.\\n */\\n function governanceRebaseOptIn(address _account) external onlyGovernor {\\n require(_account != address(0), \\\"Zero address not allowed\\\");\\n _rebaseOptIn(_account);\\n }\\n\\n /**\\n * @notice The calling account will start receiving yield after a successful call.\\n */\\n function rebaseOptIn() external {\\n _rebaseOptIn(msg.sender);\\n }\\n\\n function _rebaseOptIn(address _account) internal {\\n uint256 balance = balanceOf(_account);\\n\\n // prettier-ignore\\n require(\\n alternativeCreditsPerToken[_account] > 0 ||\\n // Accounts may explicitly `rebaseOptIn` regardless of\\n // accounting if they have a 0 balance.\\n creditBalances[_account] == 0\\n ,\\n \\\"Account must be non-rebasing\\\"\\n );\\n RebaseOptions state = rebaseState[_account];\\n // prettier-ignore\\n require(\\n state == RebaseOptions.StdNonRebasing ||\\n state == RebaseOptions.NotSet,\\n \\\"Only standard non-rebasing accounts can opt in\\\"\\n );\\n\\n uint256 newCredits = _balanceToRebasingCredits(balance);\\n\\n // Account\\n rebaseState[_account] = RebaseOptions.StdRebasing;\\n alternativeCreditsPerToken[_account] = 0;\\n creditBalances[_account] = newCredits;\\n // Globals\\n _adjustGlobals(newCredits.toInt256(), -balance.toInt256());\\n\\n emit AccountRebasingEnabled(_account);\\n }\\n\\n /**\\n * @notice The calling account will no longer receive yield\\n */\\n function rebaseOptOut() external {\\n _rebaseOptOut(msg.sender);\\n }\\n\\n function _rebaseOptOut(address _account) internal {\\n require(\\n alternativeCreditsPerToken[_account] == 0,\\n \\\"Account must be rebasing\\\"\\n );\\n RebaseOptions state = rebaseState[_account];\\n require(\\n state == RebaseOptions.StdRebasing || state == RebaseOptions.NotSet,\\n \\\"Only standard rebasing accounts can opt out\\\"\\n );\\n\\n uint256 oldCredits = creditBalances[_account];\\n uint256 balance = balanceOf(_account);\\n\\n // Account\\n rebaseState[_account] = RebaseOptions.StdNonRebasing;\\n alternativeCreditsPerToken[_account] = 1e18;\\n creditBalances[_account] = balance;\\n // Globals\\n _adjustGlobals(-oldCredits.toInt256(), balance.toInt256());\\n\\n emit AccountRebasingDisabled(_account);\\n }\\n\\n /**\\n * @notice Distribute yield to users. This changes the exchange rate\\n * between \\\"credits\\\" and OUSD tokens to change rebasing user's balances.\\n * @param _newTotalSupply New total supply of OUSD.\\n */\\n function changeSupply(uint256 _newTotalSupply) external onlyVault {\\n require(totalSupply > 0, \\\"Cannot increase 0 supply\\\");\\n\\n if (totalSupply == _newTotalSupply) {\\n emit TotalSupplyUpdatedHighres(\\n totalSupply,\\n rebasingCredits_,\\n rebasingCreditsPerToken_\\n );\\n return;\\n }\\n\\n totalSupply = _newTotalSupply > MAX_SUPPLY\\n ? MAX_SUPPLY\\n : _newTotalSupply;\\n\\n uint256 rebasingSupply = totalSupply - nonRebasingSupply;\\n // round up in the favour of the protocol\\n rebasingCreditsPerToken_ =\\n (rebasingCredits_ * 1e18 + rebasingSupply - 1) /\\n rebasingSupply;\\n\\n require(rebasingCreditsPerToken_ > 0, \\\"Invalid change in supply\\\");\\n\\n emit TotalSupplyUpdatedHighres(\\n totalSupply,\\n rebasingCredits_,\\n rebasingCreditsPerToken_\\n );\\n }\\n\\n /*\\n * @notice Send the yield from one account to another account.\\n * Each account keeps its own balances.\\n */\\n function delegateYield(address _from, address _to)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_from != address(0), \\\"Zero from address not allowed\\\");\\n require(_to != address(0), \\\"Zero to address not allowed\\\");\\n\\n require(_from != _to, \\\"Cannot delegate to self\\\");\\n require(\\n yieldFrom[_to] == address(0) &&\\n yieldTo[_to] == address(0) &&\\n yieldFrom[_from] == address(0) &&\\n yieldTo[_from] == address(0),\\n \\\"Blocked by existing yield delegation\\\"\\n );\\n RebaseOptions stateFrom = rebaseState[_from];\\n RebaseOptions stateTo = rebaseState[_to];\\n\\n require(\\n stateFrom == RebaseOptions.NotSet ||\\n stateFrom == RebaseOptions.StdNonRebasing ||\\n stateFrom == RebaseOptions.StdRebasing,\\n \\\"Invalid rebaseState from\\\"\\n );\\n\\n require(\\n stateTo == RebaseOptions.NotSet ||\\n stateTo == RebaseOptions.StdNonRebasing ||\\n stateTo == RebaseOptions.StdRebasing,\\n \\\"Invalid rebaseState to\\\"\\n );\\n\\n if (alternativeCreditsPerToken[_from] == 0) {\\n _rebaseOptOut(_from);\\n }\\n if (alternativeCreditsPerToken[_to] > 0) {\\n _rebaseOptIn(_to);\\n }\\n\\n uint256 fromBalance = balanceOf(_from);\\n uint256 toBalance = balanceOf(_to);\\n uint256 oldToCredits = creditBalances[_to];\\n uint256 newToCredits = _balanceToRebasingCredits(\\n fromBalance + toBalance\\n );\\n\\n // Set up the bidirectional links\\n yieldTo[_from] = _to;\\n yieldFrom[_to] = _from;\\n\\n // Local\\n rebaseState[_from] = RebaseOptions.YieldDelegationSource;\\n alternativeCreditsPerToken[_from] = 1e18;\\n creditBalances[_from] = fromBalance;\\n rebaseState[_to] = RebaseOptions.YieldDelegationTarget;\\n creditBalances[_to] = newToCredits;\\n\\n // Global\\n int256 creditsChange = newToCredits.toInt256() -\\n oldToCredits.toInt256();\\n _adjustGlobals(creditsChange, -(fromBalance).toInt256());\\n emit YieldDelegated(_from, _to);\\n }\\n\\n /*\\n * @notice Stop sending the yield from one account to another account.\\n */\\n function undelegateYield(address _from) external onlyGovernorOrStrategist {\\n // Require a delegation, which will also ensure a valid delegation\\n require(yieldTo[_from] != address(0), \\\"Zero address not allowed\\\");\\n\\n address to = yieldTo[_from];\\n uint256 fromBalance = balanceOf(_from);\\n uint256 toBalance = balanceOf(to);\\n uint256 oldToCredits = creditBalances[to];\\n uint256 newToCredits = _balanceToRebasingCredits(toBalance);\\n\\n // Remove the bidirectional links\\n yieldFrom[to] = address(0);\\n yieldTo[_from] = address(0);\\n\\n // Local\\n rebaseState[_from] = RebaseOptions.StdNonRebasing;\\n // alternativeCreditsPerToken[from] already 1e18 from `delegateYield()`\\n creditBalances[_from] = fromBalance;\\n rebaseState[to] = RebaseOptions.StdRebasing;\\n // alternativeCreditsPerToken[to] already 0 from `delegateYield()`\\n creditBalances[to] = newToCredits;\\n\\n // Global\\n int256 creditsChange = newToCredits.toInt256() -\\n oldToCredits.toInt256();\\n _adjustGlobals(creditsChange, fromBalance.toInt256());\\n emit YieldUndelegated(_from, to);\\n }\\n}\\n\",\"keccak256\":\"0x73439bef6569f5adf6f5ce2cb54a5f0d3109d4819457532236e172a7091980a9\",\"license\":\"BUSL-1.1\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { IBasicToken } from \\\"../interfaces/IBasicToken.sol\\\";\\n\\nlibrary Helpers {\\n /**\\n * @notice Fetch the `symbol()` from an ERC20 token\\n * @dev Grabs the `symbol()` from a contract\\n * @param _token Address of the ERC20 token\\n * @return string Symbol of the ERC20 token\\n */\\n function getSymbol(address _token) internal view returns (string memory) {\\n string memory symbol = IBasicToken(_token).symbol();\\n return symbol;\\n }\\n\\n /**\\n * @notice Fetch the `decimals()` from an ERC20 token\\n * @dev Grabs the `decimals()` from a contract and fails if\\n * the decimal value does not live within a certain range\\n * @param _token Address of the ERC20 token\\n * @return uint256 Decimals of the ERC20 token\\n */\\n function getDecimals(address _token) internal view returns (uint256) {\\n uint256 decimals = IBasicToken(_token).decimals();\\n require(\\n decimals >= 4 && decimals <= 18,\\n \\\"Token must have sufficient decimal places\\\"\\n );\\n\\n return decimals;\\n }\\n}\\n\",\"keccak256\":\"0x4366f8d90b34c1eef8bbaaf369b1e5cd59f04027bb3c111f208eaee65bbc0346\",\"license\":\"BUSL-1.1\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base contract any contracts that need to initialize state after deployment.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0x50d39ebf38a3d3111f2b77a6c75ece1d4ae731552fec4697ab16fcf6c0d4d5e8\",\"license\":\"BUSL-1.1\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n // slither-disable-next-line divide-before-multiply\\n x = x.div(10**(from - to));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e36 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0x71d6ed0053a1e5ef018d27c3b6d024f336d8157ab6f6859e400b3243a50a71b7\",\"license\":\"BUSL-1.1\"},\"contracts/vault/OSVault.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { VaultAdmin } from \\\"./VaultAdmin.sol\\\";\\n\\n/**\\n * @title Origin Sonic VaultAdmin contract on Sonic\\n * @author Origin Protocol Inc\\n */\\ncontract OSVault is VaultAdmin {\\n constructor(address _wS) VaultAdmin(_wS) {}\\n}\\n\",\"keccak256\":\"0xc0218289301d2bc36ca53e2932aef3332547b12feb80e616da4d44d8e886422e\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultAdmin contract\\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\nimport \\\"./VaultCore.sol\\\";\\n\\nabstract contract VaultAdmin is VaultCore {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n using SafeCast for uint256;\\n\\n /**\\n * @dev Verifies that the caller is the Governor or Strategist.\\n */\\n modifier onlyGovernorOrStrategist() {\\n require(\\n msg.sender == strategistAddr || isGovernor(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n constructor(address _asset) VaultCore(_asset) {}\\n\\n /***************************************\\n Configuration\\n ****************************************/\\n /**\\n * @notice Set a buffer of asset to keep in the Vault to handle most\\n * redemptions without needing to spend gas unwinding asset from a Strategy.\\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\\n */\\n function setVaultBuffer(uint256 _vaultBuffer)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_vaultBuffer <= 1e18, \\\"Invalid value\\\");\\n vaultBuffer = _vaultBuffer;\\n emit VaultBufferUpdated(_vaultBuffer);\\n }\\n\\n /**\\n * @notice Sets the minimum amount of OTokens in a mint to trigger an\\n * automatic allocation of funds afterwords.\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setAutoAllocateThreshold(uint256 _threshold)\\n external\\n onlyGovernor\\n {\\n autoAllocateThreshold = _threshold;\\n emit AllocateThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set address of Strategist\\n * @param _address Address of Strategist\\n */\\n function setStrategistAddr(address _address) external onlyGovernor {\\n strategistAddr = _address;\\n emit StrategistUpdated(_address);\\n }\\n\\n /**\\n * @notice Set the address authorized to call `rebase()`.\\n * @param _operator New operator address. May be set to the zero address\\n * to disable operator-initiated rebases.\\n */\\n function setOperatorAddr(address _operator) external onlyGovernor {\\n operatorAddr = _operator;\\n emit OperatorUpdated(_operator);\\n }\\n\\n /**\\n * @notice Set the default Strategy for asset, i.e. the one which\\n * the asset will be automatically allocated to and withdrawn from\\n * @param _strategy Address of the Strategy\\n */\\n function setDefaultStrategy(address _strategy)\\n external\\n onlyGovernorOrStrategist\\n {\\n emit DefaultStrategyUpdated(_strategy);\\n // If its a zero address being passed for the strategy we are removing\\n // the default strategy\\n if (_strategy != address(0)) {\\n // Make sure the strategy meets some criteria\\n require(strategies[_strategy].isSupported, \\\"Strategy not approved\\\");\\n require(\\n IStrategy(_strategy).supportsAsset(asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n }\\n defaultStrategy = _strategy;\\n }\\n\\n /**\\n * @notice Changes the async withdrawal claim period for OETH & superOETHb\\n * @param _delay Delay period (should be between 10 mins to 7 days).\\n * Set to 0 to disable async withdrawals\\n */\\n function setWithdrawalClaimDelay(uint256 _delay) external onlyGovernor {\\n require(\\n _delay == 0 || (_delay >= 10 minutes && _delay <= 15 days),\\n \\\"Invalid claim delay period\\\"\\n );\\n withdrawalClaimDelay = _delay;\\n emit WithdrawalClaimDelayUpdated(_delay);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Set a yield streaming max rate. This spreads yield over\\n * time if it is above the max rate. This is a per rebase APR which\\n * due to compounding differs from the yearly APR. Governance should\\n * consider this fact when picking a desired APR\\n * @param apr in 1e18 notation. 3 * 1e18 = 3% APR\\n */\\n function setRebaseRateMax(uint256 apr) external onlyGovernorOrStrategist {\\n // The old yield will be at the old rate\\n _rebase();\\n // Change the rate\\n uint256 newPerSecond = apr / 100 / 365 days;\\n require(newPerSecond <= MAX_REBASE_PER_SECOND, \\\"Rate too high\\\");\\n rebasePerSecondMax = newPerSecond.toUint64();\\n emit RebasePerSecondMaxChanged(newPerSecond);\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Set the drip duration period\\n * @param _dripDuration Time in seconds to target a constant yield rate\\n */\\n function setDripDuration(uint256 _dripDuration)\\n external\\n onlyGovernorOrStrategist\\n {\\n // The old yield will be at the old rate\\n _rebase();\\n dripDuration = _dripDuration.toUint64();\\n emit DripDurationChanged(_dripDuration);\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /***************************************\\n Strategy Config\\n ****************************************/\\n\\n /**\\n * @notice Add a strategy to the Vault.\\n * @param _addr Address of the strategy to add\\n */\\n function approveStrategy(address _addr) external onlyGovernor {\\n require(!strategies[_addr].isSupported, \\\"Strategy already approved\\\");\\n require(\\n IStrategy(_addr).supportsAsset(asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\\n allStrategies.push(_addr);\\n emit StrategyApproved(_addr);\\n }\\n\\n /**\\n * @notice Remove a strategy from the Vault.\\n * @param _addr Address of the strategy to remove\\n */\\n\\n function removeStrategy(address _addr) external onlyGovernor {\\n require(strategies[_addr].isSupported, \\\"Strategy not approved\\\");\\n require(defaultStrategy != _addr, \\\"Strategy is default for asset\\\");\\n\\n // Initialize strategyIndex with out of bounds result so function will\\n // revert if no valid index found\\n uint256 stratCount = allStrategies.length;\\n uint256 strategyIndex = stratCount;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n if (allStrategies[i] == _addr) {\\n strategyIndex = i;\\n break;\\n }\\n }\\n\\n if (strategyIndex < stratCount) {\\n allStrategies[strategyIndex] = allStrategies[stratCount - 1];\\n allStrategies.pop();\\n\\n // Withdraw all assets BEFORE marking as unsupported so that AMO\\n // strategies can call burnForStrategy/mintForStrategy during withdrawAll\\n IStrategy strategy = IStrategy(_addr);\\n // slither-disable-next-line reentrancy-no-eth\\n strategy.withdrawAll();\\n\\n // Mark the strategy as not supported\\n strategies[_addr].isSupported = false;\\n isMintWhitelistedStrategy[_addr] = false;\\n\\n // 1e13 for 18 decimals. And 1e1(10) for 6 decimals\\n uint256 maxDustBalance = uint256(1e13).scaleBy(assetDecimals, 18);\\n\\n /*\\n * Some strategies are not able to withdraw all of their funds in a synchronous call.\\n * Prevent the possible accidental removal of such strategies before their funds are withdrawn.\\n */\\n require(\\n strategy.checkBalance(asset) < maxDustBalance,\\n \\\"Strategy has funds\\\"\\n );\\n emit StrategyRemoved(_addr);\\n }\\n }\\n\\n /**\\n * @notice Adds a strategy to the mint whitelist.\\n * Reverts if strategy isn't approved on Vault.\\n * @param strategyAddr Strategy address\\n */\\n function addStrategyToMintWhitelist(address strategyAddr)\\n external\\n onlyGovernor\\n {\\n require(strategies[strategyAddr].isSupported, \\\"Strategy not approved\\\");\\n\\n require(\\n !isMintWhitelistedStrategy[strategyAddr],\\n \\\"Already whitelisted\\\"\\n );\\n\\n isMintWhitelistedStrategy[strategyAddr] = true;\\n\\n emit StrategyAddedToMintWhitelist(strategyAddr);\\n }\\n\\n /**\\n * @notice Removes a strategy from the mint whitelist.\\n * @param strategyAddr Strategy address\\n */\\n function removeStrategyFromMintWhitelist(address strategyAddr)\\n external\\n onlyGovernor\\n {\\n // Intentionally skipping `strategies.isSupported` check since\\n // we may wanna remove an address even after removing the strategy\\n\\n require(isMintWhitelistedStrategy[strategyAddr], \\\"Not whitelisted\\\");\\n\\n isMintWhitelistedStrategy[strategyAddr] = false;\\n\\n emit StrategyRemovedFromMintWhitelist(strategyAddr);\\n }\\n\\n /***************************************\\n Strategies\\n ****************************************/\\n\\n /**\\n * @notice Deposit multiple asset from the vault into the strategy.\\n * @param _strategyToAddress Address of the Strategy to deposit asset into.\\n * @param _assets Array of asset address that will be deposited into the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to deposit.\\n */\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _depositToStrategy(_strategyToAddress, _assets, _amounts);\\n }\\n\\n function _depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyToAddress].isSupported,\\n \\\"Invalid to Strategy\\\"\\n );\\n require(\\n _assets.length == 1 && _amounts.length == 1 && _assets[0] == asset,\\n \\\"Only asset is supported\\\"\\n );\\n\\n // Check the there is enough asset to transfer once the backing\\n // asset reserved for the withdrawal queue is accounted for\\n require(\\n _amounts[0] <= _assetAvailable(),\\n \\\"Not enough assets available\\\"\\n );\\n\\n // Send required amount of funds to the strategy\\n IERC20(asset).safeTransfer(_strategyToAddress, _amounts[0]);\\n\\n // Deposit all the funds that have been sent to the strategy\\n IStrategy(_strategyToAddress).depositAll();\\n }\\n\\n /**\\n * @notice Withdraw multiple asset from the strategy to the vault.\\n * @param _strategyFromAddress Address of the Strategy to withdraw asset from.\\n * @param _assets Array of asset address that will be withdrawn from the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to withdraw.\\n */\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _withdrawFromStrategy(\\n address(this),\\n _strategyFromAddress,\\n _assets,\\n _amounts\\n );\\n }\\n\\n /**\\n * @param _recipient can either be a strategy or the Vault\\n */\\n function _withdrawFromStrategy(\\n address _recipient,\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyFromAddress].isSupported,\\n \\\"Invalid from Strategy\\\"\\n );\\n require(_assets.length == _amounts.length, \\\"Parameter length mismatch\\\");\\n\\n uint256 assetCount = _assets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n // Withdraw from Strategy to the recipient\\n IStrategy(_strategyFromAddress).withdraw(\\n _recipient,\\n _assets[i],\\n _amounts[i]\\n );\\n }\\n\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @notice Sets the maximum allowable difference between\\n * total supply and asset' value.\\n */\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\\n maxSupplyDiff = _maxSupplyDiff;\\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\\n }\\n\\n /**\\n * @notice Sets the trusteeAddress that can receive a portion of yield.\\n * Setting to the zero address disables this feature.\\n */\\n function setTrusteeAddress(address _address) external onlyGovernor {\\n trusteeAddress = _address;\\n emit TrusteeAddressChanged(_address);\\n }\\n\\n /**\\n * @notice Sets the TrusteeFeeBps to the percentage of yield that should be\\n * received in basis points.\\n */\\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\\n require(_basis <= 5000, \\\"basis cannot exceed 50%\\\");\\n trusteeFeeBps = _basis;\\n emit TrusteeFeeBpsChanged(_basis);\\n }\\n\\n /***************************************\\n Pause\\n ****************************************/\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent rebasing.\\n */\\n function pauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = true;\\n emit RebasePaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to allow rebasing.\\n */\\n function unpauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = false;\\n emit RebaseUnpaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent capital movement.\\n */\\n function pauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = true;\\n emit CapitalPaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to false to enable capital movement.\\n */\\n function unpauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = false;\\n emit CapitalUnpaused();\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\\n * contract, i.e. mistaken sends.\\n * @param _asset Address for the asset\\n * @param _amount Amount of the asset to transfer\\n */\\n function transferToken(address _asset, uint256 _amount)\\n external\\n onlyGovernor\\n {\\n require(asset != _asset, \\\"Only unsupported asset\\\");\\n IERC20(_asset).safeTransfer(governor(), _amount);\\n }\\n\\n /***************************************\\n Strategies Admin\\n ****************************************/\\n\\n /**\\n * @notice Withdraws all asset from the strategy and sends asset to the Vault.\\n * @param _strategyAddr Strategy address.\\n */\\n function withdrawAllFromStrategy(address _strategyAddr)\\n external\\n onlyGovernorOrStrategist\\n {\\n _withdrawAllFromStrategy(_strategyAddr);\\n }\\n\\n function _withdrawAllFromStrategy(address _strategyAddr) internal virtual {\\n require(\\n strategies[_strategyAddr].isSupported,\\n \\\"Strategy is not supported\\\"\\n );\\n IStrategy strategy = IStrategy(_strategyAddr);\\n strategy.withdrawAll();\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @notice Withdraws all asset from all the strategies and sends asset to the Vault.\\n */\\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\\n _withdrawAllFromStrategies();\\n }\\n\\n function _withdrawAllFromStrategies() internal virtual {\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy(allStrategies[i]).withdrawAll();\\n }\\n _addWithdrawalQueueLiquidity();\\n }\\n}\\n\",\"keccak256\":\"0xa9489d6c1c248bbf2d022d50dcc494f97f85b6d0fe40a13ab8516bd1ffda75ef\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultCore.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultCore contract\\n * @notice The Vault contract stores asset. On a deposit, OTokens will be minted\\n and sent to the depositor. On a withdrawal, OTokens will be burned and\\n asset will be sent to the withdrawer. The Vault accepts deposits of\\n interest from yield bearing strategies which will modify the supply\\n of OTokens.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\n\\nimport \\\"./VaultInitializer.sol\\\";\\n\\nabstract contract VaultCore is VaultInitializer {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n\\n /**\\n * @dev Verifies that the rebasing is not paused.\\n */\\n modifier whenNotRebasePaused() {\\n require(!rebasePaused, \\\"Rebasing paused\\\");\\n _;\\n }\\n\\n /**\\n * @dev Verifies that the deposits are not paused.\\n */\\n modifier whenNotCapitalPaused() {\\n require(!capitalPaused, \\\"Capital paused\\\");\\n _;\\n }\\n\\n constructor(address _asset) VaultInitializer(_asset) {}\\n\\n ////////////////////////////////////////////////////\\n /// MINT / BURN ///\\n ////////////////////////////////////////////////////\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @dev Deprecated: use `mint(uint256 _amount)` instead.\\n * @dev Deprecated: param _asset Address of the asset being deposited\\n * @param _amount Amount of the asset being deposited\\n * @dev Deprecated: param _minimumOusdAmount Minimum OTokens to mint\\n */\\n function mint(\\n address,\\n uint256 _amount,\\n uint256\\n ) external whenNotCapitalPaused nonReentrant {\\n _mint(_amount);\\n }\\n\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @param _amount Amount of the asset being deposited\\n */\\n function mint(uint256 _amount) external whenNotCapitalPaused nonReentrant {\\n _mint(_amount);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @dev Deposit a supported asset and mint OTokens.\\n * @param _amount Amount of the asset being deposited\\n */\\n function _mint(uint256 _amount) internal virtual {\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n\\n // Scale amount to 18 decimals\\n uint256 scaledAmount = _amount.scaleBy(18, assetDecimals);\\n\\n emit Mint(msg.sender, scaledAmount);\\n\\n // Mint oTokens\\n oToken.mint(msg.sender, scaledAmount);\\n\\n IERC20(asset).safeTransferFrom(msg.sender, address(this), _amount);\\n\\n // Give priority to the withdrawal queue for the new asset liquidity\\n _addWithdrawalQueueLiquidity();\\n\\n // Auto-allocate if necessary\\n if (scaledAmount >= autoAllocateThreshold) {\\n _allocate();\\n }\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /**\\n * @notice Mint OTokens for an allowed Strategy\\n * @param _amount Amount of OToken to mint\\n *\\n * Notice: can't use `nonReentrant` modifier since the `mint` function can\\n * call `allocate`, and that can trigger an AMO strategy to call this function\\n * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function mintForStrategy(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n {\\n require(\\n strategies[msg.sender].isSupported == true,\\n \\\"Unsupported strategy\\\"\\n );\\n require(\\n isMintWhitelistedStrategy[msg.sender] == true,\\n \\\"Not whitelisted strategy\\\"\\n );\\n\\n emit Mint(msg.sender, _amount);\\n // Mint matching amount of OTokens\\n oToken.mint(msg.sender, _amount);\\n }\\n\\n /**\\n * @notice Burn OTokens for an allowed Strategy\\n * @param _amount Amount of OToken to burn\\n *\\n * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could\\n * require withdrawal on an AMO strategy and that one can call `burnForStrategy`\\n * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function burnForStrategy(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n {\\n require(\\n strategies[msg.sender].isSupported == true,\\n \\\"Unsupported strategy\\\"\\n );\\n require(\\n isMintWhitelistedStrategy[msg.sender] == true,\\n \\\"Not whitelisted strategy\\\"\\n );\\n\\n emit Redeem(msg.sender, _amount);\\n\\n // Burn OTokens\\n oToken.burn(msg.sender, _amount);\\n }\\n\\n ////////////////////////////////////////////////////\\n /// ASYNC WITHDRAWALS ///\\n ////////////////////////////////////////////////////\\n /**\\n * @notice Request an asynchronous withdrawal of asset in exchange for OToken.\\n * The OToken is burned on request and the asset is transferred to the withdrawer on claim.\\n * This request can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal this request's `queued` amount.\\n * There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs\\n * enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue.\\n * OToken is converted to asset at 1:1.\\n * @param _amount Amount of OToken to burn.\\n * @return requestId Unique ID for the withdrawal request\\n * @return queued Cumulative total of all asset queued including already claimed requests.\\n */\\n function requestWithdrawal(uint256 _amount)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 requestId, uint256 queued)\\n {\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n require(withdrawalClaimDelay > 0, \\\"Async withdrawals not enabled\\\");\\n\\n // The check that the requester has enough OToken is done in to later burn call\\n\\n requestId = withdrawalQueueMetadata.nextWithdrawalIndex;\\n queued =\\n withdrawalQueueMetadata.queued +\\n _amount.scaleBy(assetDecimals, 18);\\n\\n // Store the next withdrawal request\\n withdrawalQueueMetadata.nextWithdrawalIndex = SafeCast.toUint128(\\n requestId + 1\\n );\\n // Store the updated queued amount which reserves asset in the withdrawal queue\\n // and reduces the vault's total asset\\n withdrawalQueueMetadata.queued = SafeCast.toUint128(queued);\\n // Store the user's withdrawal request\\n // `queued` is in asset decimals, while `amount` is in OToken decimals (18)\\n withdrawalRequests[requestId] = WithdrawalRequest({\\n withdrawer: msg.sender,\\n claimed: false,\\n timestamp: uint40(block.timestamp),\\n amount: SafeCast.toUint128(_amount),\\n queued: SafeCast.toUint128(queued)\\n });\\n\\n // Burn the user's OToken\\n oToken.burn(msg.sender, _amount);\\n\\n // Prevent withdrawal if the vault is solvent by more than the allowed percentage\\n _postRedeem();\\n\\n emit WithdrawalRequested(msg.sender, requestId, _amount, queued);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n /**\\n * @notice Claim a previously requested withdrawal once it is claimable.\\n * This request can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal this request's `queued` amount and 10 minutes has passed.\\n * If the requests is not claimable, the transaction will revert with `Queue pending liquidity`.\\n * If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`.\\n * OToken is converted to asset at 1:1.\\n * @param _requestId Unique ID for the withdrawal request\\n * @return amount Amount of asset transferred to the withdrawer\\n */\\n function claimWithdrawal(uint256 _requestId)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 amount)\\n {\\n // Try and get more liquidity if there is not enough available\\n if (\\n withdrawalRequests[_requestId].queued >\\n withdrawalQueueMetadata.claimable\\n ) {\\n // Add any asset to the withdrawal queue\\n // this needs to remain here as:\\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\\n // - funds can be withdrawn from a strategy\\n //\\n // Those funds need to be added to withdrawal queue liquidity\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n // Scale amount to asset decimals\\n amount = _claimWithdrawal(_requestId);\\n\\n // transfer asset from the vault to the withdrawer\\n IERC20(asset).safeTransfer(msg.sender, amount);\\n\\n // Prevent insolvency\\n _postRedeem();\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n /**\\n * @notice Claim a previously requested withdrawals once they are claimable.\\n * This requests can be claimed once the withdrawal queue's `claimable` amount\\n * is greater than or equal each request's `queued` amount and 10 minutes has passed.\\n * If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`.\\n * If one of the requests is not older than 10 minutes,\\n * the whole transaction will revert with `Claim delay not met`.\\n * @param _requestIds Unique ID of each withdrawal request\\n * @return amounts Amount of asset received for each request\\n * @return totalAmount Total amount of asset transferred to the withdrawer\\n */\\n function claimWithdrawals(uint256[] calldata _requestIds)\\n external\\n virtual\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256[] memory amounts, uint256 totalAmount)\\n {\\n // Add any asset to the withdrawal queue\\n // this needs to remain here as:\\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\\n // - funds can be withdrawn from a strategy\\n //\\n // Those funds need to be added to withdrawal queue liquidity\\n _addWithdrawalQueueLiquidity();\\n\\n amounts = new uint256[](_requestIds.length);\\n for (uint256 i; i < _requestIds.length; ++i) {\\n // Scale all amounts to asset decimals, thus totalAmount is also in asset decimals\\n amounts[i] = _claimWithdrawal(_requestIds[i]);\\n totalAmount += amounts[i];\\n }\\n\\n // transfer all the claimed asset from the vault to the withdrawer\\n IERC20(asset).safeTransfer(msg.sender, totalAmount);\\n\\n // Prevent insolvency\\n _postRedeem();\\n\\n return (amounts, totalAmount);\\n }\\n\\n function _claimWithdrawal(uint256 requestId)\\n internal\\n returns (uint256 amount)\\n {\\n require(withdrawalClaimDelay > 0, \\\"Async withdrawals not enabled\\\");\\n\\n // Load the structs from storage into memory\\n WithdrawalRequest memory request = withdrawalRequests[requestId];\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n require(\\n request.timestamp + withdrawalClaimDelay <= block.timestamp,\\n \\\"Claim delay not met\\\"\\n );\\n // If there isn't enough reserved liquidity in the queue to claim\\n require(request.queued <= queue.claimable, \\\"Queue pending liquidity\\\");\\n require(request.withdrawer == msg.sender, \\\"Not requester\\\");\\n require(request.claimed == false, \\\"Already claimed\\\");\\n\\n // Store the request as claimed\\n withdrawalRequests[requestId].claimed = true;\\n // Store the updated claimed amount\\n withdrawalQueueMetadata.claimed =\\n queue.claimed +\\n SafeCast.toUint128(\\n StableMath.scaleBy(request.amount, assetDecimals, 18)\\n );\\n\\n emit WithdrawalClaimed(msg.sender, requestId, request.amount);\\n\\n return StableMath.scaleBy(request.amount, assetDecimals, 18);\\n }\\n\\n function _postRedeem() internal view {\\n // Until we can prove that we won't affect the prices of our asset\\n // by withdrawing them, this should be here.\\n // It's possible that a strategy was off on its asset total, perhaps\\n // a reward token sold for more or for less than anticipated.\\n uint256 totalUnits = _totalValue();\\n\\n // Check that the OTokens are backed by enough asset\\n if (maxSupplyDiff > 0) {\\n // If there are more outstanding withdrawal requests than asset in the vault and strategies\\n // then the available asset will be negative and totalUnits will be rounded up to zero.\\n // As we don't know the exact shortfall amount, we will reject all redeem and withdrawals\\n require(totalUnits > 0, \\\"Too many outstanding requests\\\");\\n\\n // Allow a max difference of maxSupplyDiff% between\\n // asset value and OUSD total supply\\n uint256 diff = oToken.totalSupply().divPrecisely(totalUnits);\\n require(\\n (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,\\n \\\"Backing supply liquidity error\\\"\\n );\\n }\\n }\\n\\n /**\\n * @notice Allocate unallocated funds on Vault to strategies.\\n */\\n function allocate() external virtual whenNotCapitalPaused nonReentrant {\\n // Add any unallocated asset to the withdrawal queue first\\n _addWithdrawalQueueLiquidity();\\n\\n _allocate();\\n }\\n\\n /**\\n * @dev Allocate asset (eg. WETH or USDC) to the default asset strategy\\n * if there is excess to the Vault buffer.\\n * This is called from either `mint` or `allocate` and assumes `_addWithdrawalQueueLiquidity`\\n * has been called before this function.\\n */\\n function _allocate() internal virtual {\\n // No need to do anything if no default strategy for asset\\n address depositStrategyAddr = defaultStrategy;\\n if (depositStrategyAddr == address(0)) return;\\n\\n uint256 assetAvailableInVault = _assetAvailable();\\n // No need to do anything if there isn't any asset in the vault to allocate\\n if (assetAvailableInVault == 0) return;\\n\\n // Calculate the target buffer for the vault using the total supply\\n uint256 totalSupply = oToken.totalSupply();\\n // Scaled to asset decimals\\n uint256 targetBuffer = totalSupply.mulTruncate(vaultBuffer).scaleBy(\\n assetDecimals,\\n 18\\n );\\n\\n // If available asset in the Vault is below or equal the target buffer then there's nothing to allocate\\n if (assetAvailableInVault <= targetBuffer) return;\\n\\n // The amount of asset to allocate to the default strategy\\n uint256 allocateAmount = assetAvailableInVault - targetBuffer;\\n\\n IStrategy strategy = IStrategy(depositStrategyAddr);\\n // Transfer asset to the strategy and call the strategy's deposit function\\n IERC20(asset).safeTransfer(address(strategy), allocateAmount);\\n strategy.deposit(asset, allocateAmount);\\n\\n emit AssetAllocated(asset, depositStrategyAddr, allocateAmount);\\n }\\n\\n /**\\n * @notice Calculate the total value of asset held by the Vault and all\\n * strategies and update the supply of OTokens.\\n * @dev Restricted to the Operator, Strategist or Governor.\\n */\\n function rebase() external virtual nonReentrant {\\n require(\\n msg.sender == operatorAddr ||\\n msg.sender == strategistAddr ||\\n isGovernor(),\\n \\\"Caller not authorized\\\"\\n );\\n _rebase();\\n }\\n\\n /**\\n * @dev Calculate the total value of asset held by the Vault and all\\n * strategies and update the supply of OTokens, optionally sending a\\n * portion of the yield to the trustee.\\n * @return totalUnits Total balance of Vault in units\\n */\\n function _rebase() internal whenNotRebasePaused returns (uint256) {\\n uint256 supply = oToken.totalSupply();\\n uint256 vaultValue = _totalValue();\\n // If no supply yet, do not rebase\\n if (supply == 0) {\\n return vaultValue;\\n }\\n\\n // Calculate yield and new supply\\n (uint256 yield, uint256 targetRate) = _nextYield(supply, vaultValue);\\n uint256 newSupply = supply + yield;\\n // Only rebase upwards and if we have enough backing funds\\n if (newSupply <= supply || newSupply > vaultValue) {\\n return vaultValue;\\n }\\n\\n rebasePerSecondTarget = uint64(_min(targetRate, type(uint64).max));\\n lastRebase = uint64(block.timestamp); // Intentional cast\\n\\n // Fee collection on yield\\n address _trusteeAddress = trusteeAddress; // gas savings\\n uint256 fee = 0;\\n if (_trusteeAddress != address(0)) {\\n fee = (yield * trusteeFeeBps) / 1e4;\\n if (fee > 0) {\\n require(fee < yield, \\\"Fee must not be greater than yield\\\");\\n oToken.mint(_trusteeAddress, fee);\\n }\\n }\\n emit YieldDistribution(_trusteeAddress, yield, fee);\\n\\n // Only ratchet OToken supply upwards\\n // Final check uses latest totalSupply\\n if (newSupply > oToken.totalSupply()) {\\n oToken.changeSupply(newSupply);\\n }\\n return vaultValue;\\n }\\n\\n /**\\n * @notice Calculates the amount that would rebase at next rebase.\\n * This is before any fees.\\n * @return yield amount of expected yield\\n */\\n function previewYield() external view returns (uint256 yield) {\\n (yield, ) = _nextYield(oToken.totalSupply(), _totalValue());\\n return yield;\\n }\\n\\n /**\\n * @dev Calculates the amount that would rebase at next rebase.\\n * See this Readme for detailed explanation:\\n * contracts/contracts/vault/README - Yield Limits.md\\n */\\n function _nextYield(uint256 supply, uint256 vaultValue)\\n internal\\n view\\n virtual\\n returns (uint256 yield, uint256 targetRate)\\n {\\n uint256 nonRebasing = oToken.nonRebasingSupply();\\n uint256 rebasing = supply - nonRebasing;\\n uint256 elapsed = block.timestamp - lastRebase;\\n targetRate = rebasePerSecondTarget;\\n\\n if (\\n elapsed == 0 || // Yield only once per block.\\n rebasing == 0 || // No yield if there are no rebasing tokens to give it to.\\n supply > vaultValue || // No yield if we do not have yield to give.\\n block.timestamp >= type(uint64).max // No yield if we are too far in the future to calculate it correctly.\\n ) {\\n return (0, targetRate);\\n }\\n\\n // Start with the full difference available\\n yield = vaultValue - supply;\\n\\n // Cap via optional automatic duration smoothing\\n uint256 _dripDuration = dripDuration;\\n if (_dripDuration > 1) {\\n // If we are able to sustain an increased drip rate for\\n // double the duration, then increase the target drip rate\\n targetRate = _max(targetRate, yield / (_dripDuration * 2));\\n // If we cannot sustain the target rate any more,\\n // then rebase what we can, and reduce the target\\n targetRate = _min(targetRate, yield / _dripDuration);\\n // drip at the new target rate\\n yield = _min(yield, targetRate * elapsed);\\n }\\n\\n // Cap per second. elapsed is not 1e18 denominated\\n yield = _min(yield, (rebasing * elapsed * rebasePerSecondMax) / 1e18);\\n\\n // Cap at a hard max per rebase, to avoid long durations resulting in huge rebases\\n yield = _min(yield, (rebasing * MAX_REBASE) / 1e18);\\n\\n return (yield, targetRate);\\n }\\n\\n /**\\n * @notice Determine the total value of asset held by the vault and its\\n * strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function totalValue() external view virtual returns (uint256 value) {\\n value = _totalValue();\\n }\\n\\n /**\\n * @dev Internal Calculate the total value of the asset held by the\\n * vault and its strategies.\\n * @dev The total value of all WETH held by the vault and all its strategies\\n * less any WETH that is reserved for the withdrawal queue.\\n * If there is not enough WETH in the vault and all strategies to cover\\n * all outstanding withdrawal requests then return a total value of 0.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValue() internal view virtual returns (uint256 value) {\\n // As asset is the only asset, just return the asset balance\\n value = _checkBalance(asset).scaleBy(18, assetDecimals);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @param _asset Address of asset\\n * @return uint256 Balance of asset in decimals of asset\\n */\\n function checkBalance(address _asset) external view returns (uint256) {\\n return _checkBalance(_asset);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @dev Get the balance of an asset held in Vault and all strategies\\n * less any asset that is reserved for the withdrawal queue.\\n * BaseAsset is the only asset that can return a non-zero balance.\\n * All other asset will return 0 even if there is some dust amounts left in the Vault.\\n * For example, there is 1 wei left of stETH (or USDC) in the OETH (or OUSD) Vault but\\n * will return 0 in this function.\\n *\\n * If there is not enough asset in the vault and all strategies to cover all outstanding\\n * withdrawal requests then return a asset balance of 0\\n * @param _asset Address of asset\\n * @return balance Balance of asset in decimals of asset\\n */\\n function _checkBalance(address _asset)\\n internal\\n view\\n virtual\\n returns (uint256 balance)\\n {\\n if (_asset != asset) return 0;\\n\\n // Get the asset in the vault and the strategies\\n IERC20 asset = IERC20(_asset);\\n balance = asset.balanceOf(address(this));\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy strategy = IStrategy(allStrategies[i]);\\n if (strategy.supportsAsset(_asset)) {\\n balance = balance + strategy.checkBalance(_asset);\\n }\\n }\\n\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // If the vault becomes insolvent enough that the total value in the vault and all strategies\\n // is less than the outstanding withdrawals.\\n // For example, there was a mass slashing event and most users request a withdrawal.\\n if (balance + queue.claimed < queue.queued) {\\n return 0;\\n }\\n\\n // Need to remove asset that is reserved for the withdrawal queue\\n return balance + queue.claimed - queue.queued;\\n }\\n\\n /**\\n * @notice Adds WETH to the withdrawal queue if there is a funding shortfall.\\n * @dev is called from the Native Staking strategy when validator withdrawals are processed.\\n * It also called before any WETH is allocated to a strategy.\\n */\\n function addWithdrawalQueueLiquidity() external {\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /**\\n * @dev Adds asset (eg. WETH or USDC) to the withdrawal queue if there is a funding shortfall.\\n * This assumes 1 asset equal 1 corresponding OToken.\\n */\\n function _addWithdrawalQueueLiquidity()\\n internal\\n returns (uint256 addedClaimable)\\n {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // Check if the claimable asset is less than the queued amount\\n uint256 queueShortfall = queue.queued - queue.claimable;\\n\\n // No need to do anything is the withdrawal queue is full funded\\n if (queueShortfall == 0) {\\n return 0;\\n }\\n\\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\\n\\n // Of the claimable withdrawal requests, how much is unclaimed?\\n // That is, the amount of asset that is currently allocated for the withdrawal queue\\n uint256 allocatedBaseAsset = queue.claimable - queue.claimed;\\n\\n // If there is no unallocated asset then there is nothing to add to the queue\\n if (assetBalance <= allocatedBaseAsset) {\\n return 0;\\n }\\n\\n uint256 unallocatedBaseAsset = assetBalance - allocatedBaseAsset;\\n // the new claimable amount is the smaller of the queue shortfall or unallocated asset\\n addedClaimable = queueShortfall < unallocatedBaseAsset\\n ? queueShortfall\\n : unallocatedBaseAsset;\\n uint256 newClaimable = queue.claimable + addedClaimable;\\n\\n // Store the new claimable amount back to storage\\n withdrawalQueueMetadata.claimable = SafeCast.toUint128(newClaimable);\\n\\n // emit a WithdrawalClaimable event\\n emit WithdrawalClaimable(newClaimable, addedClaimable);\\n }\\n\\n /**\\n * @dev Calculate how much asset (eg. WETH or USDC) in the vault is not reserved for the withdrawal queue.\\n * That is, it is available to be redeemed or deposited into a strategy.\\n */\\n function _assetAvailable() internal view returns (uint256 assetAvailable) {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // The amount of asset that is still to be claimed in the withdrawal queue\\n uint256 outstandingWithdrawals = queue.queued - queue.claimed;\\n\\n // The amount of sitting in asset in the vault\\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\\n // If there is not enough asset in the vault to cover the outstanding withdrawals\\n if (assetBalance <= outstandingWithdrawals) return 0;\\n\\n return assetBalance - outstandingWithdrawals;\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Return the number of asset supported by the Vault.\\n */\\n function getAssetCount() public view returns (uint256) {\\n return 1;\\n }\\n\\n /**\\n * @notice Return all vault asset addresses in order\\n */\\n function getAllAssets() external view returns (address[] memory) {\\n address[] memory a = new address[](1);\\n a[0] = asset;\\n return a;\\n }\\n\\n /**\\n * @notice Return the number of strategies active on the Vault.\\n */\\n function getStrategyCount() external view returns (uint256) {\\n return allStrategies.length;\\n }\\n\\n /**\\n * @notice Return the array of all strategies\\n */\\n function getAllStrategies() external view returns (address[] memory) {\\n return allStrategies;\\n }\\n\\n /**\\n * @notice Returns whether the vault supports the asset\\n * @param _asset address of the asset\\n * @return true if supported\\n */\\n function isSupportedAsset(address _asset) external view returns (bool) {\\n return asset == _asset;\\n }\\n\\n function _min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n function _max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a > b ? a : b;\\n }\\n}\\n\",\"keccak256\":\"0xc2080a50088fc275eddea5784cef6a561280918679c846de48a8983613acf56e\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultInitializer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultInitializer contract\\n * @notice The Vault contract initializes the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport \\\"./VaultStorage.sol\\\";\\n\\nabstract contract VaultInitializer is VaultStorage {\\n constructor(address _asset) VaultStorage(_asset) {}\\n\\n function initialize(address _oToken) external onlyGovernor initializer {\\n require(_oToken != address(0), \\\"oToken address is zero\\\");\\n\\n oToken = OUSD(_oToken);\\n\\n rebasePaused = false;\\n capitalPaused = true;\\n\\n // Initial Vault buffer of 0%\\n vaultBuffer = 0;\\n // Initial allocate threshold of 25,000 OUSD\\n autoAllocateThreshold = 25000e18;\\n // Initialize all strategies\\n allStrategies = new address[](0);\\n // Start with drip duration: 7 days\\n dripDuration = 604800;\\n }\\n}\\n\",\"keccak256\":\"0x5198442b36146a9c1c1f38294866f4b3a12344ccf67dd9dd2e3958243bbd9c98\",\"license\":\"BUSL-1.1\"},\"contracts/vault/VaultStorage.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultStorage contract\\n * @notice The VaultStorage contract defines the storage for the Vault contracts\\n * @author Origin Protocol Inc\\n */\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { IERC20Metadata } from \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { OUSD } from \\\"../token/OUSD.sol\\\";\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport \\\"../utils/Helpers.sol\\\";\\n\\nabstract contract VaultStorage is Initializable, Governable {\\n using SafeERC20 for IERC20;\\n\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event DefaultStrategyUpdated(address _strategy);\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event StrategyAddedToMintWhitelist(address indexed strategy);\\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\\n event DripDurationChanged(uint256 dripDuration);\\n event OperatorUpdated(address newOperator);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\\n\\n // Since we are proxy, all state should be uninitalized.\\n // Since this storage contract does not have logic directly on it\\n // we should not be checking for to see if these variables can be constant.\\n // slither-disable-start uninitialized-state\\n // slither-disable-start constable-states\\n\\n /// @dev mapping of supported vault assets to their configuration\\n uint256 private _deprecated_assets;\\n /// @dev list of all assets supported by the vault.\\n address[] private _deprecated_allAssets;\\n\\n // Strategies approved for use by the Vault\\n struct Strategy {\\n bool isSupported;\\n uint256 _deprecated; // Deprecated storage slot\\n }\\n /// @dev mapping of strategy contracts to their configuration\\n mapping(address => Strategy) public strategies;\\n /// @dev list of all vault strategies\\n address[] internal allStrategies;\\n\\n /// @notice Address of the Oracle price provider contract\\n address private _deprecated_priceProvider;\\n /// @notice pause rebasing if true\\n bool public rebasePaused;\\n /// @notice pause operations that change the OToken supply.\\n /// eg mint, redeem, allocate, mint/burn for strategy\\n bool public capitalPaused;\\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\\n uint256 private _deprecated_redeemFeeBps;\\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\\n uint256 public vaultBuffer;\\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\\n uint256 public autoAllocateThreshold;\\n /// @dev Deprecated. Was the auto-rebase trigger threshold for mint/redeem.\\n /// Storage slot retained for proxy compatibility; no longer read or written.\\n uint256 internal __deprecatedRebaseThreshold;\\n\\n /// @dev Address of the OToken token. eg OUSD or OETH.\\n OUSD public oToken;\\n\\n /// @dev Address of the contract responsible for post rebase syncs with AMMs\\n address private _deprecated_rebaseHooksAddr = address(0);\\n\\n /// @dev Deprecated: Address of Uniswap\\n address private _deprecated_uniswapAddr = address(0);\\n\\n /// @notice Address of the Strategist\\n address public strategistAddr = address(0);\\n\\n /// @notice Mapping of asset address to the Strategy that they should automatically\\n // be allocated to\\n uint256 private _deprecated_assetDefaultStrategies;\\n\\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\\n uint256 public maxSupplyDiff;\\n\\n /// @notice Trustee contract that can collect a percentage of yield\\n address public trusteeAddress;\\n\\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\\n uint256 public trusteeFeeBps;\\n\\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\\n address[] private _deprecated_swapTokens;\\n\\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\\n\\n address private _deprecated_ousdMetaStrategy;\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n int256 private _deprecated_netOusdMintedForStrategy;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n uint256 private _deprecated_netOusdMintForStrategyThreshold;\\n\\n uint256 private _deprecated_swapConfig;\\n\\n // List of strategies that can mint oTokens directly\\n // Used in OETHBaseVaultCore\\n mapping(address => bool) public isMintWhitelistedStrategy;\\n\\n /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\\n /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\\n address private _deprecated_dripper;\\n\\n /// Withdrawal Queue Storage /////\\n\\n struct WithdrawalQueueMetadata {\\n // cumulative total of all withdrawal requests included the ones that have already been claimed\\n uint128 queued;\\n // cumulative total of all the requests that can be claimed including the ones that have already been claimed\\n uint128 claimable;\\n // total of all the requests that have been claimed\\n uint128 claimed;\\n // index of the next withdrawal request starting at 0\\n uint128 nextWithdrawalIndex;\\n }\\n\\n /// @notice Global metadata for the withdrawal queue including:\\n /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed\\n /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed\\n /// claimed - total of all the requests that have been claimed\\n /// nextWithdrawalIndex - index of the next withdrawal request starting at 0\\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\\n\\n struct WithdrawalRequest {\\n address withdrawer;\\n bool claimed;\\n uint40 timestamp; // timestamp of the withdrawal request\\n // Amount of oTokens to redeem. eg OETH\\n uint128 amount;\\n // cumulative total of all withdrawal requests including this one.\\n // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\\n uint128 queued;\\n }\\n\\n /// @notice Mapping of withdrawal request indices to the user withdrawal request data\\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\\n\\n /// @notice Sets a minimum delay that is required to elapse between\\n /// requesting async withdrawals and claiming the request.\\n /// When set to 0 async withdrawals are disabled.\\n uint256 public withdrawalClaimDelay;\\n\\n /// @notice Time in seconds that the vault last rebased yield.\\n uint64 public lastRebase;\\n\\n /// @notice Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\\n uint64 public dripDuration;\\n\\n /// @notice max rebase percentage per second\\n /// Can be used to set maximum yield of the protocol,\\n /// spreading out yield over time\\n uint64 public rebasePerSecondMax;\\n\\n /// @notice target rebase rate limit, based on past rates and funds available.\\n uint64 public rebasePerSecondTarget;\\n\\n uint256 internal constant MAX_REBASE = 0.02 ether;\\n uint256 internal constant MAX_REBASE_PER_SECOND =\\n uint256(0.05 ether) / 1 days;\\n\\n /// @notice Default strategy for asset\\n address public defaultStrategy;\\n\\n /// @notice Address authorized to call `rebase()` directly. The Governor\\n /// and Strategist are always allowed in addition to this address.\\n address public operatorAddr;\\n\\n // For future use\\n uint256[41] private __gap;\\n\\n /// @notice Index of WETH asset in allAssets array\\n /// Legacy OETHVaultCore code, relocated here for vault consistency.\\n uint256 private _deprecated_wethAssetIndex;\\n\\n /// @dev Address of the asset (eg. WETH or USDC)\\n address public immutable asset;\\n uint8 internal immutable assetDecimals;\\n\\n // slither-disable-end constable-states\\n // slither-disable-end uninitialized-state\\n\\n constructor(address _asset) {\\n uint8 _decimals = IERC20Metadata(_asset).decimals();\\n require(_decimals <= 18, \\\"invalid asset decimals\\\");\\n asset = _asset;\\n assetDecimals = _decimals;\\n }\\n\\n /// @notice Deprecated: use `oToken()` instead.\\n function oUSD() external view returns (OUSD) {\\n return oToken;\\n }\\n}\\n\",\"keccak256\":\"0x9245e680c777afc86fc97e0101940bd0d702b206e49b940c42c574be92860e4f\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x60c0604052603d80546001600160a01b0319908116909155603e805482169055603f8054909116905534801561003457600080fd5b5060405161541938038061541983398101604081905261005391610133565b808080806000816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100bb9190610163565b905060128160ff1611156101155760405162461bcd60e51b815260206004820152601660248201527f696e76616c696420617373657420646563696d616c7300000000000000000000604482015260640160405180910390fd5b6001600160a01b0390911660805260ff1660a0525061018692505050565b60006020828403121561014557600080fd5b81516001600160a01b038116811461015c57600080fd5b9392505050565b60006020828403121561017557600080fd5b815160ff8116811461015c57600080fd5b60805160a0516151c661025360003960008181610fbb015281816120ac0152818161319201528181613773015281816138170152818161408f01526144440152600081816105870152818161088b01528181610c5801528181610ff9015281816112e80152818161144d0152818161176c0152818161187a01528181612ca1015281816132630152818161339101528181613ae601528181613dbb01528181613ef2015281816140fa01528181614145015281816141ad0152818161446b01526148a601526151c66000f3fe608060405234801561001057600080fd5b50600436106104075760003560e01c8063663e64ce11610220578063ae69f3cb11610130578063c7af3352116100b8578063e6cc543211610087578063e6cc5432146109e5578063ea33b8e4146109f9578063f3f18c3714610a01578063f844443614610a14578063fac5bb9b14610a2757600080fd5b8063c7af3352146109ba578063c9919112146109c2578063d38bfff4146109ca578063d4c3eea0146109dd57600080fd5b8063b9b17f9f116100ff578063b9b17f9f14610975578063bb7a632e1461097d578063c3b2886414610997578063c4d66de81461099f578063c5f00841146109b257600080fd5b8063ae69f3cb14610934578063af14052c14610947578063b2c9336d1461094f578063b4925a201461096257600080fd5b806395b166bc116101b35780639fa1826e116101825780639fa1826e146108f6578063a0712d68146108ff578063a0aead4d14610912578063ab80dafb14610919578063abaa99161461092c57600080fd5b806395b166bc146108685780639be918e61461087b5780639e428552146108bb5780639ee679e8146108ce57600080fd5b80638e510b52116101ef5780638e510b521461079c5780638ec489a2146107a5578063937b2581146107b857806394828ffd1461086057600080fd5b8063663e64ce14610750578063773540b31461076357806378f353a114610776578063840c4c7a1461078957600080fd5b806339ebf8231161031b578063527e83a8116102ae5780635802a1721161027d5780635802a172146106fe578063597c89101461070f5780635d36b190146107225780635f5152261461072a5780636217f3ea1461073d57600080fd5b8063527e83a8146106aa57806353ca9f24146106c4578063570d8e1d146106d857806357bee944146106eb57600080fd5b806345e4213b116102ea57806345e4213b1461063b57806348e30f541461064457806349c1d54d146106655780634d5f46291461067857600080fd5b806339ebf823146105a95780633b8ae397146105ed5780633dbc911f146106005780634530820a1461060857600080fd5b80631a32aad61161039e5780632acada4d1161036d5780632acada4d146104f35780632da845a81461050857806331e19cfa1461051b578063362bd1a31461052357806338d52e0f1461058257600080fd5b80631a32aad6146104ad5780631cfbe7bc146104c05780631edfe3da146104d3578063207134b0146104ea57600080fd5b80631072cbea116103da5780631072cbea14610461578063156e29f614610474578063175188e8146104875780631816dd4a1461049a57600080fd5b80630493a0fa1461040c57806309f49bf5146104215780630acbda75146104295780630c340a241461043c575b600080fd5b61041f61041a366004614b54565b610a3a565b005b61041f610af0565b61041f610437366004614b54565b610b60565b610444610c0b565b6040516001600160a01b0390911681526020015b60405180910390f35b61041f61046f366004614b89565b610c28565b61041f610482366004614bb3565b610ce6565b61041f610495366004614be6565b610d59565b61041f6104a8366004614be6565b6110f7565b603c54610444906001600160a01b031681565b61041f6104ce366004614b54565b6111fe565b6104dc60395481565b604051908152602001610458565b6104dc60435481565b6104fb6112c0565b6040516104589190614c01565b61041f610516366004614be6565b611337565b6036546104dc565b604b54604c5461054f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610458565b6104447f000000000000000000000000000000000000000000000000000000000000000081565b6105d66105b7366004614be6565b6035602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610458565b61041f6105fb366004614be6565b6113a9565b61041f6115bc565b61062b610616366004614be6565b60496020526000908152604090205460ff1681565b6040519015158152602001610458565b6104dc604e5481565b610657610652366004614c91565b611632565b604051610458929190614cd2565b604254610444906001600160a01b031681565b604f5461069290600160c01b90046001600160401b031681565b6040516001600160401b039091168152602001610458565b604f5461069290600160801b90046001600160401b031681565b60375461062b90600160a01b900460ff1681565b603f54610444906001600160a01b031681565b61041f6106f9366004614be6565b6117a8565b603c546001600160a01b0316610444565b61041f61071d366004614be6565b61195b565b61041f61199f565b6104dc610738366004614be6565b611a45565b61041f61074b366004614b54565b611a56565b61041f61075e366004614b54565b611bda565b61041f610771366004614be6565b611c33565b604f54610692906001600160401b031681565b61041f610797366004614d1f565b611ca5565b6104dc60415481565b61041f6107b3366004614b54565b611d2c565b6108196107c6366004614b54565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a001610458565b61041f611de1565b61041f610876366004614be6565b611e51565b61062b610889366004614be6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b61041f6108c9366004614be6565b611f18565b6108e16108dc366004614b54565b611f8a565b60408051928352602083019190915201610458565b6104dc603a5481565b61041f61090d366004614b54565b6122ca565b60016104dc565b61041f610927366004614b54565b61233b565b61041f61248a565b61041f610942366004614d1f565b612502565b61041f61257e565b61041f61095d366004614b54565b612639565b61041f610970366004614b54565b612692565b61041f6127b0565b604f5461069290600160401b90046001600160401b031681565b6104fb6127b8565b61041f6109ad366004614be6565b61281a565b61041f6129c5565b61062b612a3b565b61041f612a6c565b61041f6109d8366004614be6565b612aac565b6104dc612b50565b60375461062b90600160a81b900460ff1681565b6104dc612b5a565b605154610444906001600160a01b031681565b6104dc610a22366004614b54565b612be9565b605054610444906001600160a01b031681565b603f546001600160a01b0316331480610a565750610a56612a3b565b610a7b5760405162461bcd60e51b8152600401610a7290614da3565b60405180910390fd5b610a83612cda565b50610a8d81613074565b604f80546001600160401b0392909216600160401b0267ffffffffffffffff60401b199092169190911790556040518181527f406e15fbca1d8ded2dbb06765fea3a54f18395c54125a4c9916dd00ea14ee15e906020015b60405180910390a150565b603f546001600160a01b0316331480610b0c5750610b0c612a3b565b610b285760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b610b68612a3b565b610b845760405162461bcd60e51b8152600401610a7290614deb565b611388811115610bd65760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f7420657863656564203530250000000000000000006044820152606401610a72565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c790602001610ae5565b6000610c236000805160206151718339815191525490565b905090565b610c30612a3b565b610c4c5760405162461bcd60e51b8152600401610a7290614deb565b816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610cc65760405162461bcd60e51b815260206004820152601660248201527513db9b1e481d5b9cdd5c1c1bdc9d195908185cdcd95d60521b6044820152606401610a72565b610ce2610cd1610c0b565b6001600160a01b03841690836130e0565b5050565b603754600160a81b900460ff1615610d105760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101610d425760405162461bcd60e51b8152600401610a7290614e4a565b60028255610d4f84613136565b5060019055505050565b610d61612a3b565b610d7d5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff16610db55760405162461bcd60e51b8152600401610a7290614e72565b6050546001600160a01b03808316911603610e125760405162461bcd60e51b815260206004820152601d60248201527f53747261746567792069732064656661756c7420666f722061737365740000006044820152606401610a72565b6036548060005b82811015610e6857836001600160a01b031660368281548110610e3e57610e3e614ea1565b6000918252602090912001546001600160a01b031603610e6057809150610e68565b600101610e19565b50818110156110f2576036610e7e600184614ecd565b81548110610e8e57610e8e614ea1565b600091825260209091200154603680546001600160a01b039092169183908110610eba57610eba614ea1565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610ef957610ef9614ee0565b6001900381819060005260206000200160006101000a8154906001600160a01b03021916905590556000839050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610f6157600080fd5b505af1158015610f75573d6000803e3d6000fd5b505050506001600160a01b0384166000908152603560209081526040808320805460ff199081169091556049909252822080549091169055610fe26509184e72a00060ff7f00000000000000000000000000000000000000000000000000000000000000001660126132a7565b604051632fa8a91360e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192508291841690635f51522690602401602060405180830381865afa15801561104d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110719190614ef6565b106110b35760405162461bcd60e51b81526020600482015260126024820152715374726174656779206861732066756e647360701b6044820152606401610a72565b6040516001600160a01b03861681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49060200160405180910390a150505b505050565b6110ff612a3b565b61111b5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff166111535760405162461bcd60e51b8152600401610a7290614e72565b6001600160a01b03811660009081526049602052604090205460ff16156111b25760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481dda1a5d195b1a5cdd1959606a1b6044820152606401610a72565b6001600160a01b038116600081815260496020526040808220805460ff19166001179055517f47c8c96a5942f094264111c5fe7f6a4fe86efe63254a6fa7afa5fc84f07d58e89190a250565b611206612a3b565b6112225760405162461bcd60e51b8152600401610a7290614deb565b80158061123f5750610258811015801561123f57506213c6808111155b61128b5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636c61696d2064656c617920706572696f640000000000006044820152606401610a72565b604e8190556040518181527fc59f5e32049abab44ddea11021f5abb89422a2f550837afcf25df9fc8d0db6b090602001610ae5565b60408051600180825281830190925260609160009190602080830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061131a5761131a614ea1565b6001600160a01b0390921660209283029190910190910152919050565b61133f612a3b565b61135b5760405162461bcd60e51b8152600401610a7290614deb565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610ae5565b6113b1612a3b565b6113cd5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff16156114365760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f766564000000000000006044820152606401610a72565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa15801561149c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c09190614f25565b61150c5760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a72565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610ae5565b603f546001600160a01b03163314806115d857506115d8612a3b565b6115f45760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b603754606090600090600160a81b900460ff16156116625760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016116945760405162461bcd60e51b8152600401610a7290614e4a565b600282556116a061330b565b50846001600160401b038111156116b9576116b9614f0f565b6040519080825280602002602001820160405280156116e2578160200160208202803683370190505b50935060005b8581101561175e5761171187878381811061170557611705614ea1565b905060200201356134e7565b85828151811061172357611723614ea1565b60200260200101818152505084818151811061174157611741614ea1565b6020026020010151846117549190614f47565b93506001016116e8565b506117936001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130e0565b61179b613848565b6001825550509250929050565b603f546001600160a01b03163314806117c457506117c4612a3b565b6117e05760405162461bcd60e51b8152600401610a7290614da3565b6040516001600160a01b03821681527f45a9e715f8779ebeab88d3e8d081fb8b484b7730857e7c4478a95a5b1d8f79489060200160405180910390a16001600160a01b03811615611939576001600160a01b03811660009081526035602052604090205460ff166118635760405162461bcd60e51b8152600401610a7290614e72565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa1580156118c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ed9190614f25565b6119395760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a72565b605080546001600160a01b0319166001600160a01b0392909216919091179055565b603f546001600160a01b03163314806119775750611977612a3b565b6119935760405162461bcd60e51b8152600401610a7290614da3565b61199c816139bb565b50565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614611a3a5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610a72565b611a4333613a83565b565b6000611a5082613ae2565b92915050565b603754600160a81b900460ff1615611a805760405162461bcd60e51b8152600401610a7290614e22565b3360009081526035602052604090205460ff161515600114611adb5760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a72565b3360009081526049602052604090205460ff161515600114611b3a5760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a72565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051611b6b929190614f5a565b60405180910390a1603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90611ba59033908590600401614f5a565b600060405180830381600087803b158015611bbf57600080fd5b505af1158015611bd3573d6000803e3d6000fd5b5050505050565b611be2612a3b565b611bfe5760405162461bcd60e51b8152600401610a7290614deb565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610ae5565b611c3b612a3b565b611c575760405162461bcd60e51b8152600401610a7290614deb565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610ae5565b603f546001600160a01b0316331480611cc15750611cc1612a3b565b611cdd5760405162461bcd60e51b8152600401610a7290614da3565b60008051602061515183398151915280546001198101611d0f5760405162461bcd60e51b8152600401610a7290614e4a565b60028255611d208787878787613d44565b50600190555050505050565b603f546001600160a01b0316331480611d485750611d48612a3b565b611d645760405162461bcd60e51b8152600401610a7290614da3565b670de0b6b3a7640000811115611dac5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b6044820152606401610a72565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610ae5565b603f546001600160a01b0316331480611dfd5750611dfd612a3b565b611e195760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e59612a3b565b611e755760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526049602052604090205460ff16611ecf5760405162461bcd60e51b815260206004820152600f60248201526e139bdd081dda1a5d195b1a5cdd1959608a1b6044820152606401610a72565b6001600160a01b038116600081815260496020526040808220805460ff19169055517f0ec40967a61509853550658e51d0e4297f7cba244fe4adc8ba18b5631ac20e2f9190a250565b611f20612a3b565b611f3c5760405162461bcd60e51b8152600401610a7290614deb565b605180546001600160a01b0319166001600160a01b0383169081179091556040519081527fb3b3f5f64ab192e4b5fefde1f51ce9733bbdcf831951543b325aebd49cc27ec490602001610ae5565b6037546000908190600160a81b900460ff1615611fb95760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101611feb5760405162461bcd60e51b8152600401610a7290614e4a565b600282556000851161203f5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a72565b6000604e54116120915760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a72565b604c54600160801b90046001600160801b031693506120d5857f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b604b546120eb91906001600160801b0316614f47565b92506121006120fb856001614f47565b613f83565b604c80546001600160801b03928316600160801b02921691909117905561212683613f83565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff16918101919091526060810161217687613f83565b6001600160801b0316815260200161218d85613f83565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906122489033908990600401614f5a565b600060405180830381600087803b15801561226257600080fd5b505af1158015612276573d6000803e3d6000fd5b50505050612282613848565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff16156122f45760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016123265760405162461bcd60e51b8152600401610a7290614e4a565b6002825561233383613136565b506001905550565b603754600160a81b900460ff16156123655760405162461bcd60e51b8152600401610a7290614e22565b3360009081526035602052604090205460ff1615156001146123c05760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a72565b3360009081526049602052604090205460ff16151560011461241f5760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a72565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853382604051612450929190614f5a565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611ba59033908590600401614f5a565b603754600160a81b900460ff16156124b45760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016124e65760405162461bcd60e51b8152600401610a7290614e4a565b600282556124f261330b565b506124fb613fec565b5060019055565b603f546001600160a01b031633148061251e575061251e612a3b565b61253a5760405162461bcd60e51b8152600401610a7290614da3565b6000805160206151518339815191528054600119810161256c5760405162461bcd60e51b8152600401610a7290614e4a565b60028255611d20308888888888614215565b600080516020615151833981519152805460011981016125b05760405162461bcd60e51b8152600401610a7290614e4a565b600282556051546001600160a01b03163314806125d75750603f546001600160a01b031633145b806125e557506125e5612a3b565b6126295760405162461bcd60e51b815260206004820152601560248201527410d85b1b195c881b9bdd08185d5d1a1bdc9a5e9959605a1b6044820152606401610a72565b612631612cda565b505060019055565b612641612a3b565b61265d5760405162461bcd60e51b8152600401610a7290614deb565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610ae5565b603f546001600160a01b03163314806126ae57506126ae612a3b565b6126ca5760405162461bcd60e51b8152600401610a7290614da3565b6126d2612cda565b5060006301e133806126e5606484614f73565b6126ef9190614f73565b90506127056201518066b1a2bc2ec50000614f73565b8111156127445760405162461bcd60e51b815260206004820152600d60248201526c0a4c2e8ca40e8dede40d0d2ced609b1b6044820152606401610a72565b61274d81613074565b604f80546001600160401b0392909216600160801b0267ffffffffffffffff60801b199092169190911790556040518181527fef46f143af5fead0010484fe7d6ec2e2972420faa76157f5a6075aa72e614cb59060200160405180910390a15050565b61199c61330b565b6060603680548060200260200160405190810160405280929190818152602001828054801561281057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116127f2575b5050505050905090565b612822612a3b565b61283e5760405162461bcd60e51b8152600401610a7290614deb565b600054610100900460ff1680612857575060005460ff16155b6128ba5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a72565b600054610100900460ff161580156128dc576000805461ffff19166101011790555b6001600160a01b03821661292b5760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b6044820152606401610a72565b603c80546001600160a01b0384166001600160a01b03199091161790556037805461ffff60a01b1916600160a81b1790556000603981905569054b40b1f852bda00000603a55604080519182526020820190819052905161298e91603691614ae3565b50604f805467ffffffffffffffff60401b19166a093a8000000000000000001790558015610ce2576000805461ff00191690555050565b603f546001600160a01b03163314806129e157506129e1612a3b565b6129fd5760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b6000612a536000805160206151718339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612a885750612a88612a3b565b612aa45760405162461bcd60e51b8152600401610a7290614da3565b611a436143a6565b612ab4612a3b565b612ad05760405162461bcd60e51b8152600401610a7290614deb565b612af8817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612b186000805160206151718339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000610c2361443b565b6000612be3603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd69190614ef6565b612bde61443b565b61448f565b50919050565b603754600090600160a81b900460ff1615612c165760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101612c485760405162461bcd60e51b8152600401610a7290614e4a565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115612c8957612c8761330b565b505b612c92846134e7565b9250612cc86001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130e0565b612cd0613848565b5060019055919050565b603754600090600160a01b900460ff1615612d295760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b6044820152606401610a72565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612d73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d979190614ef6565b90506000612da361443b565b905081600003612db65791506130719050565b600080612dc3848461448f565b90925090506000612dd48386614f47565b90508481111580612de457508381115b15612df3575091949350505050565b612e04826001600160401b03614662565b604f805477ffffffffffffffffffffffffffffffff000000000000000016600160c01b6001600160401b039384160267ffffffffffffffff19161742929092169190911790556042546001600160a01b031660008115612f405761271060435486612e6f9190614f95565b612e799190614f73565b90508015612f4057848110612edb5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b6064820152608401610a72565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612f0d9085908590600401614f5a565b600060405180830381600087803b158015612f2757600080fd5b505af1158015612f3b573d6000803e3d6000fd5b505050505b604080516001600160a01b0384168152602081018790529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a1603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fdd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130019190614ef6565b83111561306757603c546040516339a7919f60e01b8152600481018590526001600160a01b03909116906339a7919f90602401600060405180830381600087803b15801561304e57600080fd5b505af1158015613062573d6000803e3d6000fd5b505050505b5093955050505050505b90565b60006001600160401b038211156130dc5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610a72565b5090565b6110f28363a9059cbb60e01b84846040516024016130ff929190614f5a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614678565b600081116131865760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a72565b60006131b782601260ff7f0000000000000000000000000000000000000000000000000000000000000000166132a7565b90507f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516131ea929190614f5a565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132249033908590600401614f5a565b600060405180830381600087803b15801561323e57600080fd5b505af1158015613252573d6000803e3d6000fd5b5061328d9250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016905033308561474a565b61329561330b565b50603a548110610ce257610ce2613fec565b6000818311156132d7576132d06132be8385614ecd565b6132c990600a615093565b8590614788565b9350613301565b81831015613301576132fe6132ec8484614ecd565b6132f790600a615093565b8590614794565b93505b50825b9392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c548084169686019690965292909404166060830152600092839161335d9161509f565b6001600160801b03169050806000036133795760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156133e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134049190614ef6565b905060008360400151846020015161341c919061509f565b6001600160801b0316905080821161343957600094505050505090565b60006134458284614ecd565b90508084106134545780613456565b835b955060008686602001516001600160801b03166134739190614f47565b905061347e81613f83565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f463333906134d69083908a90918252602082015260400190565b60405180910390a150505050505090565b600080604e541161353a5760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a72565b6000828152604d6020908152604091829020825160a08101845281546001600160a01b038116825260ff600160a01b82041615158285015264ffffffffff600160a81b90910481168286019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915288519081018952604b548084168252849004831697810197909752604c54808316988801989098529190960490951694840194909452604e5491519093429261360192909116614f47565b11156136455760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b6044820152606401610a72565b80602001516001600160801b031682608001516001600160801b031611156136af5760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c69717569646974790000000000000000006044820152606401610a72565b81516001600160a01b031633146136f85760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b6044820152606401610a72565b60208201511561373c5760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b6044820152606401610a72565b6000848152604d60205260409020805460ff60a01b1916600160a01b179055606082015161379c906120fb906001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b81604001516137ab91906150be565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a361384082606001516001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b949350505050565b600061385261443b565b6041549091501561199c57600081116138ad5760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e672072657175657374730000006044820152606401610a72565b600061393082603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613906573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061392a9190614ef6565b906147a0565b9050604154670de0b6b3a7640000821161395b5761395682670de0b6b3a7640000614ecd565b61396d565b61396d670de0b6b3a764000083614ecd565b1115610ce25760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f7200006044820152606401610a72565b6001600160a01b03811660009081526035602052604090205460ff16613a235760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f72746564000000000000006044820152606401610a72565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a6357600080fd5b505af1158015613a77573d6000803e3d6000fd5b505050506110f261330b565b6001600160a01b038116613ad95760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610a72565b61199c816147c1565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614613b2557506000919050565b6040516370a0823160e01b815230600482015282906001600160a01b038216906370a0823190602401602060405180830381865afa158015613b6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b8f9190614ef6565b60365490925060005b81811015613cb457600060368281548110613bb557613bb5614ea1565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af690602401602060405180830381865afa158015613c0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c2f9190614f25565b15613cab57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f51522690602401602060405180830381865afa158015613c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c9e9190614ef6565b613ca89086614f47565b94505b50600101613b98565b5060408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529091613d029086614f47565b1015613d1357506000949350505050565b805160408201516001600160801b0391821691613d31911686614f47565b613d3b9190614ecd565b95945050505050565b6001600160a01b03851660009081526035602052604090205460ff16613da25760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b6044820152606401610a72565b600183148015613db25750600181145b8015613e1657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684846000818110613df657613df6614ea1565b9050602002016020810190613e0b9190614be6565b6001600160a01b0316145b613e625760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920617373657420697320737570706f727465640000000000000000006044820152606401610a72565b613e6a614828565b82826000818110613e7d57613e7d614ea1565b905060200201351115613ed25760405162461bcd60e51b815260206004820152601b60248201527f4e6f7420656e6f7567682061737365747320617661696c61626c6500000000006044820152606401610a72565b613f298583836000818110613ee957613ee9614ea1565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166130e09092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613f6457600080fd5b505af1158015613f78573d6000803e3d6000fd5b505050505050505050565b60006001600160801b038211156130dc5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610a72565b6050546001600160a01b0316806140005750565b600061400a614828565b905080600003614018575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015614062573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140869190614ef6565b905060006140cf7f000000000000000000000000000000000000000000000000000000000000000060ff1660126140c86039548661493690919063ffffffff16565b91906132a7565b90508083116140de5750505050565b60006140ea8285614ecd565b9050846141216001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682846130e0565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061416f907f0000000000000000000000000000000000000000000000000000000000000000908690600401614f5a565b600060405180830381600087803b15801561418957600080fd5b505af115801561419d573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b6001600160a01b03851660009081526035602052604090205460ff166142755760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b6044820152606401610a72565b8281146142c45760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d61746368000000000000006044820152606401610a72565b8260005b8181101561439357866001600160a01b031663d9caed12898888858181106142f2576142f2614ea1565b90506020020160208101906143079190614be6565b87878681811061431957614319614ea1565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561437057600080fd5b505af1158015614384573d6000803e3d6000fd5b505050508060010190506142c8565b5061439c61330b565b5050505050505050565b60365460005b8181101561443257603681815481106143c7576143c7614ea1565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b15801561440f57600080fd5b505af1158015614423573d6000803e3d6000fd5b505050508060010190506143ac565b50610ce261330b565b6000610c2360127f000000000000000000000000000000000000000000000000000000000000000060ff166140c87f0000000000000000000000000000000000000000000000000000000000000000613ae2565b6000806000603c60009054906101000a90046001600160a01b03166001600160a01b031663e696393a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156144e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061450b9190614ef6565b905060006145198287614ecd565b604f54909150600090614535906001600160401b031642614ecd565b604f54600160c01b90046001600160401b031694509050801580614557575081155b8061456157508587115b8061457357506001600160401b034210155b15614584576000945050505061465b565b61458e8787614ecd565b604f54909550600160401b90046001600160401b031660018111156145f3576145cb856145bc836002614f95565b6145c69089614f73565b61494b565b94506145e0856145db8389614f73565b614662565b94506145f0866145db8488614f95565b95505b604f54614634908790670de0b6b3a764000090600160801b90046001600160401b03166146208688614f95565b61462a9190614f95565b6145db9190614f73565b955061465486670de0b6b3a764000061462a66470de4df82000087614f95565b9550505050505b9250929050565b60008183106146715781613304565b5090919050565b60006146cd826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661495a9092919063ffffffff16565b8051909150156110f257808060200190518101906146eb9190614f25565b6110f25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a72565b6040516001600160a01b03808516602483015283166044820152606481018290526147829085906323b872dd60e01b906084016130ff565b50505050565b60006133048284614f95565b60006133048284614f73565b6000806147b584670de0b6b3a7640000614788565b90506138408184614794565b806001600160a01b03166147e16000805160206151718339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a360008051602061517183398151915255565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301526000928391614878919061509f565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156148ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149119190614ef6565b9050818111614924576000935050505090565b61492e8282614ecd565b935050505090565b60006133048383670de0b6b3a7640000614969565b60008183116146715781613304565b60606138408484600085614982565b6000806149768585614788565b9050613d3b8184614794565b6060824710156149e35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a72565b843b614a315760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a72565b600080866001600160a01b03168587604051614a4d9190615101565b60006040518083038185875af1925050503d8060008114614a8a576040519150601f19603f3d011682016040523d82523d6000602084013e614a8f565b606091505b5091509150614a9f828286614aaa565b979650505050505050565b60608315614ab9575081613304565b825115614ac95782518084602001fd5b8160405162461bcd60e51b8152600401610a72919061511d565b828054828255906000526020600020908101928215614b38579160200282015b82811115614b3857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614b03565b506130dc9291505b808211156130dc5760008155600101614b40565b600060208284031215614b6657600080fd5b5035919050565b80356001600160a01b0381168114614b8457600080fd5b919050565b60008060408385031215614b9c57600080fd5b614ba583614b6d565b946020939093013593505050565b600080600060608486031215614bc857600080fd5b614bd184614b6d565b95602085013595506040909401359392505050565b600060208284031215614bf857600080fd5b61330482614b6d565b602080825282518282018190526000918401906040840190835b81811015614c425783516001600160a01b0316835260209384019390920191600101614c1b565b509095945050505050565b60008083601f840112614c5f57600080fd5b5081356001600160401b03811115614c7657600080fd5b6020830191508360208260051b850101111561465b57600080fd5b60008060208385031215614ca457600080fd5b82356001600160401b03811115614cba57600080fd5b614cc685828601614c4d565b90969095509350505050565b6040808252835190820181905260009060208501906060840190835b81811015614d0c578351835260209384019390920191600101614cee565b5050602093909301939093525092915050565b600080600080600060608688031215614d3757600080fd5b614d4086614b6d565b945060208601356001600160401b03811115614d5b57600080fd5b614d6788828901614c4d565b90955093505060408601356001600160401b03811115614d8657600080fd5b614d9288828901614c4d565b969995985093965092949392505050565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60208082526015908201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115611a5057611a50614eb7565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614f0857600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215614f3757600080fd5b8151801515811461330457600080fd5b80820180821115611a5057611a50614eb7565b6001600160a01b03929092168252602082015260400190565b600082614f9057634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417611a5057611a50614eb7565b6001815b6001841115614fe757808504811115614fcb57614fcb614eb7565b6001841615614fd957908102905b60019390931c928002614fb0565b935093915050565b600082614ffe57506001611a50565b8161500b57506000611a50565b8160018114615021576002811461502b57615047565b6001915050611a50565b60ff84111561503c5761503c614eb7565b50506001821b611a50565b5060208310610133831016604e8410600b841016171561506a575081810a611a50565b6150776000198484614fac565b806000190482111561508b5761508b614eb7565b029392505050565b60006133048383614fef565b6001600160801b038281168282160390811115611a5057611a50614eb7565b6001600160801b038181168382160190811115611a5057611a50614eb7565b60005b838110156150f85781810151838201526020016150e0565b50506000910152565b600082516151138184602087016150dd565b9190910192915050565b602081526000825180602084015261513c8160408501602087016150dd565b601f01601f1916919091016040019291505056fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122091d6a7cba9d28d826c8e761f35ce59eca1d9cbfc1a254eb27a7fa5ed1cb526fe64736f6c634300081c0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106104075760003560e01c8063663e64ce11610220578063ae69f3cb11610130578063c7af3352116100b8578063e6cc543211610087578063e6cc5432146109e5578063ea33b8e4146109f9578063f3f18c3714610a01578063f844443614610a14578063fac5bb9b14610a2757600080fd5b8063c7af3352146109ba578063c9919112146109c2578063d38bfff4146109ca578063d4c3eea0146109dd57600080fd5b8063b9b17f9f116100ff578063b9b17f9f14610975578063bb7a632e1461097d578063c3b2886414610997578063c4d66de81461099f578063c5f00841146109b257600080fd5b8063ae69f3cb14610934578063af14052c14610947578063b2c9336d1461094f578063b4925a201461096257600080fd5b806395b166bc116101b35780639fa1826e116101825780639fa1826e146108f6578063a0712d68146108ff578063a0aead4d14610912578063ab80dafb14610919578063abaa99161461092c57600080fd5b806395b166bc146108685780639be918e61461087b5780639e428552146108bb5780639ee679e8146108ce57600080fd5b80638e510b52116101ef5780638e510b521461079c5780638ec489a2146107a5578063937b2581146107b857806394828ffd1461086057600080fd5b8063663e64ce14610750578063773540b31461076357806378f353a114610776578063840c4c7a1461078957600080fd5b806339ebf8231161031b578063527e83a8116102ae5780635802a1721161027d5780635802a172146106fe578063597c89101461070f5780635d36b190146107225780635f5152261461072a5780636217f3ea1461073d57600080fd5b8063527e83a8146106aa57806353ca9f24146106c4578063570d8e1d146106d857806357bee944146106eb57600080fd5b806345e4213b116102ea57806345e4213b1461063b57806348e30f541461064457806349c1d54d146106655780634d5f46291461067857600080fd5b806339ebf823146105a95780633b8ae397146105ed5780633dbc911f146106005780634530820a1461060857600080fd5b80631a32aad61161039e5780632acada4d1161036d5780632acada4d146104f35780632da845a81461050857806331e19cfa1461051b578063362bd1a31461052357806338d52e0f1461058257600080fd5b80631a32aad6146104ad5780631cfbe7bc146104c05780631edfe3da146104d3578063207134b0146104ea57600080fd5b80631072cbea116103da5780631072cbea14610461578063156e29f614610474578063175188e8146104875780631816dd4a1461049a57600080fd5b80630493a0fa1461040c57806309f49bf5146104215780630acbda75146104295780630c340a241461043c575b600080fd5b61041f61041a366004614b54565b610a3a565b005b61041f610af0565b61041f610437366004614b54565b610b60565b610444610c0b565b6040516001600160a01b0390911681526020015b60405180910390f35b61041f61046f366004614b89565b610c28565b61041f610482366004614bb3565b610ce6565b61041f610495366004614be6565b610d59565b61041f6104a8366004614be6565b6110f7565b603c54610444906001600160a01b031681565b61041f6104ce366004614b54565b6111fe565b6104dc60395481565b604051908152602001610458565b6104dc60435481565b6104fb6112c0565b6040516104589190614c01565b61041f610516366004614be6565b611337565b6036546104dc565b604b54604c5461054f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610458565b6104447f000000000000000000000000000000000000000000000000000000000000000081565b6105d66105b7366004614be6565b6035602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610458565b61041f6105fb366004614be6565b6113a9565b61041f6115bc565b61062b610616366004614be6565b60496020526000908152604090205460ff1681565b6040519015158152602001610458565b6104dc604e5481565b610657610652366004614c91565b611632565b604051610458929190614cd2565b604254610444906001600160a01b031681565b604f5461069290600160c01b90046001600160401b031681565b6040516001600160401b039091168152602001610458565b604f5461069290600160801b90046001600160401b031681565b60375461062b90600160a01b900460ff1681565b603f54610444906001600160a01b031681565b61041f6106f9366004614be6565b6117a8565b603c546001600160a01b0316610444565b61041f61071d366004614be6565b61195b565b61041f61199f565b6104dc610738366004614be6565b611a45565b61041f61074b366004614b54565b611a56565b61041f61075e366004614b54565b611bda565b61041f610771366004614be6565b611c33565b604f54610692906001600160401b031681565b61041f610797366004614d1f565b611ca5565b6104dc60415481565b61041f6107b3366004614b54565b611d2c565b6108196107c6366004614b54565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a001610458565b61041f611de1565b61041f610876366004614be6565b611e51565b61062b610889366004614be6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b61041f6108c9366004614be6565b611f18565b6108e16108dc366004614b54565b611f8a565b60408051928352602083019190915201610458565b6104dc603a5481565b61041f61090d366004614b54565b6122ca565b60016104dc565b61041f610927366004614b54565b61233b565b61041f61248a565b61041f610942366004614d1f565b612502565b61041f61257e565b61041f61095d366004614b54565b612639565b61041f610970366004614b54565b612692565b61041f6127b0565b604f5461069290600160401b90046001600160401b031681565b6104fb6127b8565b61041f6109ad366004614be6565b61281a565b61041f6129c5565b61062b612a3b565b61041f612a6c565b61041f6109d8366004614be6565b612aac565b6104dc612b50565b60375461062b90600160a81b900460ff1681565b6104dc612b5a565b605154610444906001600160a01b031681565b6104dc610a22366004614b54565b612be9565b605054610444906001600160a01b031681565b603f546001600160a01b0316331480610a565750610a56612a3b565b610a7b5760405162461bcd60e51b8152600401610a7290614da3565b60405180910390fd5b610a83612cda565b50610a8d81613074565b604f80546001600160401b0392909216600160401b0267ffffffffffffffff60401b199092169190911790556040518181527f406e15fbca1d8ded2dbb06765fea3a54f18395c54125a4c9916dd00ea14ee15e906020015b60405180910390a150565b603f546001600160a01b0316331480610b0c5750610b0c612a3b565b610b285760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b610b68612a3b565b610b845760405162461bcd60e51b8152600401610a7290614deb565b611388811115610bd65760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f7420657863656564203530250000000000000000006044820152606401610a72565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c790602001610ae5565b6000610c236000805160206151718339815191525490565b905090565b610c30612a3b565b610c4c5760405162461bcd60e51b8152600401610a7290614deb565b816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610cc65760405162461bcd60e51b815260206004820152601660248201527513db9b1e481d5b9cdd5c1c1bdc9d195908185cdcd95d60521b6044820152606401610a72565b610ce2610cd1610c0b565b6001600160a01b03841690836130e0565b5050565b603754600160a81b900460ff1615610d105760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101610d425760405162461bcd60e51b8152600401610a7290614e4a565b60028255610d4f84613136565b5060019055505050565b610d61612a3b565b610d7d5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff16610db55760405162461bcd60e51b8152600401610a7290614e72565b6050546001600160a01b03808316911603610e125760405162461bcd60e51b815260206004820152601d60248201527f53747261746567792069732064656661756c7420666f722061737365740000006044820152606401610a72565b6036548060005b82811015610e6857836001600160a01b031660368281548110610e3e57610e3e614ea1565b6000918252602090912001546001600160a01b031603610e6057809150610e68565b600101610e19565b50818110156110f2576036610e7e600184614ecd565b81548110610e8e57610e8e614ea1565b600091825260209091200154603680546001600160a01b039092169183908110610eba57610eba614ea1565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610ef957610ef9614ee0565b6001900381819060005260206000200160006101000a8154906001600160a01b03021916905590556000839050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610f6157600080fd5b505af1158015610f75573d6000803e3d6000fd5b505050506001600160a01b0384166000908152603560209081526040808320805460ff199081169091556049909252822080549091169055610fe26509184e72a00060ff7f00000000000000000000000000000000000000000000000000000000000000001660126132a7565b604051632fa8a91360e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192508291841690635f51522690602401602060405180830381865afa15801561104d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110719190614ef6565b106110b35760405162461bcd60e51b81526020600482015260126024820152715374726174656779206861732066756e647360701b6044820152606401610a72565b6040516001600160a01b03861681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49060200160405180910390a150505b505050565b6110ff612a3b565b61111b5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff166111535760405162461bcd60e51b8152600401610a7290614e72565b6001600160a01b03811660009081526049602052604090205460ff16156111b25760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481dda1a5d195b1a5cdd1959606a1b6044820152606401610a72565b6001600160a01b038116600081815260496020526040808220805460ff19166001179055517f47c8c96a5942f094264111c5fe7f6a4fe86efe63254a6fa7afa5fc84f07d58e89190a250565b611206612a3b565b6112225760405162461bcd60e51b8152600401610a7290614deb565b80158061123f5750610258811015801561123f57506213c6808111155b61128b5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636c61696d2064656c617920706572696f640000000000006044820152606401610a72565b604e8190556040518181527fc59f5e32049abab44ddea11021f5abb89422a2f550837afcf25df9fc8d0db6b090602001610ae5565b60408051600180825281830190925260609160009190602080830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061131a5761131a614ea1565b6001600160a01b0390921660209283029190910190910152919050565b61133f612a3b565b61135b5760405162461bcd60e51b8152600401610a7290614deb565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610ae5565b6113b1612a3b565b6113cd5760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526035602052604090205460ff16156114365760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f766564000000000000006044820152606401610a72565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa15801561149c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c09190614f25565b61150c5760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a72565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610ae5565b603f546001600160a01b03163314806115d857506115d8612a3b565b6115f45760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b603754606090600090600160a81b900460ff16156116625760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016116945760405162461bcd60e51b8152600401610a7290614e4a565b600282556116a061330b565b50846001600160401b038111156116b9576116b9614f0f565b6040519080825280602002602001820160405280156116e2578160200160208202803683370190505b50935060005b8581101561175e5761171187878381811061170557611705614ea1565b905060200201356134e7565b85828151811061172357611723614ea1565b60200260200101818152505084818151811061174157611741614ea1565b6020026020010151846117549190614f47565b93506001016116e8565b506117936001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130e0565b61179b613848565b6001825550509250929050565b603f546001600160a01b03163314806117c457506117c4612a3b565b6117e05760405162461bcd60e51b8152600401610a7290614da3565b6040516001600160a01b03821681527f45a9e715f8779ebeab88d3e8d081fb8b484b7730857e7c4478a95a5b1d8f79489060200160405180910390a16001600160a01b03811615611939576001600160a01b03811660009081526035602052604090205460ff166118635760405162461bcd60e51b8152600401610a7290614e72565b60405163551c457b60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282169063aa388af690602401602060405180830381865afa1580156118c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ed9190614f25565b6119395760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f72746564206279205374726174656779006044820152606401610a72565b605080546001600160a01b0319166001600160a01b0392909216919091179055565b603f546001600160a01b03163314806119775750611977612a3b565b6119935760405162461bcd60e51b8152600401610a7290614da3565b61199c816139bb565b50565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614611a3a5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610a72565b611a4333613a83565b565b6000611a5082613ae2565b92915050565b603754600160a81b900460ff1615611a805760405162461bcd60e51b8152600401610a7290614e22565b3360009081526035602052604090205460ff161515600114611adb5760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a72565b3360009081526049602052604090205460ff161515600114611b3a5760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a72565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051611b6b929190614f5a565b60405180910390a1603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90611ba59033908590600401614f5a565b600060405180830381600087803b158015611bbf57600080fd5b505af1158015611bd3573d6000803e3d6000fd5b5050505050565b611be2612a3b565b611bfe5760405162461bcd60e51b8152600401610a7290614deb565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610ae5565b611c3b612a3b565b611c575760405162461bcd60e51b8152600401610a7290614deb565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610ae5565b603f546001600160a01b0316331480611cc15750611cc1612a3b565b611cdd5760405162461bcd60e51b8152600401610a7290614da3565b60008051602061515183398151915280546001198101611d0f5760405162461bcd60e51b8152600401610a7290614e4a565b60028255611d208787878787613d44565b50600190555050505050565b603f546001600160a01b0316331480611d485750611d48612a3b565b611d645760405162461bcd60e51b8152600401610a7290614da3565b670de0b6b3a7640000811115611dac5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b6044820152606401610a72565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610ae5565b603f546001600160a01b0316331480611dfd5750611dfd612a3b565b611e195760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e59612a3b565b611e755760405162461bcd60e51b8152600401610a7290614deb565b6001600160a01b03811660009081526049602052604090205460ff16611ecf5760405162461bcd60e51b815260206004820152600f60248201526e139bdd081dda1a5d195b1a5cdd1959608a1b6044820152606401610a72565b6001600160a01b038116600081815260496020526040808220805460ff19169055517f0ec40967a61509853550658e51d0e4297f7cba244fe4adc8ba18b5631ac20e2f9190a250565b611f20612a3b565b611f3c5760405162461bcd60e51b8152600401610a7290614deb565b605180546001600160a01b0319166001600160a01b0383169081179091556040519081527fb3b3f5f64ab192e4b5fefde1f51ce9733bbdcf831951543b325aebd49cc27ec490602001610ae5565b6037546000908190600160a81b900460ff1615611fb95760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101611feb5760405162461bcd60e51b8152600401610a7290614e4a565b600282556000851161203f5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a72565b6000604e54116120915760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a72565b604c54600160801b90046001600160801b031693506120d5857f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b604b546120eb91906001600160801b0316614f47565b92506121006120fb856001614f47565b613f83565b604c80546001600160801b03928316600160801b02921691909117905561212683613f83565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff16918101919091526060810161217687613f83565b6001600160801b0316815260200161218d85613f83565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906122489033908990600401614f5a565b600060405180830381600087803b15801561226257600080fd5b505af1158015612276573d6000803e3d6000fd5b50505050612282613848565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff16156122f45760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016123265760405162461bcd60e51b8152600401610a7290614e4a565b6002825561233383613136565b506001905550565b603754600160a81b900460ff16156123655760405162461bcd60e51b8152600401610a7290614e22565b3360009081526035602052604090205460ff1615156001146123c05760405162461bcd60e51b8152602060048201526014602482015273556e737570706f7274656420737472617465677960601b6044820152606401610a72565b3360009081526049602052604090205460ff16151560011461241f5760405162461bcd60e51b81526020600482015260186024820152774e6f742077686974656c697374656420737472617465677960401b6044820152606401610a72565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853382604051612450929190614f5a565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611ba59033908590600401614f5a565b603754600160a81b900460ff16156124b45760405162461bcd60e51b8152600401610a7290614e22565b600080516020615151833981519152805460011981016124e65760405162461bcd60e51b8152600401610a7290614e4a565b600282556124f261330b565b506124fb613fec565b5060019055565b603f546001600160a01b031633148061251e575061251e612a3b565b61253a5760405162461bcd60e51b8152600401610a7290614da3565b6000805160206151518339815191528054600119810161256c5760405162461bcd60e51b8152600401610a7290614e4a565b60028255611d20308888888888614215565b600080516020615151833981519152805460011981016125b05760405162461bcd60e51b8152600401610a7290614e4a565b600282556051546001600160a01b03163314806125d75750603f546001600160a01b031633145b806125e557506125e5612a3b565b6126295760405162461bcd60e51b815260206004820152601560248201527410d85b1b195c881b9bdd08185d5d1a1bdc9a5e9959605a1b6044820152606401610a72565b612631612cda565b505060019055565b612641612a3b565b61265d5760405162461bcd60e51b8152600401610a7290614deb565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610ae5565b603f546001600160a01b03163314806126ae57506126ae612a3b565b6126ca5760405162461bcd60e51b8152600401610a7290614da3565b6126d2612cda565b5060006301e133806126e5606484614f73565b6126ef9190614f73565b90506127056201518066b1a2bc2ec50000614f73565b8111156127445760405162461bcd60e51b815260206004820152600d60248201526c0a4c2e8ca40e8dede40d0d2ced609b1b6044820152606401610a72565b61274d81613074565b604f80546001600160401b0392909216600160801b0267ffffffffffffffff60801b199092169190911790556040518181527fef46f143af5fead0010484fe7d6ec2e2972420faa76157f5a6075aa72e614cb59060200160405180910390a15050565b61199c61330b565b6060603680548060200260200160405190810160405280929190818152602001828054801561281057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116127f2575b5050505050905090565b612822612a3b565b61283e5760405162461bcd60e51b8152600401610a7290614deb565b600054610100900460ff1680612857575060005460ff16155b6128ba5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a72565b600054610100900460ff161580156128dc576000805461ffff19166101011790555b6001600160a01b03821661292b5760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b6044820152606401610a72565b603c80546001600160a01b0384166001600160a01b03199091161790556037805461ffff60a01b1916600160a81b1790556000603981905569054b40b1f852bda00000603a55604080519182526020820190819052905161298e91603691614ae3565b50604f805467ffffffffffffffff60401b19166a093a8000000000000000001790558015610ce2576000805461ff00191690555050565b603f546001600160a01b03163314806129e157506129e1612a3b565b6129fd5760405162461bcd60e51b8152600401610a7290614da3565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b6000612a536000805160206151718339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612a885750612a88612a3b565b612aa45760405162461bcd60e51b8152600401610a7290614da3565b611a436143a6565b612ab4612a3b565b612ad05760405162461bcd60e51b8152600401610a7290614deb565b612af8817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612b186000805160206151718339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000610c2361443b565b6000612be3603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd69190614ef6565b612bde61443b565b61448f565b50919050565b603754600090600160a81b900460ff1615612c165760405162461bcd60e51b8152600401610a7290614e22565b60008051602061515183398151915280546001198101612c485760405162461bcd60e51b8152600401610a7290614e4a565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115612c8957612c8761330b565b505b612c92846134e7565b9250612cc86001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856130e0565b612cd0613848565b5060019055919050565b603754600090600160a01b900460ff1615612d295760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b6044820152606401610a72565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612d73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d979190614ef6565b90506000612da361443b565b905081600003612db65791506130719050565b600080612dc3848461448f565b90925090506000612dd48386614f47565b90508481111580612de457508381115b15612df3575091949350505050565b612e04826001600160401b03614662565b604f805477ffffffffffffffffffffffffffffffff000000000000000016600160c01b6001600160401b039384160267ffffffffffffffff19161742929092169190911790556042546001600160a01b031660008115612f405761271060435486612e6f9190614f95565b612e799190614f73565b90508015612f4057848110612edb5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b6064820152608401610a72565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612f0d9085908590600401614f5a565b600060405180830381600087803b158015612f2757600080fd5b505af1158015612f3b573d6000803e3d6000fd5b505050505b604080516001600160a01b0384168152602081018790529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a1603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fdd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130019190614ef6565b83111561306757603c546040516339a7919f60e01b8152600481018590526001600160a01b03909116906339a7919f90602401600060405180830381600087803b15801561304e57600080fd5b505af1158015613062573d6000803e3d6000fd5b505050505b5093955050505050505b90565b60006001600160401b038211156130dc5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610a72565b5090565b6110f28363a9059cbb60e01b84846040516024016130ff929190614f5a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614678565b600081116131865760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610a72565b60006131b782601260ff7f0000000000000000000000000000000000000000000000000000000000000000166132a7565b90507f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516131ea929190614f5a565b60405180910390a1603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132249033908590600401614f5a565b600060405180830381600087803b15801561323e57600080fd5b505af1158015613252573d6000803e3d6000fd5b5061328d9250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016905033308561474a565b61329561330b565b50603a548110610ce257610ce2613fec565b6000818311156132d7576132d06132be8385614ecd565b6132c990600a615093565b8590614788565b9350613301565b81831015613301576132fe6132ec8484614ecd565b6132f790600a615093565b8590614794565b93505b50825b9392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c548084169686019690965292909404166060830152600092839161335d9161509f565b6001600160801b03169050806000036133795760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156133e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134049190614ef6565b905060008360400151846020015161341c919061509f565b6001600160801b0316905080821161343957600094505050505090565b60006134458284614ecd565b90508084106134545780613456565b835b955060008686602001516001600160801b03166134739190614f47565b905061347e81613f83565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f463333906134d69083908a90918252602082015260400190565b60405180910390a150505050505090565b600080604e541161353a5760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c65640000006044820152606401610a72565b6000828152604d6020908152604091829020825160a08101845281546001600160a01b038116825260ff600160a01b82041615158285015264ffffffffff600160a81b90910481168286019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915288519081018952604b548084168252849004831697810197909752604c54808316988801989098529190960490951694840194909452604e5491519093429261360192909116614f47565b11156136455760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b6044820152606401610a72565b80602001516001600160801b031682608001516001600160801b031611156136af5760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c69717569646974790000000000000000006044820152606401610a72565b81516001600160a01b031633146136f85760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b6044820152606401610a72565b60208201511561373c5760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b6044820152606401610a72565b6000848152604d60205260409020805460ff60a01b1916600160a01b179055606082015161379c906120fb906001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b81604001516137ab91906150be565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a361384082606001516001600160801b03167f000000000000000000000000000000000000000000000000000000000000000060ff1660126132a7565b949350505050565b600061385261443b565b6041549091501561199c57600081116138ad5760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e672072657175657374730000006044820152606401610a72565b600061393082603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613906573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061392a9190614ef6565b906147a0565b9050604154670de0b6b3a7640000821161395b5761395682670de0b6b3a7640000614ecd565b61396d565b61396d670de0b6b3a764000083614ecd565b1115610ce25760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f7200006044820152606401610a72565b6001600160a01b03811660009081526035602052604090205460ff16613a235760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f72746564000000000000006044820152606401610a72565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a6357600080fd5b505af1158015613a77573d6000803e3d6000fd5b505050506110f261330b565b6001600160a01b038116613ad95760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610a72565b61199c816147c1565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614613b2557506000919050565b6040516370a0823160e01b815230600482015282906001600160a01b038216906370a0823190602401602060405180830381865afa158015613b6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b8f9190614ef6565b60365490925060005b81811015613cb457600060368281548110613bb557613bb5614ea1565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af690602401602060405180830381865afa158015613c0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c2f9190614f25565b15613cab57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f51522690602401602060405180830381865afa158015613c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c9e9190614ef6565b613ca89086614f47565b94505b50600101613b98565b5060408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529091613d029086614f47565b1015613d1357506000949350505050565b805160408201516001600160801b0391821691613d31911686614f47565b613d3b9190614ecd565b95945050505050565b6001600160a01b03851660009081526035602052604090205460ff16613da25760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b6044820152606401610a72565b600183148015613db25750600181145b8015613e1657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684846000818110613df657613df6614ea1565b9050602002016020810190613e0b9190614be6565b6001600160a01b0316145b613e625760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920617373657420697320737570706f727465640000000000000000006044820152606401610a72565b613e6a614828565b82826000818110613e7d57613e7d614ea1565b905060200201351115613ed25760405162461bcd60e51b815260206004820152601b60248201527f4e6f7420656e6f7567682061737365747320617661696c61626c6500000000006044820152606401610a72565b613f298583836000818110613ee957613ee9614ea1565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166130e09092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613f6457600080fd5b505af1158015613f78573d6000803e3d6000fd5b505050505050505050565b60006001600160801b038211156130dc5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610a72565b6050546001600160a01b0316806140005750565b600061400a614828565b905080600003614018575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015614062573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140869190614ef6565b905060006140cf7f000000000000000000000000000000000000000000000000000000000000000060ff1660126140c86039548661493690919063ffffffff16565b91906132a7565b90508083116140de5750505050565b60006140ea8285614ecd565b9050846141216001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682846130e0565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061416f907f0000000000000000000000000000000000000000000000000000000000000000908690600401614f5a565b600060405180830381600087803b15801561418957600080fd5b505af115801561419d573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b6001600160a01b03851660009081526035602052604090205460ff166142755760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b6044820152606401610a72565b8281146142c45760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d61746368000000000000006044820152606401610a72565b8260005b8181101561439357866001600160a01b031663d9caed12898888858181106142f2576142f2614ea1565b90506020020160208101906143079190614be6565b87878681811061431957614319614ea1565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561437057600080fd5b505af1158015614384573d6000803e3d6000fd5b505050508060010190506142c8565b5061439c61330b565b5050505050505050565b60365460005b8181101561443257603681815481106143c7576143c7614ea1565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b15801561440f57600080fd5b505af1158015614423573d6000803e3d6000fd5b505050508060010190506143ac565b50610ce261330b565b6000610c2360127f000000000000000000000000000000000000000000000000000000000000000060ff166140c87f0000000000000000000000000000000000000000000000000000000000000000613ae2565b6000806000603c60009054906101000a90046001600160a01b03166001600160a01b031663e696393a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156144e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061450b9190614ef6565b905060006145198287614ecd565b604f54909150600090614535906001600160401b031642614ecd565b604f54600160c01b90046001600160401b031694509050801580614557575081155b8061456157508587115b8061457357506001600160401b034210155b15614584576000945050505061465b565b61458e8787614ecd565b604f54909550600160401b90046001600160401b031660018111156145f3576145cb856145bc836002614f95565b6145c69089614f73565b61494b565b94506145e0856145db8389614f73565b614662565b94506145f0866145db8488614f95565b95505b604f54614634908790670de0b6b3a764000090600160801b90046001600160401b03166146208688614f95565b61462a9190614f95565b6145db9190614f73565b955061465486670de0b6b3a764000061462a66470de4df82000087614f95565b9550505050505b9250929050565b60008183106146715781613304565b5090919050565b60006146cd826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661495a9092919063ffffffff16565b8051909150156110f257808060200190518101906146eb9190614f25565b6110f25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a72565b6040516001600160a01b03808516602483015283166044820152606481018290526147829085906323b872dd60e01b906084016130ff565b50505050565b60006133048284614f95565b60006133048284614f73565b6000806147b584670de0b6b3a7640000614788565b90506138408184614794565b806001600160a01b03166147e16000805160206151718339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a360008051602061517183398151915255565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301526000928391614878919061509f565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156148ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149119190614ef6565b9050818111614924576000935050505090565b61492e8282614ecd565b935050505090565b60006133048383670de0b6b3a7640000614969565b60008183116146715781613304565b60606138408484600085614982565b6000806149768585614788565b9050613d3b8184614794565b6060824710156149e35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a72565b843b614a315760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a72565b600080866001600160a01b03168587604051614a4d9190615101565b60006040518083038185875af1925050503d8060008114614a8a576040519150601f19603f3d011682016040523d82523d6000602084013e614a8f565b606091505b5091509150614a9f828286614aaa565b979650505050505050565b60608315614ab9575081613304565b825115614ac95782518084602001fd5b8160405162461bcd60e51b8152600401610a72919061511d565b828054828255906000526020600020908101928215614b38579160200282015b82811115614b3857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614b03565b506130dc9291505b808211156130dc5760008155600101614b40565b600060208284031215614b6657600080fd5b5035919050565b80356001600160a01b0381168114614b8457600080fd5b919050565b60008060408385031215614b9c57600080fd5b614ba583614b6d565b946020939093013593505050565b600080600060608486031215614bc857600080fd5b614bd184614b6d565b95602085013595506040909401359392505050565b600060208284031215614bf857600080fd5b61330482614b6d565b602080825282518282018190526000918401906040840190835b81811015614c425783516001600160a01b0316835260209384019390920191600101614c1b565b509095945050505050565b60008083601f840112614c5f57600080fd5b5081356001600160401b03811115614c7657600080fd5b6020830191508360208260051b850101111561465b57600080fd5b60008060208385031215614ca457600080fd5b82356001600160401b03811115614cba57600080fd5b614cc685828601614c4d565b90969095509350505050565b6040808252835190820181905260009060208501906060840190835b81811015614d0c578351835260209384019390920191600101614cee565b5050602093909301939093525092915050565b600080600080600060608688031215614d3757600080fd5b614d4086614b6d565b945060208601356001600160401b03811115614d5b57600080fd5b614d6788828901614c4d565b90955093505060408601356001600160401b03811115614d8657600080fd5b614d9288828901614c4d565b969995985093965092949392505050565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60208082526015908201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115611a5057611a50614eb7565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614f0857600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215614f3757600080fd5b8151801515811461330457600080fd5b80820180821115611a5057611a50614eb7565b6001600160a01b03929092168252602082015260400190565b600082614f9057634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417611a5057611a50614eb7565b6001815b6001841115614fe757808504811115614fcb57614fcb614eb7565b6001841615614fd957908102905b60019390931c928002614fb0565b935093915050565b600082614ffe57506001611a50565b8161500b57506000611a50565b8160018114615021576002811461502b57615047565b6001915050611a50565b60ff84111561503c5761503c614eb7565b50506001821b611a50565b5060208310610133831016604e8410600b841016171561506a575081810a611a50565b6150776000198484614fac565b806000190482111561508b5761508b614eb7565b029392505050565b60006133048383614fef565b6001600160801b038281168282160390811115611a5057611a50614eb7565b6001600160801b038181168382160190811115611a5057611a50614eb7565b60005b838110156150f85781810151838201526020016150e0565b50506000910152565b600082516151138184602087016150dd565b9190910192915050565b602081526000825180602084015261513c8160408501602087016150dd565b601f01601f1916919091016040019291505056fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122091d6a7cba9d28d826c8e761f35ce59eca1d9cbfc1a254eb27a7fa5ed1cb526fe64736f6c634300081c0033", + "libraries": {}, + "devdoc": { + "author": "Origin Protocol Inc", + "kind": "dev", + "methods": { + "addStrategyToMintWhitelist(address)": { + "params": { + "strategyAddr": "Strategy address" + } + }, + "addWithdrawalQueueLiquidity()": { + "details": "is called from the Native Staking strategy when validator withdrawals are processed. It also called before any WETH is allocated to a strategy." + }, + "approveStrategy(address)": { + "params": { + "_addr": "Address of the strategy to add" + } + }, + "burnForStrategy(uint256)": { + "details": "Notice: can't use `nonReentrant` modifier since the `redeem` function could require withdrawal on an AMO strategy and that one can call `burnForStrategy` while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.", + "params": { + "_amount": "Amount of OToken to burn" + } + }, + "checkBalance(address)": { + "params": { + "_asset": "Address of asset" + }, + "returns": { + "_0": "uint256 Balance of asset in decimals of asset" + } + }, + "claimWithdrawal(uint256)": { + "params": { + "_requestId": "Unique ID for the withdrawal request" + }, + "returns": { + "amount": "Amount of asset transferred to the withdrawer" + } + }, + "claimWithdrawals(uint256[])": { + "params": { + "_requestIds": "Unique ID of each withdrawal request" + }, + "returns": { + "amounts": "Amount of asset received for each request", + "totalAmount": "Total amount of asset transferred to the withdrawer" + } + }, + "depositToStrategy(address,address[],uint256[])": { + "params": { + "_amounts": "Array of amounts of each corresponding asset to deposit.", + "_assets": "Array of asset address that will be deposited into the strategy.", + "_strategyToAddress": "Address of the Strategy to deposit asset into." + } + }, + "isSupportedAsset(address)": { + "params": { + "_asset": "address of the asset" + }, + "returns": { + "_0": "true if supported" + } + }, + "mint(address,uint256,uint256)": { + "details": "Deprecated: use `mint(uint256 _amount)` instead.Deprecated: param _asset Address of the asset being depositedDeprecated: param _minimumOusdAmount Minimum OTokens to mint", + "params": { + "_amount": "Amount of the asset being deposited" + } + }, + "mint(uint256)": { + "params": { + "_amount": "Amount of the asset being deposited" + } + }, + "mintForStrategy(uint256)": { + "params": { + "_amount": "Amount of OToken to mint Notice: can't use `nonReentrant` modifier since the `mint` function can call `allocate`, and that can trigger an AMO strategy to call this function while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function." + } + }, + "previewYield()": { + "returns": { + "yield": "amount of expected yield" + } + }, + "rebase()": { + "details": "Restricted to the Operator, Strategist or Governor." + }, + "removeStrategy(address)": { + "params": { + "_addr": "Address of the strategy to remove" + } + }, + "removeStrategyFromMintWhitelist(address)": { + "params": { + "strategyAddr": "Strategy address" + } + }, + "requestWithdrawal(uint256)": { + "params": { + "_amount": "Amount of OToken to burn." + }, + "returns": { + "queued": "Cumulative total of all asset queued including already claimed requests.", + "requestId": "Unique ID for the withdrawal request" + } + }, + "setAutoAllocateThreshold(uint256)": { + "params": { + "_threshold": "OToken amount with 18 fixed decimals." + } + }, + "setDefaultStrategy(address)": { + "params": { + "_strategy": "Address of the Strategy" + } + }, + "setDripDuration(uint256)": { + "params": { + "_dripDuration": "Time in seconds to target a constant yield rate" + } + }, + "setOperatorAddr(address)": { + "params": { + "_operator": "New operator address. May be set to the zero address to disable operator-initiated rebases." + } + }, + "setRebaseRateMax(uint256)": { + "params": { + "apr": "in 1e18 notation. 3 * 1e18 = 3% APR" + } + }, + "setStrategistAddr(address)": { + "params": { + "_address": "Address of Strategist" + } + }, + "setVaultBuffer(uint256)": { + "params": { + "_vaultBuffer": "Percentage using 18 decimals. 100% = 1e18." + } + }, + "setWithdrawalClaimDelay(uint256)": { + "params": { + "_delay": "Delay period (should be between 10 mins to 7 days). Set to 0 to disable async withdrawals" + } + }, + "totalValue()": { + "returns": { + "value": "Total value in USD/ETH (1e18)" + } + }, + "transferGovernance(address)": { + "params": { + "_newGovernor": "Address of the new Governor" + } + }, + "transferToken(address,uint256)": { + "params": { + "_amount": "Amount of the asset to transfer", + "_asset": "Address for the asset" + } + }, + "withdrawAllFromStrategy(address)": { + "params": { + "_strategyAddr": "Strategy address." + } + }, + "withdrawFromStrategy(address,address[],uint256[])": { + "params": { + "_amounts": "Array of amounts of each corresponding asset to withdraw.", + "_assets": "Array of asset address that will be withdrawn from the strategy.", + "_strategyFromAddress": "Address of the Strategy to withdraw asset from." + } + } + }, + "title": "Origin Sonic VaultAdmin contract on Sonic", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "addStrategyToMintWhitelist(address)": { + "notice": "Adds a strategy to the mint whitelist. Reverts if strategy isn't approved on Vault." + }, + "addWithdrawalQueueLiquidity()": { + "notice": "Adds WETH to the withdrawal queue if there is a funding shortfall." + }, + "allocate()": { + "notice": "Allocate unallocated funds on Vault to strategies." + }, + "approveStrategy(address)": { + "notice": "Add a strategy to the Vault." + }, + "autoAllocateThreshold()": { + "notice": "OToken mints over this amount automatically allocate funds. 18 decimals." + }, + "burnForStrategy(uint256)": { + "notice": "Burn OTokens for an allowed Strategy" + }, + "capitalPaused()": { + "notice": "pause operations that change the OToken supply. eg mint, redeem, allocate, mint/burn for strategy" + }, + "checkBalance(address)": { + "notice": "Get the balance of an asset held in Vault and all strategies." + }, + "claimGovernance()": { + "notice": "Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor." + }, + "claimWithdrawal(uint256)": { + "notice": "Claim a previously requested withdrawal once it is claimable. This request can be claimed once the withdrawal queue's `claimable` amount is greater than or equal this request's `queued` amount and 10 minutes has passed. If the requests is not claimable, the transaction will revert with `Queue pending liquidity`. If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`. OToken is converted to asset at 1:1." + }, + "claimWithdrawals(uint256[])": { + "notice": "Claim a previously requested withdrawals once they are claimable. This requests can be claimed once the withdrawal queue's `claimable` amount is greater than or equal each request's `queued` amount and 10 minutes has passed. If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`. If one of the requests is not older than 10 minutes, the whole transaction will revert with `Claim delay not met`." + }, + "defaultStrategy()": { + "notice": "Default strategy for asset" + }, + "depositToStrategy(address,address[],uint256[])": { + "notice": "Deposit multiple asset from the vault into the strategy." + }, + "dripDuration()": { + "notice": "Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable." + }, + "getAllAssets()": { + "notice": "Return all vault asset addresses in order" + }, + "getAllStrategies()": { + "notice": "Return the array of all strategies" + }, + "getAssetCount()": { + "notice": "Return the number of asset supported by the Vault." + }, + "getStrategyCount()": { + "notice": "Return the number of strategies active on the Vault." + }, + "governor()": { + "notice": "Returns the address of the current Governor." + }, + "isGovernor()": { + "notice": "Returns true if the caller is the current Governor." + }, + "isSupportedAsset(address)": { + "notice": "Returns whether the vault supports the asset" + }, + "lastRebase()": { + "notice": "Time in seconds that the vault last rebased yield." + }, + "maxSupplyDiff()": { + "notice": "Max difference between total supply and total value of assets. 18 decimals." + }, + "mint(address,uint256,uint256)": { + "notice": "Deposit a supported asset and mint OTokens." + }, + "mint(uint256)": { + "notice": "Deposit a supported asset and mint OTokens." + }, + "mintForStrategy(uint256)": { + "notice": "Mint OTokens for an allowed Strategy" + }, + "oUSD()": { + "notice": "Deprecated: use `oToken()` instead." + }, + "operatorAddr()": { + "notice": "Address authorized to call `rebase()` directly. The Governor and Strategist are always allowed in addition to this address." + }, + "pauseCapital()": { + "notice": "Set the deposit paused flag to true to prevent capital movement." + }, + "pauseRebase()": { + "notice": "Set the deposit paused flag to true to prevent rebasing." + }, + "previewYield()": { + "notice": "Calculates the amount that would rebase at next rebase. This is before any fees." + }, + "rebase()": { + "notice": "Calculate the total value of asset held by the Vault and all strategies and update the supply of OTokens." + }, + "rebasePaused()": { + "notice": "pause rebasing if true" + }, + "rebasePerSecondMax()": { + "notice": "max rebase percentage per second Can be used to set maximum yield of the protocol, spreading out yield over time" + }, + "rebasePerSecondTarget()": { + "notice": "target rebase rate limit, based on past rates and funds available." + }, + "removeStrategy(address)": { + "notice": "Remove a strategy from the Vault." + }, + "removeStrategyFromMintWhitelist(address)": { + "notice": "Removes a strategy from the mint whitelist." + }, + "requestWithdrawal(uint256)": { + "notice": "Request an asynchronous withdrawal of asset in exchange for OToken. The OToken is burned on request and the asset is transferred to the withdrawer on claim. This request can be claimed once the withdrawal queue's `claimable` amount is greater than or equal this request's `queued` amount. There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue. OToken is converted to asset at 1:1." + }, + "setAutoAllocateThreshold(uint256)": { + "notice": "Sets the minimum amount of OTokens in a mint to trigger an automatic allocation of funds afterwords." + }, + "setDefaultStrategy(address)": { + "notice": "Set the default Strategy for asset, i.e. the one which the asset will be automatically allocated to and withdrawn from" + }, + "setDripDuration(uint256)": { + "notice": "Set the drip duration period" + }, + "setMaxSupplyDiff(uint256)": { + "notice": "Sets the maximum allowable difference between total supply and asset' value." + }, + "setOperatorAddr(address)": { + "notice": "Set the address authorized to call `rebase()`." + }, + "setRebaseRateMax(uint256)": { + "notice": "Set a yield streaming max rate. This spreads yield over time if it is above the max rate. This is a per rebase APR which due to compounding differs from the yearly APR. Governance should consider this fact when picking a desired APR" + }, + "setStrategistAddr(address)": { + "notice": "Set address of Strategist" + }, + "setTrusteeAddress(address)": { + "notice": "Sets the trusteeAddress that can receive a portion of yield. Setting to the zero address disables this feature." + }, + "setTrusteeFeeBps(uint256)": { + "notice": "Sets the TrusteeFeeBps to the percentage of yield that should be received in basis points." + }, + "setVaultBuffer(uint256)": { + "notice": "Set a buffer of asset to keep in the Vault to handle most redemptions without needing to spend gas unwinding asset from a Strategy." + }, + "setWithdrawalClaimDelay(uint256)": { + "notice": "Changes the async withdrawal claim period for OETH & superOETHb" + }, + "strategistAddr()": { + "notice": "Address of the Strategist" + }, + "totalValue()": { + "notice": "Determine the total value of asset held by the vault and its strategies." + }, + "transferGovernance(address)": { + "notice": "Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete" + }, + "transferToken(address,uint256)": { + "notice": "Transfer token to governor. Intended for recovering tokens stuck in contract, i.e. mistaken sends." + }, + "trusteeAddress()": { + "notice": "Trustee contract that can collect a percentage of yield" + }, + "trusteeFeeBps()": { + "notice": "Amount of yield collected in basis points. eg 2000 = 20%" + }, + "unpauseCapital()": { + "notice": "Set the deposit paused flag to false to enable capital movement." + }, + "unpauseRebase()": { + "notice": "Set the deposit paused flag to true to allow rebasing." + }, + "vaultBuffer()": { + "notice": "Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18." + }, + "withdrawAllFromStrategies()": { + "notice": "Withdraws all asset from all the strategies and sends asset to the Vault." + }, + "withdrawAllFromStrategy(address)": { + "notice": "Withdraws all asset from the strategy and sends asset to the Vault." + }, + "withdrawFromStrategy(address,address[],uint256[])": { + "notice": "Withdraw multiple asset from the strategy to the vault." + }, + "withdrawalClaimDelay()": { + "notice": "Sets a minimum delay that is required to elapse between requesting async withdrawals and claiming the request. When set to 0 async withdrawals are disabled." + }, + "withdrawalQueueMetadata()": { + "notice": "Global metadata for the withdrawal queue including: queued - cumulative total of all withdrawal requests included the ones that have already been claimed claimable - cumulative total of all the requests that can be claimed including the ones already claimed claimed - total of all the requests that have been claimed nextWithdrawalIndex - index of the next withdrawal request starting at 0" + }, + "withdrawalRequests(uint256)": { + "notice": "Mapping of withdrawal request indices to the user withdrawal request data" + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 42033, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "initialized", + "offset": 0, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 42036, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "initializing", + "offset": 1, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 42076, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "______gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 45777, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "_deprecated_assets", + "offset": 0, + "slot": "51", + "type": "t_uint256" + }, + { + "astId": 45781, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "_deprecated_allAssets", + "offset": 0, + "slot": "52", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 45792, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "strategies", + "offset": 0, + "slot": "53", + "type": "t_mapping(t_address,t_struct(Strategy)45786_storage)" + }, + { + "astId": 45796, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "allStrategies", + "offset": 0, + "slot": "54", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 45799, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "_deprecated_priceProvider", + "offset": 0, + "slot": "55", + "type": "t_address" + }, + { + "astId": 45802, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "rebasePaused", + "offset": 20, + "slot": "55", + "type": "t_bool" + }, + { + "astId": 45805, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "capitalPaused", + "offset": 21, + "slot": "55", + "type": "t_bool" + }, + { + "astId": 45808, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "_deprecated_redeemFeeBps", + "offset": 0, + "slot": "56", + "type": "t_uint256" + }, + { + "astId": 45811, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "vaultBuffer", + "offset": 0, + "slot": "57", + "type": "t_uint256" + }, + { + "astId": 45814, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "autoAllocateThreshold", + "offset": 0, + "slot": "58", + "type": "t_uint256" + }, + { + "astId": 45817, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "__deprecatedRebaseThreshold", + "offset": 0, + "slot": "59", + "type": "t_uint256" + }, + { + "astId": 45821, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "oToken", + "offset": 0, + "slot": "60", + "type": "t_contract(OUSD)41354" + }, + { + "astId": 45828, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "_deprecated_rebaseHooksAddr", + "offset": 0, + "slot": "61", + "type": "t_address" + }, + { + "astId": 45835, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "_deprecated_uniswapAddr", + "offset": 0, + "slot": "62", + "type": "t_address" + }, + { + "astId": 45842, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "strategistAddr", + "offset": 0, + "slot": "63", + "type": "t_address" + }, + { + "astId": 45845, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "_deprecated_assetDefaultStrategies", + "offset": 0, + "slot": "64", + "type": "t_uint256" + }, + { + "astId": 45848, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "maxSupplyDiff", + "offset": 0, + "slot": "65", + "type": "t_uint256" + }, + { + "astId": 45851, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "trusteeAddress", + "offset": 0, + "slot": "66", + "type": "t_address" + }, + { + "astId": 45854, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "trusteeFeeBps", + "offset": 0, + "slot": "67", + "type": "t_uint256" + }, + { + "astId": 45858, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "_deprecated_swapTokens", + "offset": 0, + "slot": "68", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 45861, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "_deprecated_ousdMetaStrategy", + "offset": 0, + "slot": "69", + "type": "t_address" + }, + { + "astId": 45864, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "_deprecated_netOusdMintedForStrategy", + "offset": 0, + "slot": "70", + "type": "t_int256" + }, + { + "astId": 45867, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "_deprecated_netOusdMintForStrategyThreshold", + "offset": 0, + "slot": "71", + "type": "t_uint256" + }, + { + "astId": 45869, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "_deprecated_swapConfig", + "offset": 0, + "slot": "72", + "type": "t_uint256" + }, + { + "astId": 45873, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "isMintWhitelistedStrategy", + "offset": 0, + "slot": "73", + "type": "t_mapping(t_address,t_bool)" + }, + { + "astId": 45876, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "_deprecated_dripper", + "offset": 0, + "slot": "74", + "type": "t_address" + }, + { + "astId": 45890, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "withdrawalQueueMetadata", + "offset": 0, + "slot": "75", + "type": "t_struct(WithdrawalQueueMetadata)45886_storage" + }, + { + "astId": 45907, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "withdrawalRequests", + "offset": 0, + "slot": "77", + "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)45901_storage)" + }, + { + "astId": 45910, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "withdrawalClaimDelay", + "offset": 0, + "slot": "78", + "type": "t_uint256" + }, + { + "astId": 45913, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "lastRebase", + "offset": 0, + "slot": "79", + "type": "t_uint64" + }, + { + "astId": 45916, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "dripDuration", + "offset": 8, + "slot": "79", + "type": "t_uint64" + }, + { + "astId": 45919, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "rebasePerSecondMax", + "offset": 16, + "slot": "79", + "type": "t_uint64" + }, + { + "astId": 45922, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "rebasePerSecondTarget", + "offset": 24, + "slot": "79", + "type": "t_uint64" + }, + { + "astId": 45936, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "defaultStrategy", + "offset": 0, + "slot": "80", + "type": "t_address" + }, + { + "astId": 45939, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "operatorAddr", + "offset": 0, + "slot": "81", + "type": "t_address" + }, + { + "astId": 45943, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "__gap", + "offset": 0, + "slot": "82", + "type": "t_array(t_uint256)41_storage" + }, + { + "astId": 45946, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "_deprecated_wethAssetIndex", + "offset": 0, + "slot": "123", + "type": "t_uint256" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_address)dyn_storage": { + "base": "t_address", + "encoding": "dynamic_array", + "label": "address[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)41_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[41]", + "numberOfBytes": "1312" + }, + "t_array(t_uint256)50_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(OUSD)41354": { + "encoding": "inplace", + "label": "contract OUSD", + "numberOfBytes": "20" + }, + "t_int256": { + "encoding": "inplace", + "label": "int256", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_address,t_struct(Strategy)45786_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct VaultStorage.Strategy)", + "numberOfBytes": "32", + "value": "t_struct(Strategy)45786_storage" + }, + "t_mapping(t_uint256,t_struct(WithdrawalRequest)45901_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct VaultStorage.WithdrawalRequest)", + "numberOfBytes": "32", + "value": "t_struct(WithdrawalRequest)45901_storage" + }, + "t_struct(Strategy)45786_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.Strategy", + "members": [ + { + "astId": 45783, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "isSupported", + "offset": 0, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 45785, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "_deprecated", + "offset": 0, + "slot": "1", + "type": "t_uint256" + } + ], + "numberOfBytes": "64" + }, + "t_struct(WithdrawalQueueMetadata)45886_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.WithdrawalQueueMetadata", + "members": [ + { + "astId": 45879, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "queued", + "offset": 0, + "slot": "0", + "type": "t_uint128" + }, + { + "astId": 45881, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "claimable", + "offset": 16, + "slot": "0", + "type": "t_uint128" + }, + { + "astId": 45883, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "claimed", + "offset": 0, + "slot": "1", + "type": "t_uint128" + }, + { + "astId": 45885, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "nextWithdrawalIndex", + "offset": 16, + "slot": "1", + "type": "t_uint128" + } + ], + "numberOfBytes": "64" + }, + "t_struct(WithdrawalRequest)45901_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.WithdrawalRequest", + "members": [ + { + "astId": 45892, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "withdrawer", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 45894, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "claimed", + "offset": 20, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 45896, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "timestamp", + "offset": 21, + "slot": "0", + "type": "t_uint40" + }, + { + "astId": 45898, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "amount", + "offset": 0, + "slot": "1", + "type": "t_uint128" + }, + { + "astId": 45900, + "contract": "contracts/vault/OSVault.sol:OSVault", + "label": "queued", + "offset": 16, + "slot": "1", + "type": "t_uint128" + } + ], + "numberOfBytes": "64" + }, + "t_uint128": { + "encoding": "inplace", + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint40": { + "encoding": "inplace", + "label": "uint40", + "numberOfBytes": "5" + }, + "t_uint64": { + "encoding": "inplace", + "label": "uint64", + "numberOfBytes": "8" + } + } + } +} \ No newline at end of file diff --git a/contracts/deployments/sonic/operations/029_vault_permissioned_rebase.execute.json b/contracts/deployments/sonic/operations/029_vault_permissioned_rebase.execute.json new file mode 100644 index 0000000000..4d96d3cf84 --- /dev/null +++ b/contracts/deployments/sonic/operations/029_vault_permissioned_rebase.execute.json @@ -0,0 +1,52 @@ +{ + "version": "1.0", + "chainId": "146", + "createdAt": 1778496677, + "meta": { + "name": "Transaction Batch", + "description": "", + "txBuilderVersion": "1.16.1", + "createdFromSafeAddress": "0xAdDEA7933Db7d83855786EB43a238111C69B00b6", + "createdFromOwnerAddress": "" + }, + "transactions": [ + { + "to": "0x31a91336414d3B955E494E7d485a6B06b55FC8fB", + "value": "0", + "data": null, + "contractMethod": { + "inputs": [ + { + "type": "address[]", + "name": "targets" + }, + { + "type": "uint256[]", + "name": "values" + }, + { + "type": "bytes[]", + "name": "payloads" + }, + { + "type": "bytes32", + "name": "predecessor" + }, + { + "type": "bytes32", + "name": "salt" + } + ], + "name": "executeBatch", + "payable": true + }, + "contractInputsValues": { + "targets": "[\"0xa3c0eCA00D2B76b4d1F170b0AB3FdeA16C180186\",\"0xa3c0eCA00D2B76b4d1F170b0AB3FdeA16C180186\"]", + "values": "[\"0\",\"0\"]", + "payloads": "[\"0x3659cfe6000000000000000000000000f66886e242e20cab2496af1d411ebcfb73440270\",\"0x9e4285520000000000000000000000000abcda6fa7d500cf69b0ea5de9a607cd9941221c\"]", + "predecessor": "0x0000000000000000000000000000000000000000000000000000000000000000", + "salt": "0xad6318e3bf63896fe4a7816e7b2957639f59e729b8839f1b90308e8c69a57a89" + } + } + ] +} \ No newline at end of file diff --git a/contracts/deployments/sonic/operations/029_vault_permissioned_rebase.schedule.json b/contracts/deployments/sonic/operations/029_vault_permissioned_rebase.schedule.json new file mode 100644 index 0000000000..263b52e6d6 --- /dev/null +++ b/contracts/deployments/sonic/operations/029_vault_permissioned_rebase.schedule.json @@ -0,0 +1,57 @@ +{ + "version": "1.0", + "chainId": "146", + "createdAt": 1778496677, + "meta": { + "name": "Transaction Batch", + "description": "", + "txBuilderVersion": "1.16.1", + "createdFromSafeAddress": "0xAdDEA7933Db7d83855786EB43a238111C69B00b6", + "createdFromOwnerAddress": "" + }, + "transactions": [ + { + "to": "0x31a91336414d3B955E494E7d485a6B06b55FC8fB", + "value": "0", + "data": null, + "contractMethod": { + "inputs": [ + { + "type": "address[]", + "name": "targets" + }, + { + "type": "uint256[]", + "name": "values" + }, + { + "type": "bytes[]", + "name": "payloads" + }, + { + "type": "bytes32", + "name": "predecessor" + }, + { + "type": "bytes32", + "name": "salt" + }, + { + "type": "uint256", + "name": "delay" + } + ], + "name": "scheduleBatch", + "payable": false + }, + "contractInputsValues": { + "targets": "[\"0xa3c0eCA00D2B76b4d1F170b0AB3FdeA16C180186\",\"0xa3c0eCA00D2B76b4d1F170b0AB3FdeA16C180186\"]", + "values": "[\"0\",\"0\"]", + "payloads": "[\"0x3659cfe6000000000000000000000000f66886e242e20cab2496af1d411ebcfb73440270\",\"0x9e4285520000000000000000000000000abcda6fa7d500cf69b0ea5de9a607cd9941221c\"]", + "predecessor": "0x0000000000000000000000000000000000000000000000000000000000000000", + "salt": "0xad6318e3bf63896fe4a7816e7b2957639f59e729b8839f1b90308e8c69a57a89", + "delay": "172800" + } + } + ] +} \ No newline at end of file diff --git a/contracts/deployments/sonic/solcInputs/f4384e86fd2a870879603d18d53c5b16.json b/contracts/deployments/sonic/solcInputs/f4384e86fd2a870879603d18d53c5b16.json new file mode 100644 index 0000000000..0a3f9df551 --- /dev/null +++ b/contracts/deployments/sonic/solcInputs/f4384e86fd2a870879603d18d53c5b16.json @@ -0,0 +1,537 @@ +{ + "language": "Solidity", + "sources": { + "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {Client} from \"../libraries/Client.sol\";\n\ninterface IRouterClient {\n error UnsupportedDestinationChain(uint64 destChainSelector);\n error InsufficientFeeTokenAmount();\n error InvalidMsgValue();\n\n /// @notice Checks if the given chain ID is supported for sending/receiving.\n /// @param chainSelector The chain to check.\n /// @return supported is true if it is supported, false if not.\n function isChainSupported(uint64 chainSelector) external view returns (bool supported);\n\n /// @notice Gets a list of all supported tokens which can be sent or received\n /// to/from a given chain id.\n /// @param chainSelector The chainSelector.\n /// @return tokens The addresses of all tokens that are supported.\n function getSupportedTokens(uint64 chainSelector) external view returns (address[] memory tokens);\n\n /// @param destinationChainSelector The destination chainSelector\n /// @param message The cross-chain CCIP message including data and/or tokens\n /// @return fee returns execution fee for the message\n /// delivery to destination chain, denominated in the feeToken specified in the message.\n /// @dev Reverts with appropriate reason upon invalid message.\n function getFee(\n uint64 destinationChainSelector,\n Client.EVM2AnyMessage memory message\n ) external view returns (uint256 fee);\n\n /// @notice Request a message to be sent to the destination chain\n /// @param destinationChainSelector The destination chain ID\n /// @param message The cross-chain CCIP message including data and/or tokens\n /// @return messageId The message ID\n /// @dev Note if msg.value is larger than the required fee (from getFee) we accept\n /// the overpayment with no refund.\n /// @dev Reverts with appropriate reason upon invalid message.\n function ccipSend(\n uint64 destinationChainSelector,\n Client.EVM2AnyMessage calldata message\n ) external payable returns (bytes32);\n}\n" + }, + "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// End consumer library.\nlibrary Client {\n /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.\n struct EVMTokenAmount {\n address token; // token address on the local chain.\n uint256 amount; // Amount of tokens.\n }\n\n struct Any2EVMMessage {\n bytes32 messageId; // MessageId corresponding to ccipSend on source.\n uint64 sourceChainSelector; // Source chain selector.\n bytes sender; // abi.decode(sender) if coming from an EVM chain.\n bytes data; // payload sent in original message.\n EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation.\n }\n\n // If extraArgs is empty bytes, the default is 200k gas limit.\n struct EVM2AnyMessage {\n bytes receiver; // abi.encode(receiver address) for dest EVM chains\n bytes data; // Data payload\n EVMTokenAmount[] tokenAmounts; // Token transfers\n address feeToken; // Address of feeToken. address(0) means you will send msg.value.\n bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV1)\n }\n\n // bytes4(keccak256(\"CCIP EVMExtraArgsV1\"));\n bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9;\n struct EVMExtraArgsV1 {\n uint256 gasLimit;\n }\n\n function _argsToBytes(EVMExtraArgsV1 memory extraArgs) internal pure returns (bytes memory bts) {\n return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs);\n }\n}\n" + }, + "@layerzerolabs/lz-evm-messagelib-v2/contracts/libs/ExecutorOptions.sol": { + "content": "// SPDX-License-Identifier: LZBL-1.2\n\npragma solidity ^0.8.20;\n\nimport \"@layerzerolabs/lz-evm-protocol-v2/contracts/libs/CalldataBytesLib.sol\";\n\nlibrary ExecutorOptions {\n using CalldataBytesLib for bytes;\n\n uint8 internal constant WORKER_ID = 1;\n\n uint8 internal constant OPTION_TYPE_LZRECEIVE = 1;\n uint8 internal constant OPTION_TYPE_NATIVE_DROP = 2;\n uint8 internal constant OPTION_TYPE_LZCOMPOSE = 3;\n uint8 internal constant OPTION_TYPE_ORDERED_EXECUTION = 4;\n uint8 internal constant OPTION_TYPE_LZREAD = 5;\n\n error Executor_InvalidLzReceiveOption();\n error Executor_InvalidNativeDropOption();\n error Executor_InvalidLzComposeOption();\n error Executor_InvalidLzReadOption();\n\n /// @dev decode the next executor option from the options starting from the specified cursor\n /// @param _options [executor_id][executor_option][executor_id][executor_option]...\n /// executor_option = [option_size][option_type][option]\n /// option_size = len(option_type) + len(option)\n /// executor_id: uint8, option_size: uint16, option_type: uint8, option: bytes\n /// @param _cursor the cursor to start decoding from\n /// @return optionType the type of the option\n /// @return option the option of the executor\n /// @return cursor the cursor to start decoding the next executor option\n function nextExecutorOption(\n bytes calldata _options,\n uint256 _cursor\n ) internal pure returns (uint8 optionType, bytes calldata option, uint256 cursor) {\n unchecked {\n // skip worker id\n cursor = _cursor + 1;\n\n // read option size\n uint16 size = _options.toU16(cursor);\n cursor += 2;\n\n // read option type\n optionType = _options.toU8(cursor);\n\n // startCursor and endCursor are used to slice the option from _options\n uint256 startCursor = cursor + 1; // skip option type\n uint256 endCursor = cursor + size;\n option = _options[startCursor:endCursor];\n cursor += size;\n }\n }\n\n function decodeLzReceiveOption(bytes calldata _option) internal pure returns (uint128 gas, uint128 value) {\n if (_option.length != 16 && _option.length != 32) revert Executor_InvalidLzReceiveOption();\n gas = _option.toU128(0);\n value = _option.length == 32 ? _option.toU128(16) : 0;\n }\n\n function decodeNativeDropOption(bytes calldata _option) internal pure returns (uint128 amount, bytes32 receiver) {\n if (_option.length != 48) revert Executor_InvalidNativeDropOption();\n amount = _option.toU128(0);\n receiver = _option.toB32(16);\n }\n\n function decodeLzComposeOption(\n bytes calldata _option\n ) internal pure returns (uint16 index, uint128 gas, uint128 value) {\n if (_option.length != 18 && _option.length != 34) revert Executor_InvalidLzComposeOption();\n index = _option.toU16(0);\n gas = _option.toU128(2);\n value = _option.length == 34 ? _option.toU128(18) : 0;\n }\n\n function decodeLzReadOption(\n bytes calldata _option\n ) internal pure returns (uint128 gas, uint32 calldataSize, uint128 value) {\n if (_option.length != 20 && _option.length != 36) revert Executor_InvalidLzReadOption();\n gas = _option.toU128(0);\n calldataSize = _option.toU32(16);\n value = _option.length == 36 ? _option.toU128(20) : 0;\n }\n\n function encodeLzReceiveOption(uint128 _gas, uint128 _value) internal pure returns (bytes memory) {\n return _value == 0 ? abi.encodePacked(_gas) : abi.encodePacked(_gas, _value);\n }\n\n function encodeNativeDropOption(uint128 _amount, bytes32 _receiver) internal pure returns (bytes memory) {\n return abi.encodePacked(_amount, _receiver);\n }\n\n function encodeLzComposeOption(uint16 _index, uint128 _gas, uint128 _value) internal pure returns (bytes memory) {\n return _value == 0 ? abi.encodePacked(_index, _gas) : abi.encodePacked(_index, _gas, _value);\n }\n\n function encodeLzReadOption(\n uint128 _gas,\n uint32 _calldataSize,\n uint128 _value\n ) internal pure returns (bytes memory) {\n return _value == 0 ? abi.encodePacked(_gas, _calldataSize) : abi.encodePacked(_gas, _calldataSize, _value);\n }\n}\n" + }, + "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/libs/DVNOptions.sol": { + "content": "// SPDX-License-Identifier: LZBL-1.2\n\npragma solidity ^0.8.20;\n\nimport { BytesLib } from \"solidity-bytes-utils/contracts/BytesLib.sol\";\n\nimport { BitMap256 } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/BitMaps.sol\";\nimport { CalldataBytesLib } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/libs/CalldataBytesLib.sol\";\n\nlibrary DVNOptions {\n using CalldataBytesLib for bytes;\n using BytesLib for bytes;\n\n uint8 internal constant WORKER_ID = 2;\n uint8 internal constant OPTION_TYPE_PRECRIME = 1;\n\n error DVN_InvalidDVNIdx();\n error DVN_InvalidDVNOptions(uint256 cursor);\n\n /// @dev group dvn options by its idx\n /// @param _options [dvn_id][dvn_option][dvn_id][dvn_option]...\n /// dvn_option = [option_size][dvn_idx][option_type][option]\n /// option_size = len(dvn_idx) + len(option_type) + len(option)\n /// dvn_id: uint8, dvn_idx: uint8, option_size: uint16, option_type: uint8, option: bytes\n /// @return dvnOptions the grouped options, still share the same format of _options\n /// @return dvnIndices the dvn indices\n function groupDVNOptionsByIdx(\n bytes memory _options\n ) internal pure returns (bytes[] memory dvnOptions, uint8[] memory dvnIndices) {\n if (_options.length == 0) return (dvnOptions, dvnIndices);\n\n uint8 numDVNs = getNumDVNs(_options);\n\n // if there is only 1 dvn, we can just return the whole options\n if (numDVNs == 1) {\n dvnOptions = new bytes[](1);\n dvnOptions[0] = _options;\n\n dvnIndices = new uint8[](1);\n dvnIndices[0] = _options.toUint8(3); // dvn idx\n return (dvnOptions, dvnIndices);\n }\n\n // otherwise, we need to group the options by dvn_idx\n dvnIndices = new uint8[](numDVNs);\n dvnOptions = new bytes[](numDVNs);\n unchecked {\n uint256 cursor = 0;\n uint256 start = 0;\n uint8 lastDVNIdx = 255; // 255 is an invalid dvn_idx\n\n while (cursor < _options.length) {\n ++cursor; // skip worker_id\n\n // optionLength asserted in getNumDVNs (skip check)\n uint16 optionLength = _options.toUint16(cursor);\n cursor += 2;\n\n // dvnIdx asserted in getNumDVNs (skip check)\n uint8 dvnIdx = _options.toUint8(cursor);\n\n // dvnIdx must equal to the lastDVNIdx for the first option\n // so it is always skipped in the first option\n // this operation slices out options whenever the scan finds a different lastDVNIdx\n if (lastDVNIdx == 255) {\n lastDVNIdx = dvnIdx;\n } else if (dvnIdx != lastDVNIdx) {\n uint256 len = cursor - start - 3; // 3 is for worker_id and option_length\n bytes memory opt = _options.slice(start, len);\n _insertDVNOptions(dvnOptions, dvnIndices, lastDVNIdx, opt);\n\n // reset the start and lastDVNIdx\n start += len;\n lastDVNIdx = dvnIdx;\n }\n\n cursor += optionLength;\n }\n\n // skip check the cursor here because the cursor is asserted in getNumDVNs\n // if we have reached the end of the options, we need to process the last dvn\n uint256 size = cursor - start;\n bytes memory op = _options.slice(start, size);\n _insertDVNOptions(dvnOptions, dvnIndices, lastDVNIdx, op);\n\n // revert dvnIndices to start from 0\n for (uint8 i = 0; i < numDVNs; ++i) {\n --dvnIndices[i];\n }\n }\n }\n\n function _insertDVNOptions(\n bytes[] memory _dvnOptions,\n uint8[] memory _dvnIndices,\n uint8 _dvnIdx,\n bytes memory _newOptions\n ) internal pure {\n // dvnIdx starts from 0 but default value of dvnIndices is 0,\n // so we tell if the slot is empty by adding 1 to dvnIdx\n if (_dvnIdx == 255) revert DVN_InvalidDVNIdx();\n uint8 dvnIdxAdj = _dvnIdx + 1;\n\n for (uint256 j = 0; j < _dvnIndices.length; ++j) {\n uint8 index = _dvnIndices[j];\n if (dvnIdxAdj == index) {\n _dvnOptions[j] = abi.encodePacked(_dvnOptions[j], _newOptions);\n break;\n } else if (index == 0) {\n // empty slot, that means it is the first time we see this dvn\n _dvnIndices[j] = dvnIdxAdj;\n _dvnOptions[j] = _newOptions;\n break;\n }\n }\n }\n\n /// @dev get the number of unique dvns\n /// @param _options the format is the same as groupDVNOptionsByIdx\n function getNumDVNs(bytes memory _options) internal pure returns (uint8 numDVNs) {\n uint256 cursor = 0;\n BitMap256 bitmap;\n\n // find number of unique dvn_idx\n unchecked {\n while (cursor < _options.length) {\n ++cursor; // skip worker_id\n\n uint16 optionLength = _options.toUint16(cursor);\n cursor += 2;\n if (optionLength < 2) revert DVN_InvalidDVNOptions(cursor); // at least 1 byte for dvn_idx and 1 byte for option_type\n\n uint8 dvnIdx = _options.toUint8(cursor);\n\n // if dvnIdx is not set, increment numDVNs\n // max num of dvns is 255, 255 is an invalid dvn_idx\n // The order of the dvnIdx is not required to be sequential, as enforcing the order may weaken\n // the composability of the options. e.g. if we refrain from enforcing the order, an OApp that has\n // already enforced certain options can append additional options to the end of the enforced\n // ones without restrictions.\n if (dvnIdx == 255) revert DVN_InvalidDVNIdx();\n if (!bitmap.get(dvnIdx)) {\n ++numDVNs;\n bitmap = bitmap.set(dvnIdx);\n }\n\n cursor += optionLength;\n }\n }\n if (cursor != _options.length) revert DVN_InvalidDVNOptions(cursor);\n }\n\n /// @dev decode the next dvn option from _options starting from the specified cursor\n /// @param _options the format is the same as groupDVNOptionsByIdx\n /// @param _cursor the cursor to start decoding\n /// @return optionType the type of the option\n /// @return option the option\n /// @return cursor the cursor to start decoding the next option\n function nextDVNOption(\n bytes calldata _options,\n uint256 _cursor\n ) internal pure returns (uint8 optionType, bytes calldata option, uint256 cursor) {\n unchecked {\n // skip worker id\n cursor = _cursor + 1;\n\n // read option size\n uint16 size = _options.toU16(cursor);\n cursor += 2;\n\n // read option type\n optionType = _options.toU8(cursor + 1); // skip dvn_idx\n\n // startCursor and endCursor are used to slice the option from _options\n uint256 startCursor = cursor + 2; // skip option type and dvn_idx\n uint256 endCursor = cursor + size;\n option = _options[startCursor:endCursor];\n cursor += size;\n }\n }\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\nimport { IMessageLibManager } from \"./IMessageLibManager.sol\";\nimport { IMessagingComposer } from \"./IMessagingComposer.sol\";\nimport { IMessagingChannel } from \"./IMessagingChannel.sol\";\nimport { IMessagingContext } from \"./IMessagingContext.sol\";\n\nstruct MessagingParams {\n uint32 dstEid;\n bytes32 receiver;\n bytes message;\n bytes options;\n bool payInLzToken;\n}\n\nstruct MessagingReceipt {\n bytes32 guid;\n uint64 nonce;\n MessagingFee fee;\n}\n\nstruct MessagingFee {\n uint256 nativeFee;\n uint256 lzTokenFee;\n}\n\nstruct Origin {\n uint32 srcEid;\n bytes32 sender;\n uint64 nonce;\n}\n\ninterface ILayerZeroEndpointV2 is IMessageLibManager, IMessagingComposer, IMessagingChannel, IMessagingContext {\n event PacketSent(bytes encodedPayload, bytes options, address sendLibrary);\n\n event PacketVerified(Origin origin, address receiver, bytes32 payloadHash);\n\n event PacketDelivered(Origin origin, address receiver);\n\n event LzReceiveAlert(\n address indexed receiver,\n address indexed executor,\n Origin origin,\n bytes32 guid,\n uint256 gas,\n uint256 value,\n bytes message,\n bytes extraData,\n bytes reason\n );\n\n event LzTokenSet(address token);\n\n event DelegateSet(address sender, address delegate);\n\n function quote(MessagingParams calldata _params, address _sender) external view returns (MessagingFee memory);\n\n function send(\n MessagingParams calldata _params,\n address _refundAddress\n ) external payable returns (MessagingReceipt memory);\n\n function verify(Origin calldata _origin, address _receiver, bytes32 _payloadHash) external;\n\n function verifiable(Origin calldata _origin, address _receiver) external view returns (bool);\n\n function initializable(Origin calldata _origin, address _receiver) external view returns (bool);\n\n function lzReceive(\n Origin calldata _origin,\n address _receiver,\n bytes32 _guid,\n bytes calldata _message,\n bytes calldata _extraData\n ) external payable;\n\n // oapp can burn messages partially by calling this function with its own business logic if messages are verified in order\n function clear(address _oapp, Origin calldata _origin, bytes32 _guid, bytes calldata _message) external;\n\n function setLzToken(address _lzToken) external;\n\n function lzToken() external view returns (address);\n\n function nativeToken() external view returns (address);\n\n function setDelegate(address _delegate) external;\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLibManager.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\nstruct SetConfigParam {\n uint32 eid;\n uint32 configType;\n bytes config;\n}\n\ninterface IMessageLibManager {\n struct Timeout {\n address lib;\n uint256 expiry;\n }\n\n event LibraryRegistered(address newLib);\n event DefaultSendLibrarySet(uint32 eid, address newLib);\n event DefaultReceiveLibrarySet(uint32 eid, address newLib);\n event DefaultReceiveLibraryTimeoutSet(uint32 eid, address oldLib, uint256 expiry);\n event SendLibrarySet(address sender, uint32 eid, address newLib);\n event ReceiveLibrarySet(address receiver, uint32 eid, address newLib);\n event ReceiveLibraryTimeoutSet(address receiver, uint32 eid, address oldLib, uint256 timeout);\n\n function registerLibrary(address _lib) external;\n\n function isRegisteredLibrary(address _lib) external view returns (bool);\n\n function getRegisteredLibraries() external view returns (address[] memory);\n\n function setDefaultSendLibrary(uint32 _eid, address _newLib) external;\n\n function defaultSendLibrary(uint32 _eid) external view returns (address);\n\n function setDefaultReceiveLibrary(uint32 _eid, address _newLib, uint256 _gracePeriod) external;\n\n function defaultReceiveLibrary(uint32 _eid) external view returns (address);\n\n function setDefaultReceiveLibraryTimeout(uint32 _eid, address _lib, uint256 _expiry) external;\n\n function defaultReceiveLibraryTimeout(uint32 _eid) external view returns (address lib, uint256 expiry);\n\n function isSupportedEid(uint32 _eid) external view returns (bool);\n\n function isValidReceiveLibrary(address _receiver, uint32 _eid, address _lib) external view returns (bool);\n\n /// ------------------- OApp interfaces -------------------\n function setSendLibrary(address _oapp, uint32 _eid, address _newLib) external;\n\n function getSendLibrary(address _sender, uint32 _eid) external view returns (address lib);\n\n function isDefaultSendLibrary(address _sender, uint32 _eid) external view returns (bool);\n\n function setReceiveLibrary(address _oapp, uint32 _eid, address _newLib, uint256 _gracePeriod) external;\n\n function getReceiveLibrary(address _receiver, uint32 _eid) external view returns (address lib, bool isDefault);\n\n function setReceiveLibraryTimeout(address _oapp, uint32 _eid, address _lib, uint256 _expiry) external;\n\n function receiveLibraryTimeout(address _receiver, uint32 _eid) external view returns (address lib, uint256 expiry);\n\n function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external;\n\n function getConfig(\n address _oapp,\n address _lib,\n uint32 _eid,\n uint32 _configType\n ) external view returns (bytes memory config);\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessagingChannel.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\ninterface IMessagingChannel {\n event InboundNonceSkipped(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce);\n event PacketNilified(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash);\n event PacketBurnt(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash);\n\n function eid() external view returns (uint32);\n\n // this is an emergency function if a message cannot be verified for some reasons\n // required to provide _nextNonce to avoid race condition\n function skip(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce) external;\n\n function nilify(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external;\n\n function burn(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external;\n\n function nextGuid(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (bytes32);\n\n function inboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64);\n\n function outboundNonce(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (uint64);\n\n function inboundPayloadHash(\n address _receiver,\n uint32 _srcEid,\n bytes32 _sender,\n uint64 _nonce\n ) external view returns (bytes32);\n\n function lazyInboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64);\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessagingComposer.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\ninterface IMessagingComposer {\n event ComposeSent(address from, address to, bytes32 guid, uint16 index, bytes message);\n event ComposeDelivered(address from, address to, bytes32 guid, uint16 index);\n event LzComposeAlert(\n address indexed from,\n address indexed to,\n address indexed executor,\n bytes32 guid,\n uint16 index,\n uint256 gas,\n uint256 value,\n bytes message,\n bytes extraData,\n bytes reason\n );\n\n function composeQueue(\n address _from,\n address _to,\n bytes32 _guid,\n uint16 _index\n ) external view returns (bytes32 messageHash);\n\n function sendCompose(address _to, bytes32 _guid, uint16 _index, bytes calldata _message) external;\n\n function lzCompose(\n address _from,\n address _to,\n bytes32 _guid,\n uint16 _index,\n bytes calldata _message,\n bytes calldata _extraData\n ) external payable;\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessagingContext.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\ninterface IMessagingContext {\n function isSendingMessage() external view returns (bool);\n\n function getSendContext() external view returns (uint32 dstEid, address sender);\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/CalldataBytesLib.sol": { + "content": "// SPDX-License-Identifier: LZBL-1.2\n\npragma solidity ^0.8.20;\n\nlibrary CalldataBytesLib {\n function toU8(bytes calldata _bytes, uint256 _start) internal pure returns (uint8) {\n return uint8(_bytes[_start]);\n }\n\n function toU16(bytes calldata _bytes, uint256 _start) internal pure returns (uint16) {\n unchecked {\n uint256 end = _start + 2;\n return uint16(bytes2(_bytes[_start:end]));\n }\n }\n\n function toU32(bytes calldata _bytes, uint256 _start) internal pure returns (uint32) {\n unchecked {\n uint256 end = _start + 4;\n return uint32(bytes4(_bytes[_start:end]));\n }\n }\n\n function toU64(bytes calldata _bytes, uint256 _start) internal pure returns (uint64) {\n unchecked {\n uint256 end = _start + 8;\n return uint64(bytes8(_bytes[_start:end]));\n }\n }\n\n function toU128(bytes calldata _bytes, uint256 _start) internal pure returns (uint128) {\n unchecked {\n uint256 end = _start + 16;\n return uint128(bytes16(_bytes[_start:end]));\n }\n }\n\n function toU256(bytes calldata _bytes, uint256 _start) internal pure returns (uint256) {\n unchecked {\n uint256 end = _start + 32;\n return uint256(bytes32(_bytes[_start:end]));\n }\n }\n\n function toAddr(bytes calldata _bytes, uint256 _start) internal pure returns (address) {\n unchecked {\n uint256 end = _start + 20;\n return address(bytes20(_bytes[_start:end]));\n }\n }\n\n function toB32(bytes calldata _bytes, uint256 _start) internal pure returns (bytes32) {\n unchecked {\n uint256 end = _start + 32;\n return bytes32(_bytes[_start:end]);\n }\n }\n}\n" + }, + "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/BitMaps.sol": { + "content": "// SPDX-License-Identifier: MIT\n\n// modified from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/structs/BitMaps.sol\npragma solidity ^0.8.20;\n\ntype BitMap256 is uint256;\n\nusing BitMaps for BitMap256 global;\n\nlibrary BitMaps {\n /**\n * @dev Returns whether the bit at `index` is set.\n */\n function get(BitMap256 bitmap, uint8 index) internal pure returns (bool) {\n uint256 mask = 1 << index;\n return BitMap256.unwrap(bitmap) & mask != 0;\n }\n\n /**\n * @dev Sets the bit at `index`.\n */\n function set(BitMap256 bitmap, uint8 index) internal pure returns (BitMap256) {\n uint256 mask = 1 << index;\n return BitMap256.wrap(BitMap256.unwrap(bitmap) | mask);\n }\n}\n" + }, + "@layerzerolabs/oapp-evm/contracts/oapp/interfaces/IOAppCore.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { ILayerZeroEndpointV2 } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol\";\n\n/**\n * @title IOAppCore\n */\ninterface IOAppCore {\n // Custom error messages\n error OnlyPeer(uint32 eid, bytes32 sender);\n error NoPeer(uint32 eid);\n error InvalidEndpointCall();\n error InvalidDelegate();\n\n // Event emitted when a peer (OApp) is set for a corresponding endpoint\n event PeerSet(uint32 eid, bytes32 peer);\n\n /**\n * @notice Retrieves the OApp version information.\n * @return senderVersion The version of the OAppSender.sol contract.\n * @return receiverVersion The version of the OAppReceiver.sol contract.\n */\n function oAppVersion() external view returns (uint64 senderVersion, uint64 receiverVersion);\n\n /**\n * @notice Retrieves the LayerZero endpoint associated with the OApp.\n * @return iEndpoint The LayerZero endpoint as an interface.\n */\n function endpoint() external view returns (ILayerZeroEndpointV2 iEndpoint);\n\n /**\n * @notice Retrieves the peer (OApp) associated with a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @return peer The peer address (OApp instance) associated with the corresponding endpoint.\n */\n function peers(uint32 _eid) external view returns (bytes32 peer);\n\n /**\n * @notice Sets the peer address (OApp instance) for a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @param _peer The address of the peer to be associated with the corresponding endpoint.\n */\n function setPeer(uint32 _eid, bytes32 _peer) external;\n\n /**\n * @notice Sets the delegate address for the OApp Core.\n * @param _delegate The address of the delegate to be set.\n */\n function setDelegate(address _delegate) external;\n}\n" + }, + "@layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { BytesLib } from \"solidity-bytes-utils/contracts/BytesLib.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { ExecutorOptions } from \"@layerzerolabs/lz-evm-messagelib-v2/contracts/libs/ExecutorOptions.sol\";\nimport { DVNOptions } from \"@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/libs/DVNOptions.sol\";\n\n/**\n * @title OptionsBuilder\n * @dev Library for building and encoding various message options.\n */\nlibrary OptionsBuilder {\n using SafeCast for uint256;\n using BytesLib for bytes;\n\n // Constants for options types\n uint16 internal constant TYPE_1 = 1; // legacy options type 1\n uint16 internal constant TYPE_2 = 2; // legacy options type 2\n uint16 internal constant TYPE_3 = 3;\n\n // Custom error message\n error InvalidSize(uint256 max, uint256 actual);\n error InvalidOptionType(uint16 optionType);\n\n // Modifier to ensure only options of type 3 are used\n modifier onlyType3(bytes memory _options) {\n if (_options.toUint16(0) != TYPE_3) revert InvalidOptionType(_options.toUint16(0));\n _;\n }\n\n /**\n * @dev Creates a new options container with type 3.\n * @return options The newly created options container.\n */\n function newOptions() internal pure returns (bytes memory) {\n return abi.encodePacked(TYPE_3);\n }\n\n /**\n * @dev Adds an executor LZ receive option to the existing options.\n * @param _options The existing options container.\n * @param _gas The gasLimit used on the lzReceive() function in the OApp.\n * @param _value The msg.value passed to the lzReceive() function in the OApp.\n * @return options The updated options container.\n *\n * @dev When multiples of this option are added, they are summed by the executor\n * eg. if (_gas: 200k, and _value: 1 ether) AND (_gas: 100k, _value: 0.5 ether) are sent in an option to the LayerZeroEndpoint,\n * that becomes (300k, 1.5 ether) when the message is executed on the remote lzReceive() function.\n */\n function addExecutorLzReceiveOption(\n bytes memory _options,\n uint128 _gas,\n uint128 _value\n ) internal pure onlyType3(_options) returns (bytes memory) {\n bytes memory option = ExecutorOptions.encodeLzReceiveOption(_gas, _value);\n return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZRECEIVE, option);\n }\n\n /**\n * @dev Adds an executor native drop option to the existing options.\n * @param _options The existing options container.\n * @param _amount The amount for the native value that is airdropped to the 'receiver'.\n * @param _receiver The receiver address for the native drop option.\n * @return options The updated options container.\n *\n * @dev When multiples of this option are added, they are summed by the executor on the remote chain.\n */\n function addExecutorNativeDropOption(\n bytes memory _options,\n uint128 _amount,\n bytes32 _receiver\n ) internal pure onlyType3(_options) returns (bytes memory) {\n bytes memory option = ExecutorOptions.encodeNativeDropOption(_amount, _receiver);\n return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_NATIVE_DROP, option);\n }\n\n // /**\n // * @dev Adds an executor native drop option to the existing options.\n // * @param _options The existing options container.\n // * @param _amount The amount for the native value that is airdropped to the 'receiver'.\n // * @param _receiver The receiver address for the native drop option.\n // * @return options The updated options container.\n // *\n // * @dev When multiples of this option are added, they are summed by the executor on the remote chain.\n // */\n function addExecutorLzReadOption(\n bytes memory _options,\n uint128 _gas,\n uint32 _size,\n uint128 _value\n ) internal pure onlyType3(_options) returns (bytes memory) {\n bytes memory option = ExecutorOptions.encodeLzReadOption(_gas, _size, _value);\n return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZREAD, option);\n }\n\n /**\n * @dev Adds an executor LZ compose option to the existing options.\n * @param _options The existing options container.\n * @param _index The index for the lzCompose() function call.\n * @param _gas The gasLimit for the lzCompose() function call.\n * @param _value The msg.value for the lzCompose() function call.\n * @return options The updated options container.\n *\n * @dev When multiples of this option are added, they are summed PER index by the executor on the remote chain.\n * @dev If the OApp sends N lzCompose calls on the remote, you must provide N incremented indexes starting with 0.\n * ie. When your remote OApp composes (N = 3) messages, you must set this option for index 0,1,2\n */\n function addExecutorLzComposeOption(\n bytes memory _options,\n uint16 _index,\n uint128 _gas,\n uint128 _value\n ) internal pure onlyType3(_options) returns (bytes memory) {\n bytes memory option = ExecutorOptions.encodeLzComposeOption(_index, _gas, _value);\n return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZCOMPOSE, option);\n }\n\n /**\n * @dev Adds an executor ordered execution option to the existing options.\n * @param _options The existing options container.\n * @return options The updated options container.\n */\n function addExecutorOrderedExecutionOption(\n bytes memory _options\n ) internal pure onlyType3(_options) returns (bytes memory) {\n return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_ORDERED_EXECUTION, bytes(\"\"));\n }\n\n /**\n * @dev Adds a DVN pre-crime option to the existing options.\n * @param _options The existing options container.\n * @param _dvnIdx The DVN index for the pre-crime option.\n * @return options The updated options container.\n */\n function addDVNPreCrimeOption(\n bytes memory _options,\n uint8 _dvnIdx\n ) internal pure onlyType3(_options) returns (bytes memory) {\n return addDVNOption(_options, _dvnIdx, DVNOptions.OPTION_TYPE_PRECRIME, bytes(\"\"));\n }\n\n /**\n * @dev Adds an executor option to the existing options.\n * @param _options The existing options container.\n * @param _optionType The type of the executor option.\n * @param _option The encoded data for the executor option.\n * @return options The updated options container.\n */\n function addExecutorOption(\n bytes memory _options,\n uint8 _optionType,\n bytes memory _option\n ) internal pure onlyType3(_options) returns (bytes memory) {\n return\n abi.encodePacked(\n _options,\n ExecutorOptions.WORKER_ID,\n _option.length.toUint16() + 1, // +1 for optionType\n _optionType,\n _option\n );\n }\n\n /**\n * @dev Adds a DVN option to the existing options.\n * @param _options The existing options container.\n * @param _dvnIdx The DVN index for the DVN option.\n * @param _optionType The type of the DVN option.\n * @param _option The encoded data for the DVN option.\n * @return options The updated options container.\n */\n function addDVNOption(\n bytes memory _options,\n uint8 _dvnIdx,\n uint8 _optionType,\n bytes memory _option\n ) internal pure onlyType3(_options) returns (bytes memory) {\n return\n abi.encodePacked(\n _options,\n DVNOptions.WORKER_ID,\n _option.length.toUint16() + 2, // +2 for optionType and dvnIdx\n _dvnIdx,\n _optionType,\n _option\n );\n }\n\n /**\n * @dev Encodes legacy options of type 1.\n * @param _executionGas The gasLimit value passed to lzReceive().\n * @return legacyOptions The encoded legacy options.\n */\n function encodeLegacyOptionsType1(uint256 _executionGas) internal pure returns (bytes memory) {\n if (_executionGas > type(uint128).max) revert InvalidSize(type(uint128).max, _executionGas);\n return abi.encodePacked(TYPE_1, _executionGas);\n }\n\n /**\n * @dev Encodes legacy options of type 2.\n * @param _executionGas The gasLimit value passed to lzReceive().\n * @param _nativeForDst The amount of native air dropped to the receiver.\n * @param _receiver The _nativeForDst receiver address.\n * @return legacyOptions The encoded legacy options of type 2.\n */\n function encodeLegacyOptionsType2(\n uint256 _executionGas,\n uint256 _nativeForDst,\n bytes memory _receiver // @dev Use bytes instead of bytes32 in legacy type 2 for _receiver.\n ) internal pure returns (bytes memory) {\n if (_executionGas > type(uint128).max) revert InvalidSize(type(uint128).max, _executionGas);\n if (_nativeForDst > type(uint128).max) revert InvalidSize(type(uint128).max, _nativeForDst);\n if (_receiver.length > 32) revert InvalidSize(32, _receiver.length);\n return abi.encodePacked(TYPE_2, _executionGas, _nativeForDst, _receiver);\n }\n}\n" + }, + "@layerzerolabs/oapp-evm/contracts/oapp/OAppCore.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { IOAppCore, ILayerZeroEndpointV2 } from \"./interfaces/IOAppCore.sol\";\n\n/**\n * @title OAppCore\n * @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations.\n */\nabstract contract OAppCore is IOAppCore, Ownable {\n // The LayerZero endpoint associated with the given OApp\n ILayerZeroEndpointV2 public immutable endpoint;\n\n // Mapping to store peers associated with corresponding endpoints\n mapping(uint32 eid => bytes32 peer) public peers;\n\n /**\n * @dev Constructor to initialize the OAppCore with the provided endpoint and delegate.\n * @param _endpoint The address of the LOCAL Layer Zero endpoint.\n * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.\n *\n * @dev The delegate typically should be set as the owner of the contract.\n */\n constructor(address _endpoint, address _delegate) {\n endpoint = ILayerZeroEndpointV2(_endpoint);\n\n if (_delegate == address(0)) revert InvalidDelegate();\n endpoint.setDelegate(_delegate);\n }\n\n /**\n * @notice Sets the peer address (OApp instance) for a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @param _peer The address of the peer to be associated with the corresponding endpoint.\n *\n * @dev Only the owner/admin of the OApp can call this function.\n * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.\n * @dev Set this to bytes32(0) to remove the peer address.\n * @dev Peer is a bytes32 to accommodate non-evm chains.\n */\n function setPeer(uint32 _eid, bytes32 _peer) public virtual onlyOwner {\n _setPeer(_eid, _peer);\n }\n\n /**\n * @notice Sets the peer address (OApp instance) for a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @param _peer The address of the peer to be associated with the corresponding endpoint.\n *\n * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.\n * @dev Set this to bytes32(0) to remove the peer address.\n * @dev Peer is a bytes32 to accommodate non-evm chains.\n */\n function _setPeer(uint32 _eid, bytes32 _peer) internal virtual {\n peers[_eid] = _peer;\n emit PeerSet(_eid, _peer);\n }\n\n /**\n * @notice Internal function to get the peer address associated with a specific endpoint; reverts if NOT set.\n * ie. the peer is set to bytes32(0).\n * @param _eid The endpoint ID.\n * @return peer The address of the peer associated with the specified endpoint.\n */\n function _getPeerOrRevert(uint32 _eid) internal view virtual returns (bytes32) {\n bytes32 peer = peers[_eid];\n if (peer == bytes32(0)) revert NoPeer(_eid);\n return peer;\n }\n\n /**\n * @notice Sets the delegate address for the OApp.\n * @param _delegate The address of the delegate to be set.\n *\n * @dev Only the owner/admin of the OApp can call this function.\n * @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract.\n */\n function setDelegate(address _delegate) public onlyOwner {\n endpoint.setDelegate(_delegate);\n }\n}\n" + }, + "@layerzerolabs/oapp-evm/contracts/oapp/OAppSender.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { SafeERC20, IERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { MessagingParams, MessagingFee, MessagingReceipt } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol\";\nimport { OAppCore } from \"./OAppCore.sol\";\n\n/**\n * @title OAppSender\n * @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint.\n */\nabstract contract OAppSender is OAppCore {\n using SafeERC20 for IERC20;\n\n // Custom error messages\n error NotEnoughNative(uint256 msgValue);\n error LzTokenUnavailable();\n\n // @dev The version of the OAppSender implementation.\n // @dev Version is bumped when changes are made to this contract.\n uint64 internal constant SENDER_VERSION = 1;\n\n /**\n * @notice Retrieves the OApp version information.\n * @return senderVersion The version of the OAppSender.sol contract.\n * @return receiverVersion The version of the OAppReceiver.sol contract.\n *\n * @dev Providing 0 as the default for OAppReceiver version. Indicates that the OAppReceiver is not implemented.\n * ie. this is a SEND only OApp.\n * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions\n */\n function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {\n return (SENDER_VERSION, 0);\n }\n\n /**\n * @dev Internal function to interact with the LayerZero EndpointV2.quote() for fee calculation.\n * @param _dstEid The destination endpoint ID.\n * @param _message The message payload.\n * @param _options Additional options for the message.\n * @param _payInLzToken Flag indicating whether to pay the fee in LZ tokens.\n * @return fee The calculated MessagingFee for the message.\n * - nativeFee: The native fee for the message.\n * - lzTokenFee: The LZ token fee for the message.\n */\n function _quote(\n uint32 _dstEid,\n bytes memory _message,\n bytes memory _options,\n bool _payInLzToken\n ) internal view virtual returns (MessagingFee memory fee) {\n return\n endpoint.quote(\n MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _payInLzToken),\n address(this)\n );\n }\n\n /**\n * @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message.\n * @param _dstEid The destination endpoint ID.\n * @param _message The message payload.\n * @param _options Additional options for the message.\n * @param _fee The calculated LayerZero fee for the message.\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n * @param _refundAddress The address to receive any excess fee values sent to the endpoint.\n * @return receipt The receipt for the sent message.\n * - guid: The unique identifier for the sent message.\n * - nonce: The nonce of the sent message.\n * - fee: The LayerZero fee incurred for the message.\n */\n function _lzSend(\n uint32 _dstEid,\n bytes memory _message,\n bytes memory _options,\n MessagingFee memory _fee,\n address _refundAddress\n ) internal virtual returns (MessagingReceipt memory receipt) {\n // @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint.\n uint256 messageValue = _payNative(_fee.nativeFee);\n if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee);\n\n return\n // solhint-disable-next-line check-send-result\n endpoint.send{ value: messageValue }(\n MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0),\n _refundAddress\n );\n }\n\n /**\n * @dev Internal function to pay the native fee associated with the message.\n * @param _nativeFee The native fee to be paid.\n * @return nativeFee The amount of native currency paid.\n *\n * @dev If the OApp needs to initiate MULTIPLE LayerZero messages in a single transaction,\n * this will need to be overridden because msg.value would contain multiple lzFees.\n * @dev Should be overridden in the event the LayerZero endpoint requires a different native currency.\n * @dev Some EVMs use an ERC20 as a method for paying transactions/gasFees.\n * @dev The endpoint is EITHER/OR, ie. it will NOT support both types of native payment at a time.\n */\n function _payNative(uint256 _nativeFee) internal virtual returns (uint256 nativeFee) {\n if (msg.value != _nativeFee) revert NotEnoughNative(msg.value);\n return _nativeFee;\n }\n\n /**\n * @dev Internal function to pay the LZ token fee associated with the message.\n * @param _lzTokenFee The LZ token fee to be paid.\n *\n * @dev If the caller is trying to pay in the specified lzToken, then the lzTokenFee is passed to the endpoint.\n * @dev Any excess sent, is passed back to the specified _refundAddress in the _lzSend().\n */\n function _payLzToken(uint256 _lzTokenFee) internal virtual {\n // @dev Cannot cache the token because it is not immutable in the endpoint.\n address lzToken = endpoint.lzToken();\n if (lzToken == address(0)) revert LzTokenUnavailable();\n\n // Pay LZ token fee by sending tokens to the endpoint.\n IERC20(lzToken).safeTransferFrom(msg.sender, address(endpoint), _lzTokenFee);\n }\n}\n" + }, + "@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { MessagingReceipt, MessagingFee } from \"@layerzerolabs/oapp-evm/contracts/oapp/OAppSender.sol\";\n\n/**\n * @dev Struct representing token parameters for the OFT send() operation.\n */\nstruct SendParam {\n uint32 dstEid; // Destination endpoint ID.\n bytes32 to; // Recipient address.\n uint256 amountLD; // Amount to send in local decimals.\n uint256 minAmountLD; // Minimum amount to send in local decimals.\n bytes extraOptions; // Additional options supplied by the caller to be used in the LayerZero message.\n bytes composeMsg; // The composed message for the send() operation.\n bytes oftCmd; // The OFT command to be executed, unused in default OFT implementations.\n}\n\n/**\n * @dev Struct representing OFT limit information.\n * @dev These amounts can change dynamically and are up the specific oft implementation.\n */\nstruct OFTLimit {\n uint256 minAmountLD; // Minimum amount in local decimals that can be sent to the recipient.\n uint256 maxAmountLD; // Maximum amount in local decimals that can be sent to the recipient.\n}\n\n/**\n * @dev Struct representing OFT receipt information.\n */\nstruct OFTReceipt {\n uint256 amountSentLD; // Amount of tokens ACTUALLY debited from the sender in local decimals.\n // @dev In non-default implementations, the amountReceivedLD COULD differ from this value.\n uint256 amountReceivedLD; // Amount of tokens to be received on the remote side.\n}\n\n/**\n * @dev Struct representing OFT fee details.\n * @dev Future proof mechanism to provide a standardized way to communicate fees to things like a UI.\n */\nstruct OFTFeeDetail {\n int256 feeAmountLD; // Amount of the fee in local decimals.\n string description; // Description of the fee.\n}\n\n/**\n * @title IOFT\n * @dev Interface for the OftChain (OFT) token.\n * @dev Does not inherit ERC20 to accommodate usage by OFTAdapter as well.\n * @dev This specific interface ID is '0x02e49c2c'.\n */\ninterface IOFT {\n // Custom error messages\n error InvalidLocalDecimals();\n error SlippageExceeded(uint256 amountLD, uint256 minAmountLD);\n\n // Events\n event OFTSent(\n bytes32 indexed guid, // GUID of the OFT message.\n uint32 dstEid, // Destination Endpoint ID.\n address indexed fromAddress, // Address of the sender on the src chain.\n uint256 amountSentLD, // Amount of tokens sent in local decimals.\n uint256 amountReceivedLD // Amount of tokens received in local decimals.\n );\n event OFTReceived(\n bytes32 indexed guid, // GUID of the OFT message.\n uint32 srcEid, // Source Endpoint ID.\n address indexed toAddress, // Address of the recipient on the dst chain.\n uint256 amountReceivedLD // Amount of tokens received in local decimals.\n );\n\n /**\n * @notice Retrieves interfaceID and the version of the OFT.\n * @return interfaceId The interface ID.\n * @return version The version.\n *\n * @dev interfaceId: This specific interface ID is '0x02e49c2c'.\n * @dev version: Indicates a cross-chain compatible msg encoding with other OFTs.\n * @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented.\n * ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1)\n */\n function oftVersion() external view returns (bytes4 interfaceId, uint64 version);\n\n /**\n * @notice Retrieves the address of the token associated with the OFT.\n * @return token The address of the ERC20 token implementation.\n */\n function token() external view returns (address);\n\n /**\n * @notice Indicates whether the OFT contract requires approval of the 'token()' to send.\n * @return requiresApproval Needs approval of the underlying token implementation.\n *\n * @dev Allows things like wallet implementers to determine integration requirements,\n * without understanding the underlying token implementation.\n */\n function approvalRequired() external view returns (bool);\n\n /**\n * @notice Retrieves the shared decimals of the OFT.\n * @return sharedDecimals The shared decimals of the OFT.\n */\n function sharedDecimals() external view returns (uint8);\n\n /**\n * @notice Provides the fee breakdown and settings data for an OFT. Unused in the default implementation.\n * @param _sendParam The parameters for the send operation.\n * @return limit The OFT limit information.\n * @return oftFeeDetails The details of OFT fees.\n * @return receipt The OFT receipt information.\n */\n function quoteOFT(\n SendParam calldata _sendParam\n ) external view returns (OFTLimit memory, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory);\n\n /**\n * @notice Provides a quote for the send() operation.\n * @param _sendParam The parameters for the send() operation.\n * @param _payInLzToken Flag indicating whether the caller is paying in the LZ token.\n * @return fee The calculated LayerZero messaging fee from the send() operation.\n *\n * @dev MessagingFee: LayerZero msg fee\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n */\n function quoteSend(SendParam calldata _sendParam, bool _payInLzToken) external view returns (MessagingFee memory);\n\n /**\n * @notice Executes the send() operation.\n * @param _sendParam The parameters for the send operation.\n * @param _fee The fee information supplied by the caller.\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n * @param _refundAddress The address to receive any excess funds from fees etc. on the src.\n * @return receipt The LayerZero messaging receipt from the send() operation.\n * @return oftReceipt The OFT receipt information.\n *\n * @dev MessagingReceipt: LayerZero msg receipt\n * - guid: The unique identifier for the sent message.\n * - nonce: The nonce of the sent message.\n * - fee: The LayerZero fee incurred for the message.\n */\n function send(\n SendParam calldata _sendParam,\n MessagingFee calldata _fee,\n address _refundAddress\n ) external payable returns (MessagingReceipt memory, OFTReceipt memory);\n}\n" + }, + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role, _msgSender());\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(uint160(account), 20),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/AccessControlEnumerable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/AccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlEnumerable.sol\";\nimport \"./AccessControl.sol\";\nimport \"../utils/structs/EnumerableSet.sol\";\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view override returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view override returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override {\n super._grantRole(role, account);\n _roleMembers[role].add(account);\n }\n\n /**\n * @dev Overload {_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override {\n super._revokeRole(role, account);\n _roleMembers[role].remove(account);\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControlEnumerable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n" + }, + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "@openzeppelin/contracts/security/Pausable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract Pausable is Context {\n /**\n * @dev Emitted when the pause is triggered by `account`.\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by `account`.\n */\n event Unpaused(address account);\n\n bool private _paused;\n\n /**\n * @dev Initializes the contract in unpaused state.\n */\n constructor() {\n _paused = false;\n }\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view virtual returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n modifier whenNotPaused() {\n require(!paused(), \"Pausable: paused\");\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n modifier whenPaused() {\n require(paused(), \"Pausable: not paused\");\n _;\n }\n\n /**\n * @dev Triggers stopped state.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n function _pause() internal virtual whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Returns to normal state.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n function _unpause() internal virtual whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public virtual override returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * Requirements:\n *\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for ``sender``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public virtual override returns (bool) {\n _transfer(sender, recipient, amount);\n\n uint256 currentAllowance = _allowances[sender][_msgSender()];\n require(currentAllowance >= amount, \"ERC20: transfer amount exceeds allowance\");\n unchecked {\n _approve(sender, _msgSender(), currentAllowance - amount);\n }\n\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n uint256 currentAllowance = _allowances[_msgSender()][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(_msgSender(), spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal virtual {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(sender, recipient, amount);\n\n uint256 senderBalance = _balances[sender];\n require(senderBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[sender] = senderBalance - amount;\n }\n _balances[recipient] += amount;\n\n emit Transfer(sender, recipient, amount);\n\n _afterTokenTransfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize, which returns 0 for contracts in\n // construction, since the code is only stored at the end of the\n // constructor execution.\n\n uint256 size;\n assembly {\n size := extcodesize(account)\n }\n return size > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a >= b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a / b + (a % b == 0 ? 0 : 1);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeCast.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n require(value >= 0, \"SafeCast: value must be positive\");\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v3.1._\n */\n function toInt128(int256 value) internal pure returns (int128) {\n require(value >= type(int128).min && value <= type(int128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return int128(value);\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v3.1._\n */\n function toInt64(int256 value) internal pure returns (int64) {\n require(value >= type(int64).min && value <= type(int64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return int64(value);\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v3.1._\n */\n function toInt32(int256 value) internal pure returns (int32) {\n require(value >= type(int32).min && value <= type(int32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return int32(value);\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v3.1._\n */\n function toInt16(int256 value) internal pure returns (int16) {\n require(value >= type(int16).min && value <= type(int16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return int16(value);\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n *\n * _Available since v3.1._\n */\n function toInt8(int256 value) internal pure returns (int8) {\n require(value >= type(int8).min && value <= type(int8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return int8(value);\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n return int256(value);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeMath.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/structs/EnumerableSet.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(bytes32 => uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value's index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (lastIndex != toDeleteIndex) {\n bytes32 lastvalue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastvalue;\n // Update the index for the moved value\n set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n return _values(set._inner);\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n assembly {\n result := store\n }\n\n return result;\n }\n}\n" + }, + "contracts/automation/AbstractCCIPBridgeHelperModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractSafeModule } from \"./AbstractSafeModule.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IRouterClient } from \"@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol\";\nimport { Client } from \"@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol\";\n\nabstract contract AbstractCCIPBridgeHelperModule is AbstractSafeModule {\n /**\n * @notice Bridges a token from the source chain to the destination chain using CCIP\n * @param ccipRouter The CCIP router contract\n * @param destinationChainSelector The selector for the destination chain\n * @param token The token to bridge\n * @param amount The amount of token to bridge\n */\n function _bridgeTokenWithCCIP(\n IRouterClient ccipRouter,\n uint64 destinationChainSelector,\n IERC20 token,\n uint256 amount\n ) internal {\n bool success;\n\n // Approve CCIP Router to move the token\n success = safeContract.execTransactionFromModule(\n address(token),\n 0, // Value\n abi.encodeWithSelector(token.approve.selector, ccipRouter, amount),\n 0 // Call\n );\n require(success, \"Failed to approve token\");\n\n Client.EVMTokenAmount[]\n memory tokenAmounts = new Client.EVMTokenAmount[](1);\n Client.EVMTokenAmount memory tokenAmount = Client.EVMTokenAmount({\n token: address(token),\n amount: amount\n });\n tokenAmounts[0] = tokenAmount;\n\n Client.EVM2AnyMessage memory ccipMessage = Client.EVM2AnyMessage({\n receiver: abi.encode(address(safeContract)), // ABI-encoded receiver address\n data: abi.encode(\"\"),\n tokenAmounts: tokenAmounts,\n extraArgs: Client._argsToBytes(\n Client.EVMExtraArgsV1({ gasLimit: 0 })\n ),\n feeToken: address(0)\n });\n\n // Get CCIP fee\n uint256 ccipFee = ccipRouter.getFee(\n destinationChainSelector,\n ccipMessage\n );\n\n // Send CCIP message\n success = safeContract.execTransactionFromModule(\n address(ccipRouter),\n ccipFee, // Value\n abi.encodeWithSelector(\n ccipRouter.ccipSend.selector,\n destinationChainSelector,\n ccipMessage\n ),\n 0 // Call\n );\n require(success, \"Failed to send CCIP message\");\n }\n}\n" + }, + "contracts/automation/AbstractLZBridgeHelperModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractSafeModule } from \"./AbstractSafeModule.sol\";\n\nimport { IOFT, SendParam } from \"@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol\";\nimport { MessagingFee } from \"@layerzerolabs/oapp-evm/contracts/oapp/OAppSender.sol\";\nimport { OptionsBuilder } from \"@layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol\";\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nabstract contract AbstractLZBridgeHelperModule is AbstractSafeModule {\n using OptionsBuilder for bytes;\n\n /**\n * @dev Bridges token using LayerZero.\n * @param lzEndpointId LayerZero endpoint id.\n * @param token Token to bridge.\n * @param lzAdapter LZ Adapter to use.\n * @param amount Amount of token to bridge.\n * @param slippageBps Slippage in 10^4 basis points.\n * @param isNativeToken Whether the token is native token.\n */\n function _bridgeTokenWithLz(\n uint32 lzEndpointId,\n IERC20 token,\n IOFT lzAdapter,\n uint256 amount,\n uint256 slippageBps,\n bool isNativeToken\n ) internal {\n bool success;\n\n if (!isNativeToken) {\n // Approve LZ Adapter to move the token\n success = safeContract.execTransactionFromModule(\n address(token),\n 0, // Value\n abi.encodeWithSelector(\n token.approve.selector,\n address(lzAdapter),\n amount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve token\");\n }\n\n // Calculate minimum amount to receive\n uint256 minAmount = (amount * (10000 - slippageBps)) / 10000;\n\n // Hardcoded gaslimit of 400k\n bytes memory options = OptionsBuilder\n .newOptions()\n .addExecutorLzReceiveOption(400000, 0);\n\n // Build send param\n SendParam memory sendParam = SendParam({\n dstEid: lzEndpointId,\n to: bytes32(uint256(uint160(address(safeContract)))),\n amountLD: amount,\n minAmountLD: minAmount,\n extraOptions: options,\n composeMsg: bytes(\"\"),\n oftCmd: bytes(\"\")\n });\n\n // Compute fees\n MessagingFee memory msgFee = lzAdapter.quoteSend(sendParam, false);\n\n uint256 value = isNativeToken\n ? amount + msgFee.nativeFee\n : msgFee.nativeFee;\n\n // Execute transaction\n success = safeContract.execTransactionFromModule(\n address(lzAdapter),\n value,\n abi.encodeWithSelector(\n lzAdapter.send.selector,\n sendParam,\n msgFee,\n address(safeContract)\n ),\n 0\n );\n require(success, \"Failed to bridge token\");\n }\n}\n" + }, + "contracts/automation/AbstractSafeModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AccessControlEnumerable } from \"@openzeppelin/contracts/access/AccessControlEnumerable.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { ISafe } from \"../interfaces/ISafe.sol\";\n\nabstract contract AbstractSafeModule is AccessControlEnumerable {\n ISafe public immutable safeContract;\n\n bytes32 public constant OPERATOR_ROLE = keccak256(\"OPERATOR_ROLE\");\n\n modifier onlySafe() {\n require(\n msg.sender == address(safeContract),\n \"Caller is not the safe contract\"\n );\n _;\n }\n\n modifier onlyOperator() {\n require(\n hasRole(OPERATOR_ROLE, msg.sender),\n \"Caller is not an operator\"\n );\n _;\n }\n\n constructor(address _safeContract) {\n safeContract = ISafe(_safeContract);\n _grantRole(DEFAULT_ADMIN_ROLE, address(safeContract));\n _grantRole(OPERATOR_ROLE, address(safeContract));\n }\n\n /**\n * @dev Helps recovering any tokens accidentally sent to this module.\n * @param token Token to transfer. 0x0 to transfer Native token.\n * @param amount Amount to transfer. 0 to transfer all balance.\n */\n function transferTokens(address token, uint256 amount) external onlySafe {\n if (address(token) == address(0)) {\n // Move ETH\n amount = amount > 0 ? amount : address(this).balance;\n payable(address(safeContract)).transfer(amount);\n return;\n }\n\n // Move all balance if amount set to 0\n amount = amount > 0 ? amount : IERC20(token).balanceOf(address(this));\n\n // Transfer to Safe contract\n // slither-disable-next-line unchecked-transfer unused-return\n IERC20(token).transfer(address(safeContract), amount);\n }\n\n receive() external payable {\n // Accept ETH to pay for bridge fees\n }\n}\n" + }, + "contracts/automation/AutoWithdrawalModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractSafeModule } from \"./AbstractSafeModule.sol\";\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { VaultStorage } from \"../vault/VaultStorage.sol\";\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\n\n/**\n * @title Auto Withdrawal Module\n * @notice A Gnosis Safe module that automates funding the OUSD (or OETH) vault's\n * withdrawal queue by pulling liquidity from a configured strategy.\n *\n * @dev The Safe (Guardian multisig) must:\n * 1. Deploy this module\n * 2. Call `safe.enableModule(address(this))` to authorize it\n *\n * An off-chain operator (e.g. Defender Relayer) calls `fundWithdrawals()`\n * periodically. The module:\n * - First tries to satisfy the queue from idle vault funds\n * - If there's still a shortfall, withdraws the exact shortfall amount\n * from the configured strategy (up to what the strategy holds)\n *\n * The Safe retains full override control via `setStrategy`.\n */\ncontract AutoWithdrawalModule is AbstractSafeModule {\n // ───────────────────────────────────────────────────────── Immutables ──\n\n /// @notice The vault whose withdrawal queue is being funded.\n IVault public immutable vault;\n\n /// @notice The vault's base asset (e.g. USDC for OUSD, WETH for OETH).\n /// Stored as an address to match IStrategy.checkBalance() signature.\n address public immutable asset;\n\n // ────────────────────────────────────────────────────── Mutable config ──\n\n /// @notice The strategy from which liquidity is pulled to fill the queue.\n address public strategy;\n\n // ─────────────────────────────────────────────────────────── Events ──\n\n /// @notice Emitted when liquidity is successfully moved from strategy to vault.\n event LiquidityWithdrawn(\n address indexed strategy,\n uint256 amount,\n uint256 remainingShortfall\n );\n\n /// @notice Emitted when the strategy does not hold enough funds to cover the shortfall.\n /// No withdrawal is attempted; an operator alert should fire on this event.\n event InsufficientStrategyLiquidity(\n address indexed strategy,\n uint256 shortfall,\n uint256 available\n );\n\n /// @notice Emitted when the Safe exec call to withdrawFromStrategy fails.\n event WithdrawalFailed(address indexed strategy, uint256 attemptedAmount);\n\n /// @notice Emitted when the strategy address is updated.\n event StrategyUpdated(address oldStrategy, address newStrategy);\n\n // ─────────────────────────────────────────────────────── Constructor ──\n\n /**\n * @param _safeContract Address of the Gnosis Safe (Guardian multisig).\n * @param _operator Address of the off-chain operator (e.g. Defender relayer).\n * @param _vault Address of the OUSD/OETH vault.\n * @param _strategy Initial strategy to pull liquidity from.\n */\n constructor(\n address _safeContract,\n address _operator,\n address _vault,\n address _strategy\n ) AbstractSafeModule(_safeContract) {\n require(_vault != address(0), \"Invalid vault\");\n require(_strategy != address(0), \"Invalid strategy\");\n\n vault = IVault(_vault);\n asset = IVault(_vault).asset();\n\n _setStrategy(_strategy);\n\n _grantRole(OPERATOR_ROLE, _operator);\n }\n\n // ──────────────────────────────────────────────────── Core automation ──\n\n /**\n * @notice Fund the vault's withdrawal queue from the configured strategy.\n * Called periodically by an off-chain operator (Defender Actions).\n *\n * Steps:\n * 1. Ask the vault to absorb any idle asset it already holds.\n * 2. Compute the remaining shortfall.\n * 3. Pull up to that amount from the strategy via the Safe.\n *\n * This function never reverts on \"soft\" failures (strategy underfunded,\n * Safe exec failure). It emits a descriptive event instead so off-chain\n * monitoring can alert the team without breaking the Defender action.\n */\n function fundWithdrawals() external onlyOperator {\n // Step 1: Let the vault absorb any asset it already holds idle.\n // This is a permissionless call; no Safe exec needed.\n vault.addWithdrawalQueueLiquidity();\n\n // Step 2: Read the current shortfall.\n uint256 shortfall = pendingShortfall();\n\n if (shortfall == 0) {\n // Queue is fully funded — nothing to do.\n return;\n }\n\n // Step 3: Read available balance from the strategy.\n uint256 strategyBalance = IStrategy(strategy).checkBalance(asset);\n\n // Withdraw the lesser of the shortfall and what the strategy holds.\n uint256 toWithdraw = shortfall < strategyBalance\n ? shortfall\n : strategyBalance;\n\n if (toWithdraw == 0) {\n emit InsufficientStrategyLiquidity(\n strategy,\n shortfall,\n strategyBalance\n );\n return;\n }\n\n // Step 4: Execute withdrawal via the Safe (which holds the Strategist role).\n address[] memory assets = new address[](1);\n assets[0] = asset;\n uint256[] memory amounts = new uint256[](1);\n amounts[0] = toWithdraw;\n\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0,\n abi.encodeWithSelector(\n IVault.withdrawFromStrategy.selector,\n strategy,\n assets,\n amounts\n ),\n 0 // Call (not delegatecall)\n );\n\n if (!success) {\n emit WithdrawalFailed(strategy, toWithdraw);\n return;\n }\n\n emit LiquidityWithdrawn(strategy, toWithdraw, shortfall - toWithdraw);\n }\n\n // ─────────────────────────────────────────────────────── Guardian controls ──\n\n /**\n * @notice Change the strategy from which liquidity is pulled.\n * @param _strategy New strategy address. Must not be zero.\n */\n function setStrategy(address _strategy) external onlySafe {\n _setStrategy(_strategy);\n }\n\n function _setStrategy(address _strategy) internal {\n require(_strategy != address(0), \"Invalid strategy\");\n emit StrategyUpdated(strategy, _strategy);\n strategy = _strategy;\n }\n\n // ──────────────────────────────────────────────────────── View helpers ──\n\n /**\n * @notice The current unmet shortfall in the vault's withdrawal queue.\n * @dev This is a raw read of `queued - claimable`. It does NOT account for\n * idle vault asset that `addWithdrawalQueueLiquidity()` would absorb.\n * For a fully up-to-date figure, call `vault.addWithdrawalQueueLiquidity()`\n * first (which is what `fundWithdrawals()` does).\n * @return shortfall Queue shortfall in asset units (vault asset decimals).\n */\n function pendingShortfall() public view returns (uint256 shortfall) {\n VaultStorage.WithdrawalQueueMetadata memory meta = vault\n .withdrawalQueueMetadata();\n shortfall = meta.queued - meta.claimable;\n }\n}\n" + }, + "contracts/automation/BaseBridgeHelperModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// solhint-disable-next-line max-line-length\nimport { AbstractCCIPBridgeHelperModule, AbstractSafeModule, IRouterClient } from \"./AbstractCCIPBridgeHelperModule.sol\";\n\nimport { AccessControlEnumerable } from \"@openzeppelin/contracts/access/AccessControlEnumerable.sol\";\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nimport { BridgedWOETHStrategy } from \"../strategies/BridgedWOETHStrategy.sol\";\n\ncontract BaseBridgeHelperModule is\n AccessControlEnumerable,\n AbstractCCIPBridgeHelperModule\n{\n IVault public constant vault =\n IVault(0x98a0CbeF61bD2D21435f433bE4CD42B56B38CC93);\n IWETH9 public constant weth =\n IWETH9(0x4200000000000000000000000000000000000006);\n IERC20 public constant oethb =\n IERC20(0xDBFeFD2e8460a6Ee4955A68582F85708BAEA60A3);\n IERC4626 public constant bridgedWOETH =\n IERC4626(0xD8724322f44E5c58D7A815F542036fb17DbbF839);\n\n BridgedWOETHStrategy public constant bridgedWOETHStrategy =\n BridgedWOETHStrategy(0x80c864704DD06C3693ed5179190786EE38ACf835);\n\n IRouterClient public constant CCIP_ROUTER =\n IRouterClient(0x881e3A65B4d4a04dD529061dd0071cf975F58bCD);\n\n uint64 public constant CCIP_ETHEREUM_CHAIN_SELECTOR = 5009297550715157269;\n\n constructor(address _safeContract) AbstractSafeModule(_safeContract) {}\n\n /**\n * @dev Bridges wOETH to Ethereum.\n * @param woethAmount Amount of wOETH to bridge.\n */\n function bridgeWOETHToEthereum(uint256 woethAmount)\n public\n payable\n onlyOperator\n {\n _bridgeTokenWithCCIP(\n CCIP_ROUTER,\n CCIP_ETHEREUM_CHAIN_SELECTOR,\n IERC20(address(bridgedWOETH)),\n woethAmount\n );\n }\n\n /**\n * @dev Bridges WETH to Ethereum.\n * @param wethAmount Amount of WETH to bridge.\n */\n function bridgeWETHToEthereum(uint256 wethAmount)\n public\n payable\n onlyOperator\n {\n _bridgeTokenWithCCIP(\n CCIP_ROUTER,\n CCIP_ETHEREUM_CHAIN_SELECTOR,\n IERC20(address(weth)),\n wethAmount\n );\n }\n\n /**\n * @dev Deposits wOETH into the bridgedWOETH strategy.\n * @param woethAmount Amount of wOETH to deposit.\n * @param requestWithdrawal Whether to request an async withdrawal of the\n * resulting OETHb from the Vault.\n * @return requestId The withdrawal request ID (0 if not requested).\n * @return oethbAmount Amount of OETHb received or queued for withdrawal.\n */\n function depositWOETH(uint256 woethAmount, bool requestWithdrawal)\n external\n onlyOperator\n returns (uint256 requestId, uint256 oethbAmount)\n {\n oethbAmount = _depositWOETH(woethAmount);\n if (requestWithdrawal) {\n requestId = _requestWithdrawal(oethbAmount);\n }\n }\n\n /**\n * @dev Claims a previously requested withdrawal and bridges WETH to Ethereum.\n * @param requestId The withdrawal request ID to claim.\n */\n function claimAndBridgeWETH(uint256 requestId)\n external\n payable\n onlyOperator\n {\n uint256 wethAmount = _claimWithdrawal(requestId);\n bridgeWETHToEthereum(wethAmount);\n }\n\n /**\n * @dev Claims a previously requested withdrawal.\n * @param requestId The withdrawal request ID to claim.\n * @return wethAmount Amount of WETH received.\n */\n function claimWithdrawal(uint256 requestId)\n external\n onlyOperator\n returns (uint256 wethAmount)\n {\n return _claimWithdrawal(requestId);\n }\n\n /**\n * @dev Deposits wOETH into the bridgedWOETH strategy.\n * @param woethAmount Amount of wOETH to deposit.\n * @return oethbAmount Amount of OETHb received.\n */\n function _depositWOETH(uint256 woethAmount)\n internal\n returns (uint256 oethbAmount)\n {\n // Update oracle price\n bridgedWOETHStrategy.updateWOETHOraclePrice();\n\n // Rebase to account for any yields from price update\n vault.rebase();\n\n oethbAmount = oethb.balanceOf(address(safeContract));\n\n // Approve bridgedWOETH strategy to move wOETH\n bool success = safeContract.execTransactionFromModule(\n address(bridgedWOETH),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETH.approve.selector,\n address(bridgedWOETHStrategy),\n woethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve wOETH\");\n\n // Deposit to bridgedWOETH strategy\n success = safeContract.execTransactionFromModule(\n address(bridgedWOETHStrategy),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETHStrategy.depositBridgedWOETH.selector,\n woethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to deposit bridged WOETH\");\n\n oethbAmount = oethb.balanceOf(address(safeContract)) - oethbAmount;\n\n // Rebase to account for any yields from price update\n // and backing asset change from deposit\n vault.rebase();\n }\n\n /**\n * @dev Requests an async withdrawal from the Vault.\n * @param oethbAmount Amount of OETHb to withdraw.\n * @return requestId The withdrawal request ID.\n */\n function _requestWithdrawal(uint256 oethbAmount)\n internal\n returns (uint256 requestId)\n {\n // Read the next withdrawal index before requesting\n // (safe because requestWithdrawal is nonReentrant)\n requestId = vault.withdrawalQueueMetadata().nextWithdrawalIndex;\n\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(\n vault.requestWithdrawal.selector,\n oethbAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to request withdrawal\");\n }\n\n /**\n * @dev Claims a previously requested withdrawal from the Vault.\n * @param requestId The withdrawal request ID to claim.\n * @return wethAmount Amount of WETH received.\n */\n function _claimWithdrawal(uint256 requestId)\n internal\n returns (uint256 wethAmount)\n {\n wethAmount = weth.balanceOf(address(safeContract));\n\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(vault.claimWithdrawal.selector, requestId),\n 0 // Call\n );\n require(success, \"Failed to claim withdrawal\");\n\n wethAmount = weth.balanceOf(address(safeContract)) - wethAmount;\n }\n\n /**\n * @dev Deposits WETH into the Vault and redeems wOETH from the bridgedWOETH strategy.\n * @param wethAmount Amount of WETH to deposit.\n * @return Amount of wOETH received.\n */\n function depositWETHAndRedeemWOETH(uint256 wethAmount)\n external\n onlyOperator\n returns (uint256)\n {\n return _withdrawWOETH(wethAmount);\n }\n\n function depositWETHAndBridgeWOETH(uint256 wethAmount)\n external\n onlyOperator\n returns (uint256)\n {\n uint256 woethAmount = _withdrawWOETH(wethAmount);\n bridgeWOETHToEthereum(woethAmount);\n return woethAmount;\n }\n\n /**\n * @dev Withdraws wOETH from the bridgedWOETH strategy.\n * @param wethAmount Amount of WETH to use to withdraw.\n * @return Amount of wOETH received.\n */\n function _withdrawWOETH(uint256 wethAmount) internal returns (uint256) {\n // Approve Vault to move WETH\n bool success = safeContract.execTransactionFromModule(\n address(weth),\n 0, // Value\n abi.encodeWithSelector(\n weth.approve.selector,\n address(vault),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve WETH\");\n\n // Mint OETHb with WETH\n success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(vault.mint.selector, wethAmount),\n 0 // Call\n );\n require(success, \"Failed to mint OETHb\");\n\n // Approve bridgedWOETH strategy to move OETHb\n success = safeContract.execTransactionFromModule(\n address(oethb),\n 0, // Value\n abi.encodeWithSelector(\n oethb.approve.selector,\n address(bridgedWOETHStrategy),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve OETHb\");\n\n uint256 woethAmount = bridgedWOETH.balanceOf(address(safeContract));\n\n // Withdraw from bridgedWOETH strategy\n success = safeContract.execTransactionFromModule(\n address(bridgedWOETHStrategy),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETHStrategy.withdrawBridgedWOETH.selector,\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to withdraw bridged WOETH\");\n\n woethAmount =\n bridgedWOETH.balanceOf(address(safeContract)) -\n woethAmount;\n\n return woethAmount;\n }\n}\n" + }, + "contracts/automation/EthereumBridgeHelperModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// solhint-disable-next-line max-line-length\nimport { AbstractCCIPBridgeHelperModule, AbstractSafeModule, IRouterClient } from \"./AbstractCCIPBridgeHelperModule.sol\";\n\nimport { AccessControlEnumerable } from \"@openzeppelin/contracts/access/AccessControlEnumerable.sol\";\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract EthereumBridgeHelperModule is\n AccessControlEnumerable,\n AbstractCCIPBridgeHelperModule\n{\n IVault public constant vault =\n IVault(0x39254033945AA2E4809Cc2977E7087BEE48bd7Ab);\n IWETH9 public constant weth =\n IWETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);\n IERC20 public constant oeth =\n IERC20(0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3);\n IERC4626 public constant woeth =\n IERC4626(0xDcEe70654261AF21C44c093C300eD3Bb97b78192);\n\n IRouterClient public constant CCIP_ROUTER =\n IRouterClient(0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D);\n\n uint64 public constant CCIP_BASE_CHAIN_SELECTOR = 15971525489660198786;\n\n constructor(address _safeContract) AbstractSafeModule(_safeContract) {}\n\n /**\n * @dev Bridges wOETH to Base using CCIP.\n * @param woethAmount Amount of wOETH to bridge.\n */\n function bridgeWOETHToBase(uint256 woethAmount)\n public\n payable\n onlyOperator\n {\n _bridgeTokenWithCCIP(\n CCIP_ROUTER,\n CCIP_BASE_CHAIN_SELECTOR,\n woeth,\n woethAmount\n );\n }\n\n /**\n * @dev Bridges wETH to Base using CCIP.\n * @param wethAmount Amount of wETH to bridge.\n */\n function bridgeWETHToBase(uint256 wethAmount) public payable onlyOperator {\n _bridgeTokenWithCCIP(\n CCIP_ROUTER,\n CCIP_BASE_CHAIN_SELECTOR,\n IERC20(address(weth)),\n wethAmount\n );\n }\n\n /**\n * @dev Mints OETH and wraps it into wOETH.\n * @param wethAmount Amount of WETH to mint.\n * @param useNativeToken Whether to use native token to mint.\n * @return Amount of wOETH minted.\n */\n function mintAndWrap(uint256 wethAmount, bool useNativeToken)\n external\n onlyOperator\n returns (uint256)\n {\n if (useNativeToken) {\n wrapETH(wethAmount);\n }\n\n return _mintAndWrap(wethAmount);\n }\n\n function wrapETH(uint256 ethAmount) public payable onlyOperator {\n // Deposit ETH into WETH\n safeContract.execTransactionFromModule(\n address(weth),\n ethAmount, // Value\n abi.encodeWithSelector(weth.deposit.selector),\n 0 // Call\n );\n }\n\n /**\n * @dev Mints OETH and wraps it into wOETH.\n * @param wethAmount Amount of WETH to mint.\n * @return Amount of wOETH minted.\n */\n function _mintAndWrap(uint256 wethAmount) internal returns (uint256) {\n // Approve Vault to move WETH\n bool success = safeContract.execTransactionFromModule(\n address(weth),\n 0, // Value\n abi.encodeWithSelector(\n weth.approve.selector,\n address(vault),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve WETH\");\n\n // Mint OETH\n success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(vault.mint.selector, wethAmount),\n 0 // Call\n );\n require(success, \"Failed to mint OETH\");\n\n // Approve wOETH to move OETH\n success = safeContract.execTransactionFromModule(\n address(oeth),\n 0, // Value\n abi.encodeWithSelector(\n oeth.approve.selector,\n address(woeth),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve OETH\");\n\n uint256 woethAmount = woeth.balanceOf(address(safeContract));\n\n // Wrap OETH into wOETH\n success = safeContract.execTransactionFromModule(\n address(woeth),\n 0, // Value\n abi.encodeWithSelector(\n woeth.deposit.selector,\n wethAmount,\n address(safeContract)\n ),\n 0 // Call\n );\n require(success, \"Failed to wrap OETH\");\n\n // Compute amount of wOETH minted\n return woeth.balanceOf(address(safeContract)) - woethAmount;\n }\n\n /**\n * @dev Mints OETH and wraps it into wOETH, then bridges it to Base using CCIP.\n * @param wethAmount Amount of WETH to mint.\n * @param useNativeToken Whether to use native token to mint.\n */\n function mintWrapAndBridgeToBase(uint256 wethAmount, bool useNativeToken)\n external\n payable\n onlyOperator\n {\n if (useNativeToken) {\n wrapETH(wethAmount);\n }\n\n uint256 woethAmount = _mintAndWrap(wethAmount);\n bridgeWOETHToBase(woethAmount);\n }\n\n /**\n * @dev Unwraps wOETH and requests an async withdrawal from the Vault.\n * @param woethAmount Amount of wOETH to unwrap.\n * @return requestId The withdrawal request ID.\n * @return oethAmount Amount of OETH queued for withdrawal.\n */\n function unwrapAndRequestWithdrawal(uint256 woethAmount)\n external\n onlyOperator\n returns (uint256 requestId, uint256 oethAmount)\n {\n return _unwrapAndRequestWithdrawal(woethAmount);\n }\n\n /**\n * @dev Claims a previously requested withdrawal and bridges WETH to Base.\n * @param requestId The withdrawal request ID to claim.\n */\n function claimAndBridgeToBase(uint256 requestId)\n external\n payable\n onlyOperator\n {\n uint256 wethAmount = _claimWithdrawal(requestId);\n bridgeWETHToBase(wethAmount);\n }\n\n /**\n * @dev Claims a previously requested withdrawal.\n * @param requestId The withdrawal request ID to claim.\n * @return wethAmount Amount of WETH received.\n */\n function claimWithdrawal(uint256 requestId)\n external\n onlyOperator\n returns (uint256 wethAmount)\n {\n return _claimWithdrawal(requestId);\n }\n\n /**\n * @dev Unwraps wOETH and requests an async withdrawal from the Vault.\n * @param woethAmount Amount of wOETH to unwrap.\n * @return requestId The withdrawal request ID.\n * @return oethAmount Amount of OETH queued for withdrawal.\n */\n function _unwrapAndRequestWithdrawal(uint256 woethAmount)\n internal\n returns (uint256 requestId, uint256 oethAmount)\n {\n // Read the next withdrawal index before requesting\n // (safe because requestWithdrawal is nonReentrant)\n requestId = vault.withdrawalQueueMetadata().nextWithdrawalIndex;\n\n oethAmount = oeth.balanceOf(address(safeContract));\n\n // Unwrap wOETH\n bool success = safeContract.execTransactionFromModule(\n address(woeth),\n 0, // Value\n abi.encodeWithSelector(\n woeth.redeem.selector,\n woethAmount,\n address(safeContract),\n address(safeContract)\n ),\n 0 // Call\n );\n require(success, \"Failed to unwrap wOETH\");\n\n oethAmount = oeth.balanceOf(address(safeContract)) - oethAmount;\n\n // Request async withdrawal from Vault\n success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(\n vault.requestWithdrawal.selector,\n oethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to request withdrawal\");\n }\n\n /**\n * @dev Claims a previously requested withdrawal from the Vault.\n * @param requestId The withdrawal request ID to claim.\n * @return wethAmount Amount of WETH received.\n */\n function _claimWithdrawal(uint256 requestId)\n internal\n returns (uint256 wethAmount)\n {\n wethAmount = weth.balanceOf(address(safeContract));\n\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(vault.claimWithdrawal.selector, requestId),\n 0 // Call\n );\n require(success, \"Failed to claim withdrawal\");\n\n wethAmount = weth.balanceOf(address(safeContract)) - wethAmount;\n }\n}\n" + }, + "contracts/automation/PlumeBridgeHelperModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractSafeModule } from \"./AbstractSafeModule.sol\";\nimport { AbstractLZBridgeHelperModule } from \"./AbstractLZBridgeHelperModule.sol\";\n\nimport { AccessControlEnumerable } from \"@openzeppelin/contracts/access/AccessControlEnumerable.sol\";\n\nimport { IOFT } from \"@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol\";\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nimport { BridgedWOETHStrategy } from \"../strategies/BridgedWOETHStrategy.sol\";\n\ncontract PlumeBridgeHelperModule is\n AccessControlEnumerable,\n AbstractLZBridgeHelperModule\n{\n IVault public constant vault =\n IVault(0xc8c8F8bEA5631A8AF26440AF32a55002138cB76a);\n IWETH9 public constant weth =\n IWETH9(0xca59cA09E5602fAe8B629DeE83FfA819741f14be);\n IERC20 public constant oethp =\n IERC20(0xFCbe50DbE43bF7E5C88C6F6Fb9ef432D4165406E);\n IERC4626 public constant bridgedWOETH =\n IERC4626(0xD8724322f44E5c58D7A815F542036fb17DbbF839);\n\n uint32 public constant LZ_ETHEREUM_ENDPOINT_ID = 30101;\n IOFT public constant LZ_WOETH_OMNICHAIN_ADAPTER =\n IOFT(0x592CB6A596E7919930bF49a27AdAeCA7C055e4DB);\n IOFT public constant LZ_ETH_OMNICHAIN_ADAPTER =\n IOFT(0x4683CE822272CD66CEa73F5F1f9f5cBcaEF4F066);\n\n BridgedWOETHStrategy public constant bridgedWOETHStrategy =\n BridgedWOETHStrategy(0x1E3EdD5e019207D6355Ea77F724b1F1BF639B569);\n\n constructor(address _safeContract) AbstractSafeModule(_safeContract) {}\n\n /**\n * @dev Bridges wOETH to Ethereum.\n * @param woethAmount Amount of wOETH to bridge.\n * @param slippageBps Slippage in 10^4 basis points.\n */\n function bridgeWOETHToEthereum(uint256 woethAmount, uint256 slippageBps)\n public\n payable\n onlyOperator\n {\n _bridgeTokenWithLz(\n LZ_ETHEREUM_ENDPOINT_ID,\n IERC20(address(bridgedWOETH)),\n LZ_WOETH_OMNICHAIN_ADAPTER,\n woethAmount,\n slippageBps,\n false\n );\n }\n\n /**\n * @dev Bridges wETH to Ethereum.\n * @param wethAmount Amount of wETH to bridge.\n * @param slippageBps Slippage in 10^4 basis points.\n */\n function bridgeWETHToEthereum(uint256 wethAmount, uint256 slippageBps)\n public\n payable\n onlyOperator\n {\n _bridgeTokenWithLz(\n LZ_ETHEREUM_ENDPOINT_ID,\n IERC20(address(weth)),\n LZ_ETH_OMNICHAIN_ADAPTER,\n wethAmount,\n slippageBps,\n false\n );\n }\n\n /**\n * @dev Deposits wOETH into the bridgedWOETH strategy.\n * @param woethAmount Amount of wOETH to deposit.\n * @param redeemWithVault Whether to redeem with Vault.\n * @return Amount of OETHp received.\n */\n function depositWOETH(uint256 woethAmount, bool redeemWithVault)\n external\n onlyOperator\n returns (uint256)\n {\n return _depositWOETH(woethAmount, redeemWithVault);\n }\n\n /**\n * @dev Deposits wOETH into the bridgedWOETH strategy and bridges it to Ethereum.\n * @param woethAmount Amount of wOETH to deposit.\n * @param slippageBps Slippage in 10^4 basis points.\n * @return Amount of WETH received.\n */\n function depositWOETHAndBridgeWETH(uint256 woethAmount, uint256 slippageBps)\n external\n payable\n onlyOperator\n returns (uint256)\n {\n uint256 wethAmount = _depositWOETH(woethAmount, true);\n bridgeWETHToEthereum(wethAmount, slippageBps);\n return wethAmount;\n }\n\n /**\n * @dev Deposits wOETH into the bridgedWOETH strategy.\n * @param woethAmount Amount of wOETH to deposit.\n * @param redeemWithVault Whether to redeem with Vault.\n * @return Amount of OETHp received.\n */\n function _depositWOETH(uint256 woethAmount, bool redeemWithVault)\n internal\n returns (uint256)\n {\n // Update oracle price\n bridgedWOETHStrategy.updateWOETHOraclePrice();\n\n // Rebase to account for any yields from price update\n vault.rebase();\n\n uint256 oethpAmount = oethp.balanceOf(address(safeContract));\n\n // Approve bridgedWOETH strategy to move wOETH\n bool success = safeContract.execTransactionFromModule(\n address(bridgedWOETH),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETH.approve.selector,\n address(bridgedWOETHStrategy),\n woethAmount\n ),\n 0 // Call\n );\n\n // Deposit to bridgedWOETH strategy\n success = safeContract.execTransactionFromModule(\n address(bridgedWOETHStrategy),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETHStrategy.depositBridgedWOETH.selector,\n woethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to deposit bridged WOETH\");\n\n oethpAmount = oethp.balanceOf(address(safeContract)) - oethpAmount;\n\n // Rebase to account for any yields from price update\n // and backing asset change from deposit\n vault.rebase();\n\n if (!redeemWithVault) {\n return oethpAmount;\n }\n\n // Redeem for WETH using Vault\n // redeem(uint256,uint256) was removed from VaultCore; use hardcoded selector\n success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(\n bytes4(keccak256(\"redeem(uint256,uint256)\")),\n oethpAmount,\n oethpAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to redeem OETHp\");\n\n return oethpAmount;\n }\n\n /**\n * @dev Deposits wETH into the vault.\n * @param wethAmount Amount of wETH to deposit.\n * @return Amount of OETHp received.\n */\n function depositWETHAndRedeemWOETH(uint256 wethAmount)\n external\n onlyOperator\n returns (uint256)\n {\n return _withdrawWOETH(wethAmount);\n }\n\n /**\n * @dev Deposits wETH into the vault and bridges it to Ethereum.\n * @param wethAmount Amount of wETH to deposit.\n * @param slippageBps Slippage in 10^4 basis points.\n * @return Amount of WOETH received.\n */\n function depositWETHAndBridgeWOETH(uint256 wethAmount, uint256 slippageBps)\n external\n payable\n onlyOperator\n returns (uint256)\n {\n uint256 woethAmount = _withdrawWOETH(wethAmount);\n bridgeWOETHToEthereum(woethAmount, slippageBps);\n return woethAmount;\n }\n\n /**\n * @dev Withdraws wOETH from the bridgedWOETH strategy.\n * @param wethAmount Amount of WETH to use to withdraw.\n * @return Amount of wOETH received.\n */\n function _withdrawWOETH(uint256 wethAmount) internal returns (uint256) {\n // Approve Vault to move WETH\n bool success = safeContract.execTransactionFromModule(\n address(weth),\n 0, // Value\n abi.encodeWithSelector(\n weth.approve.selector,\n address(vault),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve WETH\");\n\n // Mint OETHp with WETH\n // mint(address,uint256,uint256) was removed from IVault; use hardcoded selector\n success = safeContract.execTransactionFromModule(\n address(vault),\n 0, // Value\n abi.encodeWithSelector(\n bytes4(keccak256(\"mint(address,uint256,uint256)\")),\n address(weth),\n wethAmount,\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to mint OETHp\");\n\n // Approve bridgedWOETH strategy to move OETHp\n success = safeContract.execTransactionFromModule(\n address(oethp),\n 0, // Value\n abi.encodeWithSelector(\n oethp.approve.selector,\n address(bridgedWOETHStrategy),\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to approve OETHp\");\n\n uint256 woethAmount = bridgedWOETH.balanceOf(address(safeContract));\n\n // Withdraw from bridgedWOETH strategy\n success = safeContract.execTransactionFromModule(\n address(bridgedWOETHStrategy),\n 0, // Value\n abi.encodeWithSelector(\n bridgedWOETHStrategy.withdrawBridgedWOETH.selector,\n wethAmount\n ),\n 0 // Call\n );\n require(success, \"Failed to withdraw bridged WOETH\");\n\n woethAmount =\n bridgedWOETH.balanceOf(address(safeContract)) -\n woethAmount;\n\n return woethAmount;\n }\n}\n" + }, + "contracts/automation/RebalancerModule.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractSafeModule } from \"./AbstractSafeModule.sol\";\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { VaultStorage } from \"../vault/VaultStorage.sol\";\n\n/**\n * @title Rebalancer Module\n * @notice A Gnosis Safe module that automates OUSD vault rebalancing by\n * withdrawing from overallocated strategies and depositing to\n * underallocated strategies.\n *\n * @dev The Safe (Guardian multisig) must:\n * 1. Deploy this module\n * 2. Call `safe.enableModule(address(this))` to authorize it\n *\n * An off-chain operator (e.g. Defender Action) calls\n * `processWithdrawalsAndDeposits` periodically with computed strategy/amount\n * arrays. Either array may be empty. All intelligence (APY fetching, target\n * allocation, constraint enforcement) lives off-chain. This contract is a\n * dumb executor.\n *\n * The function uses soft failures: if a single strategy call fails via the\n * Safe, the module emits an event and continues to the next strategy rather\n * than reverting the entire batch.\n *\n * The Safe retains full control via `setPaused`.\n */\ncontract RebalancerModule is AbstractSafeModule {\n // ───────────────────────────────────────────────────────── Immutables ──\n\n /// @notice The vault whose strategies are being rebalanced.\n IVault public immutable vault;\n\n /// @notice The vault's base asset (e.g. USDC for OUSD).\n address public immutable asset;\n\n // ────────────────────────────────────────────────────── Mutable config ──\n\n /// @notice When true, processWithdrawalsAndDeposits is blocked.\n bool public paused;\n\n /// @notice Strategies that this module is permitted to withdraw from or deposit into.\n mapping(address => bool) public isAllowedStrategy;\n\n /// @notice Cumulative amount moved (withdrawals + deposits) per calendar day.\n /// Day key = block.timestamp / 1 days (i.e. days since Unix epoch).\n mapping(uint256 => uint256) public amountMovedPerDay;\n\n /// @notice Max percentage of vault TVL that can be moved in a single day.\n /// In basis points (e.g. 20000 = 200%).\n uint256 public maxDailyMovementBps;\n\n // ─────────────────────────────────────────────────────────── Events ──\n\n /// @notice Emitted after processWithdrawals completes (even if some failed).\n event WithdrawalsProcessed(\n address[] strategies,\n uint256[] amounts,\n uint256 remainingShortfall\n );\n\n /// @notice Emitted after processDeposits completes (even if some failed).\n event DepositsProcessed(address[] strategies, uint256[] amounts);\n\n /// @notice Emitted when a single withdrawFromStrategy call fails via the Safe.\n event WithdrawalFailed(address indexed strategy, uint256 attemptedAmount);\n\n /// @notice Emitted when a single depositToStrategy call fails via the Safe.\n event DepositFailed(address indexed strategy, uint256 attemptedAmount);\n\n /// @notice Emitted when the paused state changes.\n event PausedStateChanged(bool paused);\n\n /// @notice Emitted when a strategy is added to the whitelist.\n event StrategyAllowed(address indexed strategy);\n\n /// @notice Emitted when a strategy is removed from the whitelist.\n event StrategyRevoked(address indexed strategy);\n\n /// @notice Emitted when the daily movement limit is updated.\n event MaxDailyMovementBpsSet(uint256 maxDailyMovementBps);\n\n // ─────────────────────────────────────────────────────── Constructor ──\n\n /**\n * @param _safeContract Address of the Gnosis Safe (Guardian multisig).\n * @param _operator Address of the off-chain operator (e.g. Defender relayer).\n * @param _vault Address of the OUSD vault.\n */\n constructor(\n address _safeContract,\n address _operator,\n address _vault\n ) AbstractSafeModule(_safeContract) {\n require(_vault != address(0), \"Invalid vault\");\n\n vault = IVault(_vault);\n asset = IVault(_vault).asset();\n maxDailyMovementBps = 20000; // 200%\n\n _grantRole(OPERATOR_ROLE, _operator);\n }\n\n // ──────────────────────────────────────────────────────── Modifiers ──\n\n modifier whenNotPaused() {\n require(!paused, \"Module is paused\");\n _;\n }\n\n // ──────────────────────────────────────────────── Core automation ──\n\n // slither-disable-start reentrancy-no-eth\n /**\n * @notice Withdraw from overallocated strategies then deposit to underallocated\n * ones. Either array may be empty — the contract loops over zero entries\n * without reverting.\n *\n * @param _withdrawStrategies Strategies to withdraw from.\n * @param _withdrawAmounts Amounts to withdraw from each strategy.\n * @param _depositStrategies Strategies to deposit into.\n * @param _depositAmounts Amounts to deposit into each strategy.\n */\n function processWithdrawalsAndDeposits(\n address[] calldata _withdrawStrategies,\n uint256[] calldata _withdrawAmounts,\n address[] calldata _depositStrategies,\n uint256[] calldata _depositAmounts\n ) external onlyOperator whenNotPaused {\n require(\n _withdrawStrategies.length == _withdrawAmounts.length,\n \"Withdraw array length mismatch\"\n );\n require(\n _depositStrategies.length == _depositAmounts.length,\n \"Deposit array length mismatch\"\n );\n // This is a permissionless call; no Safe exec needed.\n vault.addWithdrawalQueueLiquidity();\n uint256 _limit = dailyLimit();\n _executeWithdrawals(_withdrawStrategies, _withdrawAmounts, _limit);\n _executeDeposits(_depositStrategies, _depositAmounts, _limit);\n emit WithdrawalsProcessed(\n _withdrawStrategies,\n _withdrawAmounts,\n pendingShortfall()\n );\n emit DepositsProcessed(_depositStrategies, _depositAmounts);\n }\n\n // ─────────────────────────────────────── Guardian controls ──\n\n /**\n * @notice Pause or unpause the module.\n * @param _paused True to pause, false to unpause.\n */\n function setPaused(bool _paused) external onlySafe {\n paused = _paused;\n emit PausedStateChanged(_paused);\n }\n\n /**\n * @notice Add a strategy to the whitelist, allowing the operator to move\n * funds into or out of it.\n * @param _strategy Strategy address to allow.\n */\n function allowStrategy(address _strategy) external onlySafe {\n require(_strategy != address(0), \"Invalid strategy\");\n isAllowedStrategy[_strategy] = true;\n emit StrategyAllowed(_strategy);\n }\n\n /**\n * @notice Remove a strategy from the whitelist.\n * @param _strategy Strategy address to revoke.\n */\n function revokeStrategy(address _strategy) external onlySafe {\n isAllowedStrategy[_strategy] = false;\n emit StrategyRevoked(_strategy);\n }\n\n /**\n * @notice Set the maximum percentage of vault TVL that can be moved per day.\n * @param _maxDailyMovementBps Limit in basis points (e.g. 20000 = 200%).\n * Set to 0 for unlimited daily movement.\n */\n function setMaxDailyMovementBps(uint256 _maxDailyMovementBps)\n external\n onlySafe\n {\n maxDailyMovementBps = _maxDailyMovementBps;\n emit MaxDailyMovementBpsSet(_maxDailyMovementBps);\n }\n\n // ──────────────────────────────────────────────────────── View helpers ──\n\n /**\n * @notice The current unmet shortfall in the vault's withdrawal queue.\n * @dev This is a raw read of `queued - claimable`. It does NOT account for\n * idle vault asset that `addWithdrawalQueueLiquidity()` would absorb.\n * For a fully up-to-date figure, call `vault.addWithdrawalQueueLiquidity()`\n * first (which is what `processWithdrawals` does).\n * @return shortfall Queue shortfall in asset units (vault asset decimals).\n */\n function pendingShortfall() public view returns (uint256 shortfall) {\n VaultStorage.WithdrawalQueueMetadata memory meta = vault\n .withdrawalQueueMetadata();\n shortfall = meta.queued - meta.claimable;\n }\n\n /**\n * @notice The daily movement limit based on current vault TVL.\n * @dev vault.totalValue() includes AMO (Automated Market Operations)\n * value. Excluding AMO would add significant complexity for minimal\n * accuracy gain, so the limit is slightly more generous than intended.\n * Additionally, if the vault's TVL changes significantly mid-day (e.g.\n * large mint/redeem), the limit will reflect the TVL at call time —\n * this is acceptable since the limit is a safety backstop, not a\n * precise cap.\n * If maxDailyMovementBps is set to 0, this returns type(uint256).max\n * as a sentinel value to represent an unlimited cap.\n * @return limit Amount in asset units (vault asset decimals).\n */\n function dailyLimit() public view returns (uint256 limit) {\n if (maxDailyMovementBps == 0) {\n return type(uint256).max;\n }\n limit = (vault.totalValue() * maxDailyMovementBps) / 10000;\n }\n\n /**\n * @notice The remaining amount that can be moved today before hitting the\n * daily movement limit.\n * @return remaining Amount in asset units (vault asset decimals).\n */\n function remainingDailyLimit() public view returns (uint256 remaining) {\n uint256 limit = dailyLimit();\n uint256 used = amountMovedPerDay[block.timestamp / 1 days];\n remaining = used >= limit ? 0 : limit - used;\n }\n\n // ──────────────────────────────────────────────── Internal helpers ──\n\n /// @dev Track cumulative daily movement and revert if the limit is exceeded.\n function _trackMovement(uint256 _amount, uint256 _dailyLimit) internal {\n uint256 dayKey = block.timestamp / 1 days;\n amountMovedPerDay[dayKey] += _amount;\n\n require(\n amountMovedPerDay[dayKey] <= _dailyLimit,\n \"Daily movement limit exceeded\"\n );\n }\n\n /// @dev Execute withdrawFromStrategy for each (strategy, amount) pair via the Safe.\n function _executeWithdrawals(\n address[] calldata _strategies,\n uint256[] calldata _amounts,\n uint256 _dailyLimit\n ) internal {\n address[] memory assets = _toAddressArray(asset);\n for (uint256 i = 0; i < _strategies.length; i++) {\n if (_amounts[i] == 0) continue;\n require(isAllowedStrategy[_strategies[i]], \"Strategy not allowed\");\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0,\n abi.encodeWithSelector(\n IVault.withdrawFromStrategy.selector,\n _strategies[i],\n assets,\n _toUint256Array(_amounts[i])\n ),\n 0\n );\n if (success) {\n _trackMovement(_amounts[i], _dailyLimit);\n } else {\n emit WithdrawalFailed(_strategies[i], _amounts[i]);\n }\n }\n }\n\n /// @dev Execute depositToStrategy for each (strategy, amount) pair via the Safe.\n function _executeDeposits(\n address[] calldata _strategies,\n uint256[] calldata _amounts,\n uint256 _dailyLimit\n ) internal {\n address[] memory assets = _toAddressArray(asset);\n for (uint256 i = 0; i < _strategies.length; i++) {\n if (_amounts[i] == 0) continue;\n require(isAllowedStrategy[_strategies[i]], \"Strategy not allowed\");\n bool success = safeContract.execTransactionFromModule(\n address(vault),\n 0,\n abi.encodeWithSelector(\n IVault.depositToStrategy.selector,\n _strategies[i],\n assets,\n _toUint256Array(_amounts[i])\n ),\n 0\n );\n if (success) {\n _trackMovement(_amounts[i], _dailyLimit);\n } else {\n emit DepositFailed(_strategies[i], _amounts[i]);\n }\n }\n }\n\n // slither-disable-end reentrancy-no-eth\n\n function _toAddressArray(address _addr)\n internal\n pure\n returns (address[] memory arr)\n {\n arr = new address[](1);\n arr[0] = _addr;\n }\n\n function _toUint256Array(uint256 _val)\n internal\n pure\n returns (uint256[] memory arr)\n {\n arr = new uint256[](1);\n arr[0] = _val;\n }\n}\n" + }, + "contracts/beacon/BeaconConsolidation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library to request validator consolidation on the beacon chain.\n * @author Origin Protocol Inc\n */\nlibrary BeaconConsolidation {\n /// @notice The address the validator consolidation requests are sent\n /// See https://eips.ethereum.org/EIPS/eip-7251\n address internal constant CONSOLIDATION_REQUEST_ADDRESS =\n 0x0000BBdDc7CE488642fb579F8B00f3a590007251;\n\n function request(bytes calldata source, bytes calldata target)\n internal\n returns (uint256 fee_)\n {\n require(source.length == 48, \"Invalid source byte length\");\n require(target.length == 48, \"Invalid target byte length\");\n\n fee_ = fee();\n\n // Call the Consolidation Request contract with the public keys of the source and target\n // validators packed together.\n // This does not have a function signature, so we use a call\n (bool success, ) = CONSOLIDATION_REQUEST_ADDRESS.call{ value: fee_ }(\n abi.encodePacked(source, target)\n );\n\n require(success, \"Consolidation request failed\");\n }\n\n function fee() internal view returns (uint256) {\n // Get fee from the consolidation request contract\n (bool success, bytes memory result) = CONSOLIDATION_REQUEST_ADDRESS\n .staticcall(\"\");\n\n require(success && result.length > 0, \"Failed to get fee\");\n return abi.decode(result, (uint256));\n }\n}\n" + }, + "contracts/beacon/BeaconRoots.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library to retrieve beacon block roots.\n * @author Origin Protocol Inc\n */\nlibrary BeaconRoots {\n /// @notice The address of beacon block roots oracle\n /// See https://eips.ethereum.org/EIPS/eip-4788\n address internal constant BEACON_ROOTS_ADDRESS =\n 0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02;\n\n /// @notice Returns the beacon block root for the previous block.\n /// This comes from the Beacon Roots contract defined in EIP-4788.\n /// This will revert if the block is more than 8,191 blocks old as\n /// that is the size of the beacon root's ring buffer.\n /// @param timestamp The timestamp of the block for which to get the parent root.\n /// @return parentRoot The parent block root for the given timestamp.\n function parentBlockRoot(uint64 timestamp)\n internal\n view\n returns (bytes32 parentRoot)\n {\n // Call the Beacon Roots contract to get the parent block root.\n // This does not have a function signature, so we use a staticcall.\n (bool success, bytes memory result) = BEACON_ROOTS_ADDRESS.staticcall(\n abi.encode(timestamp)\n );\n\n require(success && result.length > 0, \"Invalid beacon timestamp\");\n parentRoot = abi.decode(result, (bytes32));\n }\n}\n" + }, + "contracts/beacon/PartialWithdrawal.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library to request full or partial withdrawals from validators on the beacon chain.\n * @author Origin Protocol Inc\n */\nlibrary PartialWithdrawal {\n /// @notice The address where the withdrawal request is sent to\n /// See https://eips.ethereum.org/EIPS/eip-7002\n address internal constant WITHDRAWAL_REQUEST_ADDRESS =\n 0x00000961Ef480Eb55e80D19ad83579A64c007002;\n\n /// @notice Requests a partial withdrawal for a given validator public key and amount.\n /// @param validatorPubKey The public key of the validator to withdraw from\n /// @param amount The amount of ETH to withdraw\n function request(bytes calldata validatorPubKey, uint64 amount)\n internal\n returns (uint256 fee_)\n {\n require(validatorPubKey.length == 48, \"Invalid validator byte length\");\n fee_ = fee();\n\n // Call the Withdrawal Request contract with the validator public key\n // and amount to be withdrawn packed together\n\n // This is a general purpose EL to CL request:\n // https://eips.ethereum.org/EIPS/eip-7685\n (bool success, ) = WITHDRAWAL_REQUEST_ADDRESS.call{ value: fee_ }(\n abi.encodePacked(validatorPubKey, amount)\n );\n\n require(success, \"Withdrawal request failed\");\n }\n\n /// @notice Gets fee for withdrawal requests contract on Beacon chain\n function fee() internal view returns (uint256) {\n // Get fee from the withdrawal request contract\n (bool success, bytes memory result) = WITHDRAWAL_REQUEST_ADDRESS\n .staticcall(\"\");\n\n require(success && result.length > 0, \"Failed to get fee\");\n return abi.decode(result, (uint256));\n }\n}\n" + }, + "contracts/echidna/Debugger.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Debugger {\n event Debug(string debugString);\n event Debug(string description, string data);\n event Debug(string prefix, string description, string data);\n event Debug(string description, bytes32 data);\n event Debug(string prefix, string description, bytes32 data);\n event Debug(string description, uint256 data);\n event Debug(string prefix, string description, uint256 data);\n event Debug(string description, int256 data);\n event Debug(string prefix, string description, int256 data);\n event Debug(string description, address data);\n event Debug(string prefix, string description, address data);\n event Debug(string description, bool data);\n event Debug(string prefix, string description, bool data);\n\n function log(string memory debugString) internal {\n emit Debug(debugString);\n }\n\n function log(string memory description, string memory data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n string memory data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, bytes32 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n bytes32 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, uint256 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n uint256 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, int256 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n int256 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, address data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n address data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, bool data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n bool data\n ) internal {\n emit Debug(prefix, description, data);\n }\n}\n" + }, + "contracts/echidna/Echidna.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaTestApproval.sol\";\n\n/**\n * @title Echidna test contract for OUSD\n * @notice Target contract to be tested, containing all mixins\n * @author Rappie\n */\ncontract Echidna is EchidnaTestApproval {\n\n}\n" + }, + "contracts/echidna/EchidnaConfig.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Top-level mixin for configuring the desired fuzzing setup\n * @author Rappie\n */\ncontract EchidnaConfig {\n address internal constant ADDRESS_VAULT = address(0x10000);\n address internal constant ADDRESS_OUTSIDER_USER = address(0x20000);\n\n address internal constant ADDRESS_USER0 = address(0x30000);\n address internal constant ADDRESS_USER1 = address(0x40000);\n\n // Will be set in EchidnaSetup constructor\n address internal ADDRESS_OUTSIDER_CONTRACT;\n address internal ADDRESS_CONTRACT0;\n address internal ADDRESS_CONTRACT1;\n\n // Toggle known issues\n //\n // This can be used to skip tests that are known to fail. This is useful\n // when debugging a specific issue, but should be disabled when running\n // the full test suite.\n //\n // True => skip tests that are known to fail\n // False => run all tests\n //\n bool internal constant TOGGLE_KNOWN_ISSUES = false;\n\n // Toggle known issues within limits\n //\n // Same as TOGGLE_KNOWN_ISSUES, but also skip tests that are known to fail\n // within limits set by the variables below.\n //\n bool internal constant TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS = true;\n\n // Starting balance\n //\n // Gives OUSD a non-zero starting supply, which can be useful to ignore\n // certain edge cases.\n //\n // The starting balance is given to outsider accounts that are not used as\n // accounts while fuzzing.\n //\n bool internal constant TOGGLE_STARTING_BALANCE = true;\n uint256 internal constant STARTING_BALANCE = 1_000_000e18;\n\n // Change supply\n //\n // Set a limit to the amount of change per rebase, which can be useful to\n // ignore certain edge cases.\n //\n // True => limit the amount of change to a percentage of total supply\n // False => no limit\n //\n bool internal constant TOGGLE_CHANGESUPPLY_LIMIT = true;\n uint256 internal constant CHANGESUPPLY_DIVISOR = 10; // 10% of total supply\n\n // Mint limit\n //\n // Set a limit the amount minted per mint, which can be useful to\n // ignore certain edge cases.\n //\n // True => limit the amount of minted tokens\n // False => no limit\n //\n bool internal constant TOGGLE_MINT_LIMIT = true;\n uint256 internal constant MINT_MODULO = 1_000_000_000_000e18;\n\n // Known rounding errors\n uint256 internal constant TRANSFER_ROUNDING_ERROR = 1e18 - 1;\n uint256 internal constant OPT_IN_ROUNDING_ERROR = 1e18 - 1;\n uint256 internal constant MINT_ROUNDING_ERROR = 1e18 - 1;\n\n /**\n * @notice Modifier to skip tests that are known to fail\n * @dev see TOGGLE_KNOWN_ISSUES for more information\n */\n modifier hasKnownIssue() {\n if (TOGGLE_KNOWN_ISSUES) return;\n _;\n }\n\n /**\n * @notice Modifier to skip tests that are known to fail within limits\n * @dev see TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS for more information\n */\n modifier hasKnownIssueWithinLimits() {\n if (TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS) return;\n _;\n }\n\n /**\n * @notice Translate an account ID to an address\n * @param accountId The ID of the account\n * @return account The address of the account\n */\n function getAccount(uint8 accountId)\n internal\n view\n returns (address account)\n {\n accountId = accountId / 64;\n if (accountId == 0) return account = ADDRESS_USER0;\n if (accountId == 1) return account = ADDRESS_USER1;\n if (accountId == 2) return account = ADDRESS_CONTRACT0;\n if (accountId == 3) return account = ADDRESS_CONTRACT1;\n require(false, \"Unknown account ID\");\n }\n}\n" + }, + "contracts/echidna/EchidnaDebug.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"./EchidnaHelper.sol\";\nimport \"./Debugger.sol\";\n\nimport \"../token/OUSD.sol\";\n\n/**\n * @title Room for random debugging functions\n * @author Rappie\n */\ncontract EchidnaDebug is EchidnaHelper {\n function debugOUSD() public pure {\n // assert(ousd.balanceOf(ADDRESS_USER0) == 1000);\n // assert(ousd.rebaseState(ADDRESS_USER0) != OUSD.RebaseOptions.OptIn);\n // assert(Address.isContract(ADDRESS_CONTRACT0));\n // Debugger.log(\"nonRebasingSupply\", ousd.nonRebasingSupply());\n // assert(false);\n }\n}\n" + }, + "contracts/echidna/EchidnaHelper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaSetup.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin containing helper functions\n * @author Rappie\n */\ncontract EchidnaHelper is EchidnaSetup {\n /**\n * @notice Mint tokens to an account\n * @param toAcc Account to mint to\n * @param amount Amount to mint\n * @return Amount minted (in case of capped mint with modulo)\n */\n function mint(uint8 toAcc, uint256 amount) public returns (uint256) {\n address to = getAccount(toAcc);\n\n if (TOGGLE_MINT_LIMIT) {\n amount = amount % MINT_MODULO;\n }\n\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(to, amount);\n\n return amount;\n }\n\n /**\n * @notice Burn tokens from an account\n * @param fromAcc Account to burn from\n * @param amount Amount to burn\n */\n function burn(uint8 fromAcc, uint256 amount) public {\n address from = getAccount(fromAcc);\n hevm.prank(ADDRESS_VAULT);\n ousd.burn(from, amount);\n }\n\n /**\n * @notice Change the total supply of OUSD (rebase)\n * @param amount New total supply\n */\n function changeSupply(uint256 amount) public {\n if (TOGGLE_CHANGESUPPLY_LIMIT) {\n amount =\n ousd.totalSupply() +\n (amount % (ousd.totalSupply() / CHANGESUPPLY_DIVISOR));\n }\n\n hevm.prank(ADDRESS_VAULT);\n ousd.changeSupply(amount);\n }\n\n /**\n * @notice Transfer tokens between accounts\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function transfer(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n ousd.transfer(to, amount);\n }\n\n /**\n * @notice Transfer approved tokens between accounts\n * @param authorizedAcc Account that is authorized to transfer\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function transferFrom(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n ousd.transferFrom(from, to, amount);\n }\n\n /**\n * @notice Opt in to rebasing\n * @param targetAcc Account to opt in\n */\n function optIn(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n hevm.prank(target);\n ousd.rebaseOptIn();\n }\n\n /**\n * @notice Opt out of rebasing\n * @param targetAcc Account to opt out\n */\n function optOut(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n hevm.prank(target);\n ousd.rebaseOptOut();\n }\n\n /**\n * @notice Approve an account to spend OUSD\n * @param ownerAcc Account that owns the OUSD\n * @param spenderAcc Account that is approved to spend the OUSD\n * @param amount Amount to approve\n */\n function approve(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n hevm.prank(owner);\n // slither-disable-next-line unused-return\n ousd.approve(spender, amount);\n }\n\n /**\n * @notice Get the sum of all OUSD balances\n * @return total Total balance\n */\n function getTotalBalance() public view returns (uint256 total) {\n total += ousd.balanceOf(ADDRESS_VAULT);\n total += ousd.balanceOf(ADDRESS_OUTSIDER_USER);\n total += ousd.balanceOf(ADDRESS_OUTSIDER_CONTRACT);\n total += ousd.balanceOf(ADDRESS_USER0);\n total += ousd.balanceOf(ADDRESS_USER1);\n total += ousd.balanceOf(ADDRESS_CONTRACT0);\n total += ousd.balanceOf(ADDRESS_CONTRACT1);\n }\n\n /**\n * @notice Get the sum of all non-rebasing OUSD balances\n * @return total Total balance\n */\n function getTotalNonRebasingBalance() public returns (uint256 total) {\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_VAULT)\n ? ousd.balanceOf(ADDRESS_VAULT)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_OUTSIDER_USER)\n ? ousd.balanceOf(ADDRESS_OUTSIDER_USER)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_OUTSIDER_CONTRACT)\n ? ousd.balanceOf(ADDRESS_OUTSIDER_CONTRACT)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_USER0)\n ? ousd.balanceOf(ADDRESS_USER0)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_USER1)\n ? ousd.balanceOf(ADDRESS_USER1)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_CONTRACT0)\n ? ousd.balanceOf(ADDRESS_CONTRACT0)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_CONTRACT1)\n ? ousd.balanceOf(ADDRESS_CONTRACT1)\n : 0;\n }\n}\n" + }, + "contracts/echidna/EchidnaSetup.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./IHevm.sol\";\nimport \"./EchidnaConfig.sol\";\nimport \"./OUSDEchidna.sol\";\n\ncontract Dummy {}\n\n/**\n * @title Mixin for setup and deployment\n * @author Rappie\n */\ncontract EchidnaSetup is EchidnaConfig {\n IHevm hevm = IHevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);\n OUSDEchidna ousd = new OUSDEchidna();\n\n /**\n * @notice Deploy the OUSD contract and set up initial state\n */\n constructor() {\n ousd.initialize(ADDRESS_VAULT, 1e18);\n\n // Deploy dummny contracts as users\n Dummy outsider = new Dummy();\n ADDRESS_OUTSIDER_CONTRACT = address(outsider);\n Dummy dummy0 = new Dummy();\n ADDRESS_CONTRACT0 = address(dummy0);\n Dummy dummy1 = new Dummy();\n ADDRESS_CONTRACT1 = address(dummy1);\n\n // Start out with a reasonable amount of OUSD\n if (TOGGLE_STARTING_BALANCE) {\n // Rebasing tokens\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(ADDRESS_OUTSIDER_USER, STARTING_BALANCE / 2);\n\n // Non-rebasing tokens\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(ADDRESS_OUTSIDER_CONTRACT, STARTING_BALANCE / 2);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestAccounting.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestSupply.sol\";\n\n/**\n * @title Mixin for testing accounting functions\n * @author Rappie\n */\ncontract EchidnaTestAccounting is EchidnaTestSupply {\n /**\n * @notice After opting in, balance should not increase. (Ok to lose rounding funds doing this)\n * @param targetAcc Account to opt in\n */\n function testOptInBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optIn(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter <= balanceBefore);\n }\n\n /**\n * @notice After opting out, balance should remain the same\n * @param targetAcc Account to opt out\n */\n function testOptOutBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optOut(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Account balance should remain the same after opting in minus rounding error\n * @param targetAcc Account to opt in\n */\n function testOptInBalanceRounding(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optIn(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n int256 delta = int256(balanceAfter) - int256(balanceBefore);\n Debugger.log(\"delta\", delta);\n\n // slither-disable-next-line tautology\n assert(-1 * delta >= 0);\n assert(-1 * delta <= int256(OPT_IN_ROUNDING_ERROR));\n }\n\n /**\n * @notice After opting in, total supply should remain the same\n * @param targetAcc Account to opt in\n */\n function testOptInTotalSupply(uint8 targetAcc) public {\n uint256 totalSupplyBefore = ousd.totalSupply();\n optIn(targetAcc);\n uint256 totalSupplyAfter = ousd.totalSupply();\n\n assert(totalSupplyAfter == totalSupplyBefore);\n }\n\n /**\n * @notice After opting out, total supply should remain the same\n * @param targetAcc Account to opt out\n */\n function testOptOutTotalSupply(uint8 targetAcc) public {\n uint256 totalSupplyBefore = ousd.totalSupply();\n optOut(targetAcc);\n uint256 totalSupplyAfter = ousd.totalSupply();\n\n assert(totalSupplyAfter == totalSupplyBefore);\n }\n\n /**\n * @notice Account balance should remain the same when a smart contract auto converts\n * @param targetAcc Account to auto convert\n */\n function testAutoConvertBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n // slither-disable-next-line unused-return\n ousd._isNonRebasingAccountEchidna(target);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice The `balanceOf` function should never revert\n * @param targetAcc Account to check balance of\n */\n function testBalanceOfShouldNotRevert(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n // slither-disable-next-line unused-return\n try ousd.balanceOf(target) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestApproval.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaTestMintBurn.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin for testing approval related functions\n * @author Rappie\n */\ncontract EchidnaTestApproval is EchidnaTestMintBurn {\n /**\n * @notice Performing `transferFrom` with an amount inside the allowance should not revert\n * @param authorizedAcc The account that is authorized to transfer\n * @param fromAcc The account that is transferring\n * @param toAcc The account that is receiving\n * @param amount The amount to transfer\n */\n function testTransferFromShouldNotRevert(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount <= ousd.balanceOf(from));\n require(amount <= ousd.allowance(from, authorized));\n\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n try ousd.transferFrom(from, to, amount) {\n // pass\n } catch {\n assert(false);\n }\n }\n\n /**\n * @notice Performing `transferFrom` with an amount outside the allowance should revert\n * @param authorizedAcc The account that is authorized to transfer\n * @param fromAcc The account that is transferring\n * @param toAcc The account that is receiving\n * @param amount The amount to transfer\n */\n function testTransferFromShouldRevert(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount > 0);\n require(\n !(amount <= ousd.balanceOf(from) &&\n amount <= ousd.allowance(from, authorized))\n );\n\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n try ousd.transferFrom(from, to, amount) {\n assert(false);\n } catch {\n // pass\n }\n }\n\n /**\n * @notice Approving an amount should update the allowance and overwrite any previous allowance\n * @param ownerAcc The account that is approving\n * @param spenderAcc The account that is being approved\n * @param amount The amount to approve\n */\n function testApprove(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n\n approve(ownerAcc, spenderAcc, amount);\n uint256 allowanceAfter1 = ousd.allowance(owner, spender);\n\n assert(allowanceAfter1 == amount);\n\n approve(ownerAcc, spenderAcc, amount / 2);\n uint256 allowanceAfter2 = ousd.allowance(owner, spender);\n\n assert(allowanceAfter2 == amount / 2);\n }\n}\n" + }, + "contracts/echidna/EchidnaTestMintBurn.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestAccounting.sol\";\n\n/**\n * @title Mixin for testing Mint and Burn functions\n * @author Rappie\n */\ncontract EchidnaTestMintBurn is EchidnaTestAccounting {\n /**\n * @notice Minting 0 tokens should not affect account balance\n * @param targetAcc Account to mint to\n */\n function testMintZeroBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n mint(targetAcc, 0);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Burning 0 tokens should not affect account balance\n * @param targetAcc Account to burn from\n */\n function testBurnZeroBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n burn(targetAcc, 0);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Minting tokens must increase the account balance by at least amount\n * @param targetAcc Account to mint to\n * @param amount Amount to mint\n * @custom:error testMintBalance(uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * testMintBalance(0,1)\n * Event sequence:\n * Debug(«balanceBefore», 0)\n * Debug(«balanceAfter», 0)\n */\n function testMintBalance(uint8 targetAcc, uint256 amount)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n uint256 amountMinted = mint(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n Debugger.log(\"amountMinted\", amountMinted);\n Debugger.log(\"balanceBefore\", balanceBefore);\n Debugger.log(\"balanceAfter\", balanceAfter);\n\n assert(balanceAfter >= balanceBefore + amountMinted);\n }\n\n /**\n * @notice Burning tokens must decrease the account balance by at least amount\n * @param targetAcc Account to burn from\n * @param amount Amount to burn\n * @custom:error testBurnBalance(uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * mint(0,3)\n * testBurnBalance(0,1)\n * Event sequence:\n * Debug(«balanceBefore», 2)\n * Debug(«balanceAfter», 2)\n */\n function testBurnBalance(uint8 targetAcc, uint256 amount)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n burn(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n Debugger.log(\"balanceBefore\", balanceBefore);\n Debugger.log(\"balanceAfter\", balanceAfter);\n\n assert(balanceAfter <= balanceBefore - amount);\n }\n\n /**\n * @notice Minting tokens should not increase the account balance by less than rounding error above amount\n * @param targetAcc Account to mint to\n * @param amount Amount to mint\n */\n function testMintBalanceRounding(uint8 targetAcc, uint256 amount) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n uint256 amountMinted = mint(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n int256 delta = int256(balanceAfter) - int256(balanceBefore);\n\n // delta == amount, if no error\n // delta < amount, if too little is minted\n // delta > amount, if too much is minted\n int256 error = int256(amountMinted) - delta;\n\n assert(error >= 0);\n assert(error <= int256(MINT_ROUNDING_ERROR));\n }\n\n /**\n * @notice A burn of an account balance must result in a zero balance\n * @param targetAcc Account to burn from\n */\n function testBurnAllBalanceToZero(uint8 targetAcc) public hasKnownIssue {\n address target = getAccount(targetAcc);\n\n burn(targetAcc, ousd.balanceOf(target));\n assert(ousd.balanceOf(target) == 0);\n }\n\n /**\n * @notice You should always be able to burn an account's balance\n * @param targetAcc Account to burn from\n */\n function testBurnAllBalanceShouldNotRevert(uint8 targetAcc)\n public\n hasKnownIssue\n {\n address target = getAccount(targetAcc);\n uint256 balance = ousd.balanceOf(target);\n\n hevm.prank(ADDRESS_VAULT);\n try ousd.burn(target, balance) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestSupply.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestTransfer.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n/**\n * @title Mixin for testing supply related functions\n * @author Rappie\n */\ncontract EchidnaTestSupply is EchidnaTestTransfer {\n using StableMath for uint256;\n\n uint256 prevRebasingCreditsPerToken = type(uint256).max;\n\n /**\n * @notice After a `changeSupply`, the total supply should exactly\n * match the target total supply. (This is needed to ensure successive\n * rebases are correct).\n * @param supply New total supply\n * @custom:error testChangeSupply(uint256): failed!💥\n * Call sequence:\n * testChangeSupply(1044505275072865171609)\n * Event sequence:\n * TotalSupplyUpdatedHighres(1044505275072865171610, 1000000000000000000000000, 957391048054055578595)\n */\n function testChangeSupply(uint256 supply)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n hevm.prank(ADDRESS_VAULT);\n ousd.changeSupply(supply);\n\n assert(ousd.totalSupply() == supply);\n }\n\n /**\n * @notice The total supply must not be less than the sum of account balances.\n * (The difference will go into future rebases)\n * @custom:error testTotalSupplyLessThanTotalBalance(): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(1)\n * optOut(64)\n * transfer(0,64,1)\n * testTotalSupplyLessThanTotalBalance()\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000001000001)\n * Debug(«totalBalance», 1000000000000000001000002)\n */\n function testTotalSupplyLessThanTotalBalance()\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n uint256 totalSupply = ousd.totalSupply();\n uint256 totalBalance = getTotalBalance();\n\n Debugger.log(\"totalSupply\", totalSupply);\n Debugger.log(\"totalBalance\", totalBalance);\n\n assert(totalSupply >= totalBalance);\n }\n\n /**\n * @notice Non-rebasing supply should not be larger than total supply\n * @custom:error testNonRebasingSupplyVsTotalSupply(): failed!💥\n * Call sequence:\n * mint(0,2)\n * changeSupply(3)\n * burn(0,1)\n * optOut(0)\n * testNonRebasingSupplyVsTotalSupply()\n */\n function testNonRebasingSupplyVsTotalSupply() public hasKnownIssue {\n uint256 nonRebasingSupply = ousd.nonRebasingSupply();\n uint256 totalSupply = ousd.totalSupply();\n\n assert(nonRebasingSupply <= totalSupply);\n }\n\n /**\n * @notice Global `rebasingCreditsPerToken` should never increase\n * @custom:error testRebasingCreditsPerTokenNotIncreased(): failed!💥\n * Call sequence:\n * testRebasingCreditsPerTokenNotIncreased()\n * changeSupply(1)\n * testRebasingCreditsPerTokenNotIncreased()\n */\n function testRebasingCreditsPerTokenNotIncreased() public hasKnownIssue {\n uint256 curRebasingCreditsPerToken = ousd\n .rebasingCreditsPerTokenHighres();\n\n Debugger.log(\n \"prevRebasingCreditsPerToken\",\n prevRebasingCreditsPerToken\n );\n Debugger.log(\"curRebasingCreditsPerToken\", curRebasingCreditsPerToken);\n\n assert(curRebasingCreditsPerToken <= prevRebasingCreditsPerToken);\n\n prevRebasingCreditsPerToken = curRebasingCreditsPerToken;\n }\n\n /**\n * @notice The rebasing credits per token ratio must greater than zero\n */\n function testRebasingCreditsPerTokenAboveZero() public {\n assert(ousd.rebasingCreditsPerTokenHighres() > 0);\n }\n\n /**\n * @notice The sum of all non-rebasing balances should not be larger than\n * non-rebasing supply\n * @custom:error testTotalNonRebasingSupplyLessThanTotalBalance(): failed!💥\n * Call sequence\n * mint(0,2)\n * changeSupply(1)\n * optOut(0)\n * burn(0,1)\n * testTotalNonRebasingSupplyLessThanTotalBalance()\n * Event sequence:\n * Debug(«totalNonRebasingSupply», 500000000000000000000001)\n * Debug(«totalNonRebasingBalance», 500000000000000000000002)\n */\n function testTotalNonRebasingSupplyLessThanTotalBalance()\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n uint256 totalNonRebasingSupply = ousd.nonRebasingSupply();\n uint256 totalNonRebasingBalance = getTotalNonRebasingBalance();\n\n Debugger.log(\"totalNonRebasingSupply\", totalNonRebasingSupply);\n Debugger.log(\"totalNonRebasingBalance\", totalNonRebasingBalance);\n\n assert(totalNonRebasingSupply >= totalNonRebasingBalance);\n }\n\n /**\n * @notice An accounts credits / credits per token should not be larger it's balance\n * @param targetAcc The account to check\n */\n function testCreditsPerTokenVsBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n (uint256 credits, uint256 creditsPerToken, ) = ousd\n .creditsBalanceOfHighres(target);\n uint256 expectedBalance = credits.divPrecisely(creditsPerToken);\n\n uint256 balance = ousd.balanceOf(target);\n\n Debugger.log(\"credits\", credits);\n Debugger.log(\"creditsPerToken\", creditsPerToken);\n Debugger.log(\"expectedBalance\", expectedBalance);\n Debugger.log(\"balance\", balance);\n\n assert(expectedBalance == balance);\n }\n}\n" + }, + "contracts/echidna/EchidnaTestTransfer.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin for testing transfer related functions\n * @author Rappie\n */\ncontract EchidnaTestTransfer is EchidnaDebug {\n /**\n * @notice The receiving account's balance after a transfer must not increase by\n * less than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferBalanceReceivedLess(uint8,uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * mint(64,2)\n * testTransferBalanceReceivedLess(64,0,1)\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000000500002)\n * Debug(«toBalBefore», 0)\n * Debug(«toBalAfter», 0)\n */\n function testTransferBalanceReceivedLess(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue hasKnownIssueWithinLimits {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n\n assert(toBalAfter >= toBalBefore + amount);\n }\n\n /**\n * @notice The receiving account's balance after a transfer must not\n * increase by more than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceReceivedMore(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n\n assert(toBalAfter <= toBalBefore + amount);\n }\n\n /**\n * @notice The sending account's balance after a transfer must not\n * decrease by less than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferBalanceSentLess(uint8,uint8,uint256): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(1)\n * testTransferBalanceSentLess(0,64,1)\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000000500001)\n * Debug(«fromBalBefore», 1)\n * Debug(«fromBalAfter», 1)\n */\n function testTransferBalanceSentLess(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue hasKnownIssueWithinLimits {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n\n assert(fromBalAfter <= fromBalBefore - amount);\n }\n\n /**\n * @notice The sending account's balance after a transfer must not\n * decrease by more than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceSentMore(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n\n assert(fromBalAfter >= fromBalBefore - amount);\n }\n\n /**\n * @notice The receiving account's balance after a transfer must not\n * increase by less than the amount transferred (minus rounding error)\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceReceivedLessRounding(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n int256 toDelta = int256(toBalAfter) - int256(toBalBefore);\n\n // delta == amount, if no error\n // delta < amount, if too little is sent\n // delta > amount, if too much is sent\n int256 error = int256(amount) - toDelta;\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n Debugger.log(\"toDelta\", toDelta);\n Debugger.log(\"error\", error);\n\n assert(error >= 0);\n assert(error <= int256(TRANSFER_ROUNDING_ERROR));\n }\n\n /**\n * @notice The sending account's balance after a transfer must\n * not decrease by less than the amount transferred (minus rounding error)\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceSentLessRounding(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n int256 fromDelta = int256(fromBalAfter) - int256(fromBalBefore);\n\n // delta == -amount, if no error\n // delta < -amount, if too much is sent\n // delta > -amount, if too little is sent\n int256 error = int256(amount) + fromDelta;\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n Debugger.log(\"fromDelta\", fromDelta);\n Debugger.log(\"error\", error);\n\n assert(error >= 0);\n assert(error <= int256(TRANSFER_ROUNDING_ERROR));\n }\n\n /**\n * @notice An account should always be able to successfully transfer\n * an amount within its balance.\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferWithinBalanceDoesNotRevert(uint8,uint8,uint8): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(3)\n * optOut(0)\n * testTransferWithinBalanceDoesNotRevert(0,128,2)\n * optIn(0)\n * testTransferWithinBalanceDoesNotRevert(128,0,1)\n * Event sequence:\n * error Revert Panic(17): SafeMath over-/under-flows\n */\n function testTransferWithinBalanceDoesNotRevert(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount > 0);\n amount = amount % ousd.balanceOf(from);\n\n Debugger.log(\"Total supply\", ousd.totalSupply());\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(to, amount) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n\n /**\n * @notice An account should never be able to successfully transfer\n * an amount greater than their balance.\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferExceedingBalanceReverts(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n amount = ousd.balanceOf(from) + 1 + amount;\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(to, amount) {\n assert(false);\n } catch {\n assert(true);\n }\n }\n\n /**\n * @notice A transfer to the same account should not change that account's balance\n * @param targetAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferSelf(uint8 targetAcc, uint256 amount) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n transfer(targetAcc, targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceBefore == balanceAfter);\n }\n\n /**\n * @notice Transfers to the zero account revert\n * @param fromAcc Account to transfer from\n * @param amount Amount to transfer\n */\n function testTransferToZeroAddress(uint8 fromAcc, uint256 amount) public {\n address from = getAccount(fromAcc);\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(address(0), amount) {\n assert(false);\n } catch {\n assert(true);\n }\n }\n}\n" + }, + "contracts/echidna/IHevm.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// https://github.com/ethereum/hevm/blob/main/doc/src/controlling-the-unit-testing-environment.md#cheat-codes\n\ninterface IHevm {\n function warp(uint256 x) external;\n\n function roll(uint256 x) external;\n\n function store(\n address c,\n bytes32 loc,\n bytes32 val\n ) external;\n\n function load(address c, bytes32 loc) external returns (bytes32 val);\n\n function sign(uint256 sk, bytes32 digest)\n external\n returns (\n uint8 v,\n bytes32 r,\n bytes32 s\n );\n\n function addr(uint256 sk) external returns (address addr);\n\n function ffi(string[] calldata) external returns (bytes memory);\n\n function prank(address sender) external;\n}\n" + }, + "contracts/echidna/OUSDEchidna.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../token/OUSD.sol\";\n\ncontract OUSDEchidna is OUSD {\n constructor() OUSD() {}\n\n function _isNonRebasingAccountEchidna(address _account)\n public\n returns (bool)\n {\n _autoMigrate(_account);\n return alternativeCreditsPerToken[_account] > 0;\n }\n}\n" + }, + "contracts/governance/Governable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\n * from owner to governor and renounce methods removed. Does not use\n * Context.sol like Ownable.sol does for simplification.\n * @author Origin Protocol Inc\n */\nabstract contract Governable {\n // Storage position of the owner and pendingOwner of the contract\n // keccak256(\"OUSD.governor\");\n bytes32 private constant governorPosition =\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\n\n // keccak256(\"OUSD.pending.governor\");\n bytes32 private constant pendingGovernorPosition =\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\n\n // keccak256(\"OUSD.reentry.status\");\n bytes32 private constant reentryStatusPosition =\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\n\n // See OpenZeppelin ReentrancyGuard implementation\n uint256 constant _NOT_ENTERED = 1;\n uint256 constant _ENTERED = 2;\n\n event PendingGovernorshipTransfer(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n\n event GovernorshipTransferred(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n\n /**\n * @notice Returns the address of the current Governor.\n */\n function governor() public view returns (address) {\n return _governor();\n }\n\n /**\n * @dev Returns the address of the current Governor.\n */\n function _governor() internal view returns (address governorOut) {\n bytes32 position = governorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n governorOut := sload(position)\n }\n }\n\n /**\n * @dev Returns the address of the pending Governor.\n */\n function _pendingGovernor()\n internal\n view\n returns (address pendingGovernor)\n {\n bytes32 position = pendingGovernorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n pendingGovernor := sload(position)\n }\n }\n\n /**\n * @dev Throws if called by any account other than the Governor.\n */\n modifier onlyGovernor() {\n require(isGovernor(), \"Caller is not the Governor\");\n _;\n }\n\n /**\n * @notice Returns true if the caller is the current Governor.\n */\n function isGovernor() public view returns (bool) {\n return msg.sender == _governor();\n }\n\n function _setGovernor(address newGovernor) internal {\n emit GovernorshipTransferred(_governor(), newGovernor);\n\n bytes32 position = governorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, newGovernor)\n }\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and make it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n bytes32 position = reentryStatusPosition;\n uint256 _reentry_status;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n _reentry_status := sload(position)\n }\n\n // On the first call to nonReentrant, _notEntered will be true\n require(_reentry_status != _ENTERED, \"Reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, _ENTERED)\n }\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, _NOT_ENTERED)\n }\n }\n\n function _setPendingGovernor(address newGovernor) internal {\n bytes32 position = pendingGovernorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, newGovernor)\n }\n }\n\n /**\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\n * Can only be called by the current Governor. Must be claimed for this to complete\n * @param _newGovernor Address of the new Governor\n */\n function transferGovernance(address _newGovernor) external onlyGovernor {\n _setPendingGovernor(_newGovernor);\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\n }\n\n /**\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\n * Can only be called by the new Governor.\n */\n function claimGovernance() external {\n require(\n msg.sender == _pendingGovernor(),\n \"Only the pending Governor can complete the claim\"\n );\n _changeGovernor(msg.sender);\n }\n\n /**\n * @dev Change Governance of the contract to a new account (`newGovernor`).\n * @param _newGovernor Address of the new Governor\n */\n function _changeGovernor(address _newGovernor) internal {\n require(_newGovernor != address(0), \"New Governor is address(0)\");\n _setGovernor(_newGovernor);\n }\n}\n" + }, + "contracts/governance/Strategizable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Governable } from \"./Governable.sol\";\n\ncontract Strategizable is Governable {\n event StrategistUpdated(address _address);\n\n // Address of strategist\n address public strategistAddr;\n\n // For future use\n uint256[50] private __gap;\n\n /**\n * @dev Verifies that the caller is either Governor or Strategist.\n */\n modifier onlyGovernorOrStrategist() virtual {\n require(\n msg.sender == strategistAddr || isGovernor(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n /**\n * @dev Set address of Strategist\n * @param _address Address of Strategist\n */\n function setStrategistAddr(address _address) external onlyGovernor {\n _setStrategistAddr(_address);\n }\n\n /**\n * @dev Set address of Strategist\n * @param _address Address of Strategist\n */\n function _setStrategistAddr(address _address) internal {\n strategistAddr = _address;\n emit StrategistUpdated(_address);\n }\n}\n" + }, + "contracts/harvest/AbstractHarvester.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { IUniswapV2Router } from \"../interfaces/uniswap/IUniswapV2Router02.sol\";\nimport { IUniswapV3Router } from \"../interfaces/uniswap/IUniswapV3Router.sol\";\nimport { IBalancerVault } from \"../interfaces/balancer/IBalancerVault.sol\";\nimport { ICurvePool } from \"../strategies/ICurvePool.sol\";\nimport \"../utils/Helpers.sol\";\n\nabstract contract AbstractHarvester is Governable {\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n using StableMath for uint256;\n\n enum SwapPlatform {\n UniswapV2Compatible,\n UniswapV3,\n Balancer,\n Curve\n }\n\n event SupportedStrategyUpdate(address strategyAddress, bool isSupported);\n event RewardTokenConfigUpdated(\n address tokenAddress,\n uint16 allowedSlippageBps,\n uint16 harvestRewardBps,\n SwapPlatform swapPlatform,\n address swapPlatformAddr,\n bytes swapData,\n uint256 liquidationLimit,\n bool doSwapRewardToken\n );\n event RewardTokenSwapped(\n address indexed rewardToken,\n address indexed swappedInto,\n SwapPlatform swapPlatform,\n uint256 amountIn,\n uint256 amountOut\n );\n event RewardProceedsTransferred(\n address indexed token,\n address farmer,\n uint256 protcolYield,\n uint256 farmerFee\n );\n event RewardProceedsAddressChanged(address newProceedsAddress);\n\n error EmptyAddress();\n error InvalidSlippageBps();\n error InvalidHarvestRewardBps();\n\n error InvalidSwapPlatform(SwapPlatform swapPlatform);\n\n error InvalidUniswapV2PathLength();\n error InvalidTokenInSwapPath(address token);\n error EmptyBalancerPoolId();\n error InvalidCurvePoolAssetIndex(address token);\n\n error UnsupportedStrategy(address strategyAddress);\n\n error SlippageError(uint256 actualBalance, uint256 minExpected);\n error BalanceMismatchAfterSwap(uint256 actualBalance, uint256 minExpected);\n\n // Configuration properties for harvesting logic of reward tokens\n struct RewardTokenConfig {\n // Max allowed slippage when swapping reward token for a stablecoin denominated in basis points.\n uint16 allowedSlippageBps;\n // Reward when calling a harvest function denominated in basis points.\n uint16 harvestRewardBps;\n // Address of compatible exchange protocol (Uniswap V2/V3, SushiSwap, Balancer and Curve).\n address swapPlatformAddr;\n /* When true the reward token is being swapped. In a need of (temporarily) disabling the swapping of\n * a reward token this needs to be set to false.\n */\n bool doSwapRewardToken;\n // Platform to use for Swapping\n SwapPlatform swapPlatform;\n /* How much token can be sold per one harvest call. If the balance of rewards tokens\n * exceeds that limit multiple harvest calls are required to harvest all of the tokens.\n * Set it to MAX_INT to effectively disable the limit.\n */\n uint256 liquidationLimit;\n }\n\n mapping(address => RewardTokenConfig) public rewardTokenConfigs;\n mapping(address => bool) public supportedStrategies;\n\n address public immutable vaultAddress;\n\n /**\n * Address receiving rewards proceeds. Initially the Vault contract later will possibly\n * be replaced by another contract that eases out rewards distribution.\n **/\n address public rewardProceedsAddress;\n\n /**\n * All tokens are swapped to this token before it gets transferred\n * to the `rewardProceedsAddress`. USDT for OUSD and WETH for OETH.\n **/\n address public immutable baseTokenAddress;\n // Cached decimals for `baseTokenAddress`\n uint256 public immutable baseTokenDecimals;\n\n // Uniswap V2 path for reward tokens using Uniswap V2 Router\n mapping(address => address[]) public uniswapV2Path;\n // Uniswap V3 path for reward tokens using Uniswap V3 Router\n mapping(address => bytes) public uniswapV3Path;\n // Pool ID to use for reward tokens on Balancer\n mapping(address => bytes32) public balancerPoolId;\n\n struct CurvePoolIndices {\n // Casted into uint128 and stored in a struct to save gas\n uint128 rewardTokenIndex;\n uint128 baseTokenIndex;\n }\n // Packed indices of assets on the Curve pool\n mapping(address => CurvePoolIndices) public curvePoolIndices;\n\n constructor(address _vaultAddress, address _baseTokenAddress) {\n require(_vaultAddress != address(0));\n require(_baseTokenAddress != address(0));\n\n vaultAddress = _vaultAddress;\n baseTokenAddress = _baseTokenAddress;\n\n // Cache decimals as well\n baseTokenDecimals = Helpers.getDecimals(_baseTokenAddress);\n }\n\n /***************************************\n Configuration\n ****************************************/\n\n /**\n * Set the Address receiving rewards proceeds.\n * @param _rewardProceedsAddress Address of the reward token\n */\n function setRewardProceedsAddress(address _rewardProceedsAddress)\n external\n onlyGovernor\n {\n if (_rewardProceedsAddress == address(0)) {\n revert EmptyAddress();\n }\n\n rewardProceedsAddress = _rewardProceedsAddress;\n emit RewardProceedsAddressChanged(_rewardProceedsAddress);\n }\n\n /**\n * @dev Add/update a reward token configuration that holds harvesting config variables\n * @param _tokenAddress Address of the reward token\n * @param tokenConfig.allowedSlippageBps uint16 maximum allowed slippage denominated in basis points.\n * Example: 300 == 3% slippage\n * @param tokenConfig.harvestRewardBps uint16 amount of reward tokens the caller of the function is rewarded.\n * Example: 100 == 1%\n * @param tokenConfig.swapPlatformAddr Address Address of a UniswapV2 compatible contract to perform\n * the exchange from reward tokens to stablecoin (currently hard-coded to USDT)\n * @param tokenConfig.liquidationLimit uint256 Maximum amount of token to be sold per one swap function call.\n * When value is 0 there is no limit.\n * @param tokenConfig.doSwapRewardToken bool Disables swapping of the token when set to true,\n * does not cause it to revert though.\n * @param tokenConfig.swapPlatform SwapPlatform to use for Swapping\n * @param swapData Additional data required for swapping\n */\n function setRewardTokenConfig(\n address _tokenAddress,\n RewardTokenConfig calldata tokenConfig,\n bytes calldata swapData\n ) external onlyGovernor {\n if (tokenConfig.allowedSlippageBps > 1000) {\n revert InvalidSlippageBps();\n }\n\n if (tokenConfig.harvestRewardBps > 1000) {\n revert InvalidHarvestRewardBps();\n }\n\n address newRouterAddress = tokenConfig.swapPlatformAddr;\n if (newRouterAddress == address(0)) {\n // Swap router address should be non zero address\n revert EmptyAddress();\n }\n\n address oldRouterAddress = rewardTokenConfigs[_tokenAddress]\n .swapPlatformAddr;\n rewardTokenConfigs[_tokenAddress] = tokenConfig;\n\n // Revert if feed does not exist\n // slither-disable-next-line unused-return\n\n IERC20 token = IERC20(_tokenAddress);\n // if changing token swap provider cancel existing allowance\n if (\n /* oldRouterAddress == address(0) when there is no pre-existing\n * configuration for said rewards token\n */\n oldRouterAddress != address(0) &&\n oldRouterAddress != newRouterAddress\n ) {\n token.safeApprove(oldRouterAddress, 0);\n }\n\n // Give SwapRouter infinite approval when needed\n if (oldRouterAddress != newRouterAddress) {\n token.safeApprove(newRouterAddress, 0);\n token.safeApprove(newRouterAddress, type(uint256).max);\n }\n\n SwapPlatform _platform = tokenConfig.swapPlatform;\n if (_platform == SwapPlatform.UniswapV2Compatible) {\n uniswapV2Path[_tokenAddress] = _decodeUniswapV2Path(\n swapData,\n _tokenAddress\n );\n } else if (_platform == SwapPlatform.UniswapV3) {\n uniswapV3Path[_tokenAddress] = _decodeUniswapV3Path(\n swapData,\n _tokenAddress\n );\n } else if (_platform == SwapPlatform.Balancer) {\n balancerPoolId[_tokenAddress] = _decodeBalancerPoolId(\n swapData,\n newRouterAddress,\n _tokenAddress\n );\n } else if (_platform == SwapPlatform.Curve) {\n curvePoolIndices[_tokenAddress] = _decodeCurvePoolIndices(\n swapData,\n newRouterAddress,\n _tokenAddress\n );\n } else {\n // Note: This code is unreachable since Solidity reverts when\n // the value is outside the range of defined values of the enum\n // (even if it's under the max length of the base type)\n revert InvalidSwapPlatform(_platform);\n }\n\n emit RewardTokenConfigUpdated(\n _tokenAddress,\n tokenConfig.allowedSlippageBps,\n tokenConfig.harvestRewardBps,\n _platform,\n newRouterAddress,\n swapData,\n tokenConfig.liquidationLimit,\n tokenConfig.doSwapRewardToken\n );\n }\n\n /**\n * @dev Decodes the data passed into Uniswap V2 path and validates\n * it to make sure the path is for `token` to `baseToken`\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @param token The address of the reward token\n * @return path The validated Uniswap V2 path\n */\n function _decodeUniswapV2Path(bytes calldata data, address token)\n internal\n view\n returns (address[] memory path)\n {\n (path) = abi.decode(data, (address[]));\n uint256 len = path.length;\n\n if (len < 2) {\n // Path should have at least two tokens\n revert InvalidUniswapV2PathLength();\n }\n\n // Do some validation\n if (path[0] != token) {\n revert InvalidTokenInSwapPath(path[0]);\n }\n\n if (path[len - 1] != baseTokenAddress) {\n revert InvalidTokenInSwapPath(path[len - 1]);\n }\n }\n\n /**\n * @dev Decodes the data passed into Uniswap V3 path and validates\n * it to make sure the path is for `token` to `baseToken`\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @param token The address of the reward token\n * @return path The validated Uniswap V3 path\n */\n function _decodeUniswapV3Path(bytes calldata data, address token)\n internal\n view\n returns (bytes calldata path)\n {\n path = data;\n\n address decodedAddress = address(uint160(bytes20(data[0:20])));\n\n if (decodedAddress != token) {\n // Invalid Reward Token in swap path\n revert InvalidTokenInSwapPath(decodedAddress);\n }\n\n decodedAddress = address(uint160(bytes20(data[path.length - 20:])));\n if (decodedAddress != baseTokenAddress) {\n // Invalid Base Token in swap path\n revert InvalidTokenInSwapPath(decodedAddress);\n }\n }\n\n /**\n * @dev Decodes the data passed to Balancer Pool ID\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @return poolId The pool ID\n */\n function _decodeBalancerPoolId(\n bytes calldata data,\n address balancerVault,\n address token\n ) internal view returns (bytes32 poolId) {\n (poolId) = abi.decode(data, (bytes32));\n\n if (poolId == bytes32(0)) {\n revert EmptyBalancerPoolId();\n }\n\n IBalancerVault bVault = IBalancerVault(balancerVault);\n\n // Note: this reverts if token is not a pool asset\n // slither-disable-next-line unused-return\n bVault.getPoolTokenInfo(poolId, token);\n\n // slither-disable-next-line unused-return\n bVault.getPoolTokenInfo(poolId, baseTokenAddress);\n }\n\n /**\n * @dev Decodes the data passed to get the pool indices and\n * checks it against the Curve Pool to make sure it's\n * not misconfigured. The indices are packed into a single\n * uint256 for gas savings\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @param poolAddress Curve pool address\n * @param token The address of the reward token\n * @return indices Packed pool asset indices\n */\n function _decodeCurvePoolIndices(\n bytes calldata data,\n address poolAddress,\n address token\n ) internal view returns (CurvePoolIndices memory indices) {\n indices = abi.decode(data, (CurvePoolIndices));\n\n ICurvePool pool = ICurvePool(poolAddress);\n if (token != pool.coins(indices.rewardTokenIndex)) {\n revert InvalidCurvePoolAssetIndex(token);\n }\n if (baseTokenAddress != pool.coins(indices.baseTokenIndex)) {\n revert InvalidCurvePoolAssetIndex(baseTokenAddress);\n }\n }\n\n /**\n * @dev Flags a strategy as supported or not supported one\n * @param _strategyAddress Address of the strategy\n * @param _isSupported Bool marking strategy as supported or not supported\n */\n function setSupportedStrategy(address _strategyAddress, bool _isSupported)\n external\n onlyGovernor\n {\n supportedStrategies[_strategyAddress] = _isSupported;\n emit SupportedStrategyUpdate(_strategyAddress, _isSupported);\n }\n\n /***************************************\n Rewards\n ****************************************/\n\n /**\n * @dev Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform. Can be called by anyone.\n * Rewards incentivizing the caller are sent to the caller of this function.\n * @param _strategyAddr Address of the strategy to collect rewards from\n */\n function harvestAndSwap(address _strategyAddr) external nonReentrant {\n // Remember _harvest function checks for the validity of _strategyAddr\n _harvestAndSwap(_strategyAddr, msg.sender);\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform. Can be called by anyone\n * @param _strategyAddr Address of the strategy to collect rewards from\n * @param _rewardTo Address where to send a share of harvest rewards to as an incentive\n * for executing this function\n */\n function harvestAndSwap(address _strategyAddr, address _rewardTo)\n external\n nonReentrant\n {\n // Remember _harvest function checks for the validity of _strategyAddr\n _harvestAndSwap(_strategyAddr, _rewardTo);\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform\n * @param _strategyAddr Address of the strategy to collect rewards from\n * @param _rewardTo Address where to send a share of harvest rewards to as an incentive\n * for executing this function\n */\n function _harvestAndSwap(address _strategyAddr, address _rewardTo)\n internal\n {\n _harvest(_strategyAddr);\n IStrategy strategy = IStrategy(_strategyAddr);\n address[] memory rewardTokens = strategy.getRewardTokenAddresses();\n uint256 len = rewardTokens.length;\n for (uint256 i = 0; i < len; ++i) {\n // This harvester contract is not used anymore. Keeping the code\n // for passing test deployment. Safe to use address(0x1) as oracle.\n _swap(rewardTokens[i], _rewardTo, IOracle(address(0x1)));\n }\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform\n * @param _strategyAddr Address of the strategy to collect rewards from.\n */\n function _harvest(address _strategyAddr) internal virtual {\n if (!supportedStrategies[_strategyAddr]) {\n revert UnsupportedStrategy(_strategyAddr);\n }\n\n IStrategy strategy = IStrategy(_strategyAddr);\n strategy.collectRewardTokens();\n }\n\n /**\n * @dev Swap a reward token for the base token on the configured\n * swap platform. The token must have a registered price feed\n * with the price provider\n * @param _swapToken Address of the token to swap\n * @param _rewardTo Address where to send the share of harvest rewards to\n * @param _priceProvider Oracle to get prices of the swap token\n */\n // This function is called by the harvestAndSwap function, which is only called by\n // functions that have the nonReentrant modifier. Therefore, this function is also non-reentrant.\n // slither-disable-start reentrancy-eth,reentrancy-no-eth,reentrancy-benign\n // slither-disable-start reentrancy-events,reentrancy-unlimited-gas,reentrancy-balance\n function _swap(\n address _swapToken,\n address _rewardTo,\n IOracle _priceProvider\n ) internal virtual {\n uint256 balance = IERC20(_swapToken).balanceOf(address(this));\n\n // No need to swap if the reward token is the base token. eg USDT or WETH.\n // There is also no limit on the transfer. Everything in the harvester will be transferred\n // to the Dripper regardless of the liquidationLimit config.\n if (_swapToken == baseTokenAddress) {\n IERC20(_swapToken).safeTransfer(rewardProceedsAddress, balance);\n // currently not paying the farmer any rewards as there is no swap\n emit RewardProceedsTransferred(\n baseTokenAddress,\n address(0),\n balance,\n 0\n );\n return;\n }\n\n RewardTokenConfig memory tokenConfig = rewardTokenConfigs[_swapToken];\n\n /* This will trigger a return when reward token configuration has not yet been set\n * or we have temporarily disabled swapping of specific reward token via setting\n * doSwapRewardToken to false.\n */\n if (!tokenConfig.doSwapRewardToken) {\n return;\n }\n\n if (balance == 0) {\n return;\n }\n\n if (tokenConfig.liquidationLimit > 0) {\n balance = Math.min(balance, tokenConfig.liquidationLimit);\n }\n\n // This'll revert if there is no price feed\n uint256 oraclePrice = _priceProvider.price(_swapToken);\n\n // Oracle price is 1e18\n uint256 minExpected = (balance *\n (1e4 - tokenConfig.allowedSlippageBps) * // max allowed slippage\n oraclePrice).scaleBy(\n baseTokenDecimals,\n Helpers.getDecimals(_swapToken)\n ) /\n 1e4 / // fix the max slippage decimal position\n 1e18; // and oracle price decimals position\n\n // Do the swap\n uint256 amountReceived = _doSwap(\n tokenConfig.swapPlatform,\n tokenConfig.swapPlatformAddr,\n _swapToken,\n balance,\n minExpected\n );\n\n if (amountReceived < minExpected) {\n revert SlippageError(amountReceived, minExpected);\n }\n\n emit RewardTokenSwapped(\n _swapToken,\n baseTokenAddress,\n tokenConfig.swapPlatform,\n balance,\n amountReceived\n );\n\n IERC20 baseToken = IERC20(baseTokenAddress);\n uint256 baseTokenBalance = baseToken.balanceOf(address(this));\n if (baseTokenBalance < amountReceived) {\n // Note: It's possible to bypass this check by transferring `baseToken`\n // directly to Harvester before calling the `harvestAndSwap`. However,\n // there's no incentive for an attacker to do that. Doing a balance diff\n // will increase the gas cost significantly\n revert BalanceMismatchAfterSwap(baseTokenBalance, amountReceived);\n }\n\n // Farmer only gets fee from the base amount they helped farm,\n // They do not get anything from anything that already was there\n // on the Harvester\n uint256 farmerFee = amountReceived.mulTruncateScale(\n tokenConfig.harvestRewardBps,\n 1e4\n );\n uint256 protocolYield = baseTokenBalance - farmerFee;\n\n baseToken.safeTransfer(rewardProceedsAddress, protocolYield);\n baseToken.safeTransfer(_rewardTo, farmerFee);\n emit RewardProceedsTransferred(\n baseTokenAddress,\n _rewardTo,\n protocolYield,\n farmerFee\n );\n }\n\n // slither-disable-end reentrancy-events,reentrancy-unlimited-gas,reentrancy-balance\n // slither-disable-end reentrancy-eth,reentrancy-no-eth,reentrancy-benign\n\n function _doSwap(\n SwapPlatform swapPlatform,\n address routerAddress,\n address rewardTokenAddress,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n if (swapPlatform == SwapPlatform.UniswapV2Compatible) {\n return\n _swapWithUniswapV2(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else if (swapPlatform == SwapPlatform.UniswapV3) {\n return\n _swapWithUniswapV3(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else if (swapPlatform == SwapPlatform.Balancer) {\n return\n _swapWithBalancer(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else if (swapPlatform == SwapPlatform.Curve) {\n return\n _swapWithCurve(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else {\n // Should never be invoked since we catch invalid values\n // in the `setRewardTokenConfig` function before it's set\n revert InvalidSwapPlatform(swapPlatform);\n }\n }\n\n /**\n * @dev Swaps the token to `baseToken` with Uniswap V2\n *\n * @param routerAddress Uniswap V2 Router address\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithUniswapV2(\n address routerAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n address[] memory path = uniswapV2Path[swapToken];\n\n uint256[] memory amounts = IUniswapV2Router(routerAddress)\n .swapExactTokensForTokens(\n amountIn,\n minAmountOut,\n path,\n address(this),\n block.timestamp\n );\n\n amountOut = amounts[amounts.length - 1];\n }\n\n /**\n * @dev Swaps the token to `baseToken` with Uniswap V3\n *\n * @param routerAddress Uniswap V3 Router address\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithUniswapV3(\n address routerAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n bytes memory path = uniswapV3Path[swapToken];\n\n IUniswapV3Router.ExactInputParams memory params = IUniswapV3Router\n .ExactInputParams({\n path: path,\n recipient: address(this),\n deadline: block.timestamp,\n amountIn: amountIn,\n amountOutMinimum: minAmountOut\n });\n amountOut = IUniswapV3Router(routerAddress).exactInput(params);\n }\n\n /**\n * @dev Swaps the token to `baseToken` on Balancer\n *\n * @param balancerVaultAddress BalancerVaultAddress\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithBalancer(\n address balancerVaultAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n bytes32 poolId = balancerPoolId[swapToken];\n\n IBalancerVault.SingleSwap memory singleSwap = IBalancerVault\n .SingleSwap({\n poolId: poolId,\n kind: IBalancerVault.SwapKind.GIVEN_IN,\n assetIn: swapToken,\n assetOut: baseTokenAddress,\n amount: amountIn,\n userData: hex\"\"\n });\n\n IBalancerVault.FundManagement memory fundMgmt = IBalancerVault\n .FundManagement({\n sender: address(this),\n fromInternalBalance: false,\n recipient: payable(address(this)),\n toInternalBalance: false\n });\n\n amountOut = IBalancerVault(balancerVaultAddress).swap(\n singleSwap,\n fundMgmt,\n minAmountOut,\n block.timestamp\n );\n }\n\n /**\n * @dev Swaps the token to `baseToken` on Curve\n *\n * @param poolAddress Curve Pool Address\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithCurve(\n address poolAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n CurvePoolIndices memory indices = curvePoolIndices[swapToken];\n\n // Note: Not all CurvePools return the `amountOut`, make sure\n // to use only pool that do. Otherwise the swap would revert\n // always\n amountOut = ICurvePool(poolAddress).exchange(\n uint256(indices.rewardTokenIndex),\n uint256(indices.baseTokenIndex),\n amountIn,\n minAmountOut\n );\n }\n}\n" + }, + "contracts/harvest/Dripper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\n/**\n * @title OUSD Dripper\n *\n * The dripper contract smooths out the yield from point-in-time yield events\n * and spreads the yield out over a configurable time period. This ensures a\n * continuous per block yield to makes users happy as their next rebase\n * amount is always moving up. Also, this makes historical day to day yields\n * smooth, rather than going from a near zero day, to a large APY day, then\n * back to a near zero day again.\n *\n *\n * Design notes\n * - USDT has a smaller resolution than the number of seconds\n * in a week, which can make per second payouts have a rounding error. However\n * the total effect is not large - cents per day, and this money is\n * not lost, just distributed in the future. While we could use a higher\n * decimal precision for the drip perSecond, we chose simpler code.\n * - By calculating the changing drip rates on collects only, harvests and yield\n * events don't have to call anything on this contract or pay any extra gas.\n * Collect() is already be paying for a single write, since it has to reset\n * the lastCollect time.\n * - By having a collectAndRebase method, and having our external systems call\n * that, the OUSD vault does not need any changes, not even to know the address\n * of the dripper.\n * - A rejected design was to retro-calculate the drip rate on each collect,\n * based on the balance at the time of the collect. While this would have\n * required less state, and would also have made the contract respond more quickly\n * to new income, it would break the predictability that is this contract's entire\n * purpose. If we did this, the amount of fundsAvailable() would make sharp increases\n * when funds were deposited.\n * - When the dripper recalculates the rate, it targets spending the balance over\n * the duration. This means that every time that collect is called, if no\n * new funds have been deposited the duration is being pushed back and the\n * rate decreases. This is expected, and ends up following a smoother but\n * longer curve the more collect() is called without incoming yield.\n *\n */\n\ncontract Dripper is Governable {\n using SafeERC20 for IERC20;\n\n struct Drip {\n uint64 lastCollect; // overflows 262 billion years after the sun dies\n uint192 perSecond; // drip rate per second\n }\n\n address immutable vault; // OUSD vault\n address immutable token; // token to drip out\n uint256 public dripDuration; // in seconds\n Drip public drip; // active drip parameters\n\n constructor(address _vault, address _token) {\n vault = _vault;\n token = _token;\n }\n\n /// @notice How much funds have dripped out already and are currently\n // available to be sent to the vault.\n /// @return The amount that would be sent if a collect was called\n function availableFunds() external view returns (uint256) {\n uint256 balance = IERC20(token).balanceOf(address(this));\n return _availableFunds(balance, drip);\n }\n\n /// @notice Collect all dripped funds and send to vault.\n /// Recalculate new drip rate.\n function collect() external {\n _collect();\n }\n\n /// @notice Collect all dripped funds, send to vault, recalculate new drip\n /// rate, and rebase OUSD.\n function collectAndRebase() external {\n _collect();\n IVault(vault).rebase();\n }\n\n /// @dev Change the drip duration. Governor only.\n /// @param _durationSeconds the number of seconds to drip out the entire\n /// balance over if no collects were called during that time.\n function setDripDuration(uint256 _durationSeconds)\n external\n virtual\n onlyGovernor\n {\n require(_durationSeconds > 0, \"duration must be non-zero\");\n dripDuration = _durationSeconds;\n _collect(); // duration change take immediate effect\n }\n\n /// @dev Transfer out ERC20 tokens held by the contract. Governor only.\n /// @param _asset ERC20 token address\n /// @param _amount amount to transfer\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /// @dev Calculate available funds by taking the lower of either the\n /// currently dripped out funds or the balance available.\n /// Uses passed in parameters to calculate with for gas savings.\n /// @param _balance current balance in contract\n /// @param _drip current drip parameters\n function _availableFunds(uint256 _balance, Drip memory _drip)\n internal\n view\n returns (uint256)\n {\n uint256 elapsed = block.timestamp - _drip.lastCollect;\n uint256 allowed = (elapsed * _drip.perSecond);\n return (allowed > _balance) ? _balance : allowed;\n }\n\n /// @dev Sends the currently dripped funds to be vault, and sets\n /// the new drip rate based on the new balance.\n function _collect() internal virtual {\n // Calculate send\n uint256 balance = IERC20(token).balanceOf(address(this));\n uint256 amountToSend = _availableFunds(balance, drip);\n uint256 remaining = balance - amountToSend;\n // Calculate new drip perSecond\n // Gas savings by setting entire struct at one time\n drip = Drip({\n perSecond: uint192(remaining / dripDuration),\n lastCollect: uint64(block.timestamp)\n });\n // Send funds\n IERC20(token).safeTransfer(vault, amountToSend);\n }\n\n /// @dev Transfer out all ERC20 held by the contract. Governor only.\n /// @param _asset ERC20 token address\n function transferAllToken(address _asset, address _receiver)\n external\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(\n _receiver,\n IERC20(_asset).balanceOf(address(this))\n );\n }\n}\n" + }, + "contracts/harvest/FixedRateDripper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { Dripper } from \"./Dripper.sol\";\n\n/**\n * @title Fixed Rate Dripper\n *\n * Similar to the Dripper, Fixed Rate Dripper drips out yield per second.\n * However the Strategist decides the rate and it doesn't change after\n * a drip.\n *\n */\n\ncontract FixedRateDripper is Dripper {\n using SafeERC20 for IERC20;\n\n event DripRateUpdated(uint192 oldDripRate, uint192 newDripRate);\n\n /**\n * @dev Verifies that the caller is the Governor or Strategist.\n */\n modifier onlyGovernorOrStrategist() {\n require(\n isGovernor() || msg.sender == IVault(vault).strategistAddr(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n constructor(address _vault, address _token) Dripper(_vault, _token) {}\n\n /// @inheritdoc Dripper\n function setDripDuration(uint256) external virtual override {\n // Not used in FixedRateDripper\n revert(\"Drip duration disabled\");\n }\n\n /// @inheritdoc Dripper\n function _collect() internal virtual override {\n // Calculate amount to send\n uint256 balance = IERC20(token).balanceOf(address(this));\n uint256 amountToSend = _availableFunds(balance, drip);\n\n // Update timestamp\n drip.lastCollect = uint64(block.timestamp);\n\n // Send funds\n IERC20(token).safeTransfer(vault, amountToSend);\n }\n\n /**\n * @dev Sets the drip rate. Callable by Strategist or Governor.\n * Can be set to zero to stop dripper.\n * @param _perSecond Rate of WETH to drip per second\n */\n function setDripRate(uint192 _perSecond) external onlyGovernorOrStrategist {\n emit DripRateUpdated(_perSecond, drip.perSecond);\n\n /**\n * Note: It's important to call `_collect` before updating\n * the drip rate especially on a new proxy contract.\n * When `lastCollect` is not set/initialized, the elapsed\n * time would be calculated as `block.number` seconds,\n * resulting in a huge yield, if `collect` isn't called first.\n */\n // Collect at existing rate\n _collect();\n\n // Update rate\n drip.perSecond = _perSecond;\n }\n}\n" + }, + "contracts/harvest/OETHFixedRateDripper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { FixedRateDripper } from \"./FixedRateDripper.sol\";\n\n/**\n * @title OETH FixedRateDripper Contract\n * @author Origin Protocol Inc\n */\ncontract OETHFixedRateDripper is FixedRateDripper {\n constructor(address _vault, address _token)\n FixedRateDripper(_vault, _token)\n {}\n}\n" + }, + "contracts/interfaces/aerodrome/ICLGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\ninterface ICLGauge {\n /// @notice Returns the claimable rewards for a given account and tokenId\n /// @dev Throws if account is not the position owner\n /// @dev pool.updateRewardsGrowthGlobal() needs to be called first, to return the correct claimable rewards\n /// @param account The address of the user\n /// @param tokenId The tokenId of the position\n /// @return The amount of claimable reward\n function earned(address account, uint256 tokenId)\n external\n view\n returns (uint256);\n\n /// @notice Retrieve rewards for all tokens owned by an account\n /// @dev Throws if not called by the voter\n /// @param account The account of the user\n function getReward(address account) external;\n\n /// @notice Retrieve rewards for a tokenId\n /// @dev Throws if not called by the position owner\n /// @param tokenId The tokenId of the position\n function getReward(uint256 tokenId) external;\n\n /// @notice Notifies gauge of gauge rewards.\n /// @param amount Amount of gauge rewards (emissions) to notify. Must be greater than 604_800.\n function notifyRewardAmount(uint256 amount) external;\n\n /// @dev Notifies gauge of gauge rewards without distributing its fees.\n /// Assumes gauge reward tokens is 18 decimals.\n /// If not 18 decimals, rewardRate may have rounding issues.\n /// @param amount Amount of gauge rewards (emissions) to notify. Must be greater than 604_800.\n function notifyRewardWithoutClaim(uint256 amount) external;\n\n /// @notice Used to deposit a CL position into the gauge\n /// @notice Allows the user to receive emissions instead of fees\n /// @param tokenId The tokenId of the position\n function deposit(uint256 tokenId) external;\n\n /// @notice Used to withdraw a CL position from the gauge\n /// @notice Allows the user to receive fees instead of emissions\n /// @notice Outstanding emissions will be collected on withdrawal\n /// @param tokenId The tokenId of the position\n function withdraw(uint256 tokenId) external;\n\n // /// @notice Fetch all tokenIds staked by a given account\n // /// @param depositor The address of the user\n // /// @return The tokenIds of the staked positions\n // function stakedValues(address depositor) external view returns (uint256[] memory);\n\n // /// @notice Fetch a staked tokenId by index\n // /// @param depositor The address of the user\n // /// @param index The index of the staked tokenId\n // /// @return The tokenId of the staked position\n // function stakedByIndex(address depositor, uint256 index) external view returns (uint256);\n\n // /// @notice Check whether a position is staked in the gauge by a certain user\n // /// @param depositor The address of the user\n // /// @param tokenId The tokenId of the position\n // /// @return Whether the position is staked in the gauge\n // function stakedContains(address depositor, uint256 tokenId) external view returns (bool);\n\n // /// @notice The amount of positions staked in the gauge by a certain user\n // /// @param depositor The address of the user\n // /// @return The amount of positions staked in the gauge\n // function stakedLength(address depositor) external view returns (uint256);\n\n function feesVotingReward() external view returns (address);\n}\n" + }, + "contracts/interfaces/aerodrome/ICLPool.sol": { + "content": "pragma solidity >=0.5.0;\n\n/// @title The interface for a CL Pool\n/// @notice A CL pool facilitates swapping and automated market making between any two assets that strictly conform\n/// to the ERC20 specification\n/// @dev The pool interface is broken up into many smaller pieces\ninterface ICLPool {\n function slot0()\n external\n view\n returns (\n uint160 sqrtPriceX96,\n int24 tick,\n uint16 observationIndex,\n uint16 observationCardinality,\n uint16 observationCardinalityNext,\n bool unlocked\n );\n\n /// @notice The first of the two tokens of the pool, sorted by address\n /// @return The token contract address\n function token0() external view returns (address);\n\n /// @notice The second of the two tokens of the pool, sorted by address\n /// @return The token contract address\n function token1() external view returns (address);\n\n function tickSpacing() external view returns (int24);\n\n /// @notice The gauge corresponding to this pool\n /// @return The gauge contract address\n function gauge() external view returns (address);\n\n /// @notice The currently in range liquidity available to the pool\n /// @dev This value has no relationship to the total liquidity across all ticks\n /// @dev This value includes staked liquidity\n function liquidity() external view returns (uint128);\n\n /// @notice Look up information about a specific tick in the pool\n /// @param tick The tick to look up\n /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or\n /// tick upper,\n /// liquidityNet how much liquidity changes when the pool price crosses the tick,\n /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,\n /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,\n /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick\n /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from\n /// the current tick,\n /// secondsOutside the seconds spent on the other side of the tick from the current tick,\n /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise\n /// equal to false.\n /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.\n /// In addition, these values are only relative and must be used only in comparison to previous snapshots for\n /// a specific position.\n function ticks(int24 tick)\n external\n view\n returns (\n uint128 liquidityGross,\n int128 liquidityNet,\n uint256 feeGrowthOutside0X128,\n uint256 feeGrowthOutside1X128,\n int56 tickCumulativeOutside,\n uint160 secondsPerLiquidityOutsideX128,\n uint32 secondsOutside,\n bool initialized\n );\n}\n" + }, + "contracts/interfaces/aerodrome/INonfungiblePositionManager.sol": { + "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.7.5;\npragma abicoder v2;\n\n/// @title Non-fungible token for positions\n/// @notice Wraps CL positions in a non-fungible token interface which allows for them to be transferred\n/// and authorized.\n// slither-disable-start erc20-interface\ninterface INonfungiblePositionManager {\n /**\n * @dev See {IERC721-approve}.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev See {IERC721-getApproved}.\n */\n function getApproved(uint256 tokenId) external returns (address);\n\n /**\n * @dev See {IERC721-ownerOf}.\n */\n function ownerOf(uint256 tokenId) external view returns (address);\n\n /// @notice Returns the position information associated with a given token ID.\n /// @dev Throws if the token ID is not valid.\n /// @param tokenId The ID of the token that represents the position\n /// @return nonce The nonce for permits\n /// @return operator The address that is approved for spending\n /// @return token0 The address of the token0 for a specific pool\n /// @return token1 The address of the token1 for a specific pool\n /// @return tickSpacing The tick spacing associated with the pool\n /// @return tickLower The lower end of the tick range for the position\n /// @return tickUpper The higher end of the tick range for the position\n /// @return liquidity The liquidity of the position\n /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position\n /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position\n /// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation\n /// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation\n function positions(uint256 tokenId)\n external\n view\n returns (\n uint96 nonce,\n address operator,\n address token0,\n address token1,\n int24 tickSpacing,\n int24 tickLower,\n int24 tickUpper,\n uint128 liquidity,\n uint256 feeGrowthInside0LastX128,\n uint256 feeGrowthInside1LastX128,\n uint128 tokensOwed0,\n uint128 tokensOwed1\n );\n\n struct MintParams {\n address token0;\n address token1;\n int24 tickSpacing;\n int24 tickLower;\n int24 tickUpper;\n uint256 amount0Desired;\n uint256 amount1Desired;\n uint256 amount0Min;\n uint256 amount1Min;\n address recipient;\n uint256 deadline;\n uint160 sqrtPriceX96;\n }\n\n /// @notice Creates a new position wrapped in a NFT\n /// @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized\n /// a method does not exist, i.e. the pool is assumed to be initialized.\n /// @param params The params necessary to mint a position, encoded as `MintParams` in calldata\n /// @return tokenId The ID of the token that represents the minted position\n /// @return liquidity The amount of liquidity for this position\n /// @return amount0 The amount of token0\n /// @return amount1 The amount of token1\n function mint(MintParams calldata params)\n external\n payable\n returns (\n uint256 tokenId,\n uint128 liquidity,\n uint256 amount0,\n uint256 amount1\n );\n\n struct IncreaseLiquidityParams {\n uint256 tokenId;\n uint256 amount0Desired;\n uint256 amount1Desired;\n uint256 amount0Min;\n uint256 amount1Min;\n uint256 deadline;\n }\n\n /// @notice Increases the amount of liquidity in a position, with tokens paid by the `msg.sender`\n /// @param params tokenId The ID of the token for which liquidity is being increased,\n /// amount0Desired The desired amount of token0 to be spent,\n /// amount1Desired The desired amount of token1 to be spent,\n /// amount0Min The minimum amount of token0 to spend, which serves as a slippage check,\n /// amount1Min The minimum amount of token1 to spend, which serves as a slippage check,\n /// deadline The time by which the transaction must be included to effect the change\n /// @return liquidity The new liquidity amount as a result of the increase\n /// @return amount0 The amount of token0 to acheive resulting liquidity\n /// @return amount1 The amount of token1 to acheive resulting liquidity\n function increaseLiquidity(IncreaseLiquidityParams calldata params)\n external\n payable\n returns (\n uint128 liquidity,\n uint256 amount0,\n uint256 amount1\n );\n\n struct DecreaseLiquidityParams {\n uint256 tokenId;\n uint128 liquidity;\n uint256 amount0Min;\n uint256 amount1Min;\n uint256 deadline;\n }\n\n /// @notice Decreases the amount of liquidity in a position and accounts it to the position\n /// @param params tokenId The ID of the token for which liquidity is being decreased,\n /// amount The amount by which liquidity will be decreased,\n /// amount0Min The minimum amount of token0 that should be accounted for the burned liquidity,\n /// amount1Min The minimum amount of token1 that should be accounted for the burned liquidity,\n /// deadline The time by which the transaction must be included to effect the change\n /// @return amount0 The amount of token0 accounted to the position's tokens owed\n /// @return amount1 The amount of token1 accounted to the position's tokens owed\n /// @dev The use of this function can cause a loss to users of the NonfungiblePositionManager\n /// @dev for tokens that have very high decimals.\n /// @dev The amount of tokens necessary for the loss is: 3.4028237e+38.\n /// @dev This is equivalent to 1e20 value with 18 decimals.\n function decreaseLiquidity(DecreaseLiquidityParams calldata params)\n external\n payable\n returns (uint256 amount0, uint256 amount1);\n\n struct CollectParams {\n uint256 tokenId;\n address recipient;\n uint128 amount0Max;\n uint128 amount1Max;\n }\n\n /// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient\n /// @notice Used to update staked positions before deposit and withdraw\n /// @param params tokenId The ID of the NFT for which tokens are being collected,\n /// recipient The account that should receive the tokens,\n /// amount0Max The maximum amount of token0 to collect,\n /// amount1Max The maximum amount of token1 to collect\n /// @return amount0 The amount of fees collected in token0\n /// @return amount1 The amount of fees collected in token1\n function collect(CollectParams calldata params)\n external\n payable\n returns (uint256 amount0, uint256 amount1);\n\n /// @notice Burns a token ID, which deletes it from the NFT contract. The token must have 0 liquidity and all tokens\n /// must be collected first.\n /// @param tokenId The ID of the token that is being burned\n function burn(uint256 tokenId) external payable;\n\n /// @notice Sets a new Token Descriptor\n /// @param _tokenDescriptor Address of the new Token Descriptor to be chosen\n function setTokenDescriptor(address _tokenDescriptor) external;\n\n /// @notice Sets a new Owner address\n /// @param _owner Address of the new Owner to be chosen\n function setOwner(address _owner) external;\n}\n// slither-disable-end erc20-interface\n" + }, + "contracts/interfaces/aerodrome/ISugarHelper.sol": { + "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\npragma abicoder v2;\n\nimport { INonfungiblePositionManager } from \"./INonfungiblePositionManager.sol\";\n\ninterface ISugarHelper {\n struct PopulatedTick {\n int24 tick;\n uint160 sqrtRatioX96;\n int128 liquidityNet;\n uint128 liquidityGross;\n }\n\n ///\n /// Wrappers for LiquidityAmounts\n ///\n\n function getAmountsForLiquidity(\n uint160 sqrtRatioX96,\n uint160 sqrtRatioAX96,\n uint160 sqrtRatioBX96,\n uint128 liquidity\n ) external pure returns (uint256 amount0, uint256 amount1);\n\n function getLiquidityForAmounts(\n uint256 amount0,\n uint256 amount1,\n uint160 sqrtRatioX96,\n uint160 sqrtRatioAX96,\n uint160 sqrtRatioBX96\n ) external pure returns (uint128 liquidity);\n\n /// @notice Computes the amount of token0 for a given amount of token1 and price range\n /// @param amount1 Amount of token1 to estimate liquidity\n /// @param pool Address of the pool to be used\n /// @param sqrtRatioX96 A sqrt price representing the current pool prices\n /// @param tickLow Lower tick boundary\n /// @param tickLow Upper tick boundary\n /// @dev If the given pool address is not the zero address, will fetch `sqrtRatioX96` from pool\n /// @return amount0 Estimated amount of token0\n function estimateAmount0(\n uint256 amount1,\n address pool,\n uint160 sqrtRatioX96,\n int24 tickLow,\n int24 tickHigh\n ) external view returns (uint256 amount0);\n\n /// @notice Computes the amount of token1 for a given amount of token0 and price range\n /// @param amount0 Amount of token0 to estimate liquidity\n /// @param pool Address of the pool to be used\n /// @param sqrtRatioX96 A sqrt price representing the current pool prices\n /// @param tickLow Lower tick boundary\n /// @param tickLow Upper tick boundary\n /// @dev If the given pool address is not the zero address, will fetch `sqrtRatioX96` from pool\n /// @return amount1 Estimated amount of token1\n function estimateAmount1(\n uint256 amount0,\n address pool,\n uint160 sqrtRatioX96,\n int24 tickLow,\n int24 tickHigh\n ) external view returns (uint256 amount1);\n\n ///\n /// Wrappers for PositionValue\n ///\n\n function principal(\n INonfungiblePositionManager positionManager,\n uint256 tokenId,\n uint160 sqrtRatioX96\n ) external view returns (uint256 amount0, uint256 amount1);\n\n function fees(INonfungiblePositionManager positionManager, uint256 tokenId)\n external\n view\n returns (uint256 amount0, uint256 amount1);\n\n ///\n /// Wrappers for TickMath\n ///\n\n function getSqrtRatioAtTick(int24 tick)\n external\n pure\n returns (uint160 sqrtRatioX96);\n\n function getTickAtSqrtRatio(uint160 sqrtRatioX96)\n external\n pure\n returns (int24 tick);\n\n /// @notice Fetches Tick Data for all populated Ticks in given bitmaps\n /// @param pool Address of the pool from which to fetch data\n /// @param startTick Tick from which the first bitmap will be fetched\n /// @dev The number of bitmaps fetched by this function should always be `MAX_BITMAPS`,\n /// unless there are less than `MAX_BITMAPS` left to iterate through\n /// @return populatedTicks Array of all Populated Ticks in the provided bitmaps\n function getPopulatedTicks(address pool, int24 startTick)\n external\n view\n returns (PopulatedTick[] memory populatedTicks);\n}\n" + }, + "contracts/interfaces/aerodrome/ISwapRouter.sol": { + "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.7.5;\npragma abicoder v2;\n\n/// @title Router token swapping functionality\n/// @notice Functions for swapping tokens via CL\ninterface ISwapRouter {\n struct ExactInputSingleParams {\n address tokenIn;\n address tokenOut;\n int24 tickSpacing;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n uint160 sqrtPriceLimitX96;\n }\n\n /// @notice Swaps `amountIn` of one token for as much as possible of another token\n /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata\n /// @return amountOut The amount of the received token\n function exactInputSingle(ExactInputSingleParams calldata params)\n external\n payable\n returns (uint256 amountOut);\n\n struct ExactInputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n }\n\n /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path\n /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata\n /// @return amountOut The amount of the received token\n function exactInput(ExactInputParams calldata params)\n external\n payable\n returns (uint256 amountOut);\n\n struct ExactOutputSingleParams {\n address tokenIn;\n address tokenOut;\n int24 tickSpacing;\n address recipient;\n uint256 deadline;\n uint256 amountOut;\n uint256 amountInMaximum;\n uint160 sqrtPriceLimitX96;\n }\n\n /// @notice Swaps as little as possible of one token for `amountOut` of another token\n /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata\n /// @return amountIn The amount of the input token\n function exactOutputSingle(ExactOutputSingleParams calldata params)\n external\n payable\n returns (uint256 amountIn);\n\n struct ExactOutputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountOut;\n uint256 amountInMaximum;\n }\n\n /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)\n /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata\n /// @return amountIn The amount of the input token\n function exactOutput(ExactOutputParams calldata params)\n external\n payable\n returns (uint256 amountIn);\n}\n" + }, + "contracts/interfaces/algebra/IAlgebraGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IGauge {\n function owner() external view returns (address);\n\n function TOKEN() external view returns (address);\n\n function DISTRIBUTION() external view returns (address);\n\n function balanceOf(address account) external view returns (uint256);\n\n function claimFees() external returns (uint256 claimed0, uint256 claimed1);\n\n function deposit(uint256 amount) external;\n\n function depositAll() external;\n\n function earned(address account) external view returns (uint256);\n\n function getReward() external;\n\n function getReward(address _user) external;\n\n function isForPair() external view returns (bool);\n\n function lastTimeRewardApplicable() external view returns (uint256);\n\n function lastUpdateTime() external view returns (uint256);\n\n function notifyRewardAmount(address token, uint256 reward) external;\n\n function periodFinish() external view returns (uint256);\n\n function rewardForDuration() external view returns (uint256);\n\n function rewardPerToken() external view returns (uint256);\n\n function rewardPerTokenStored() external view returns (uint256);\n\n function rewardRate() external view returns (uint256);\n\n function rewardToken() external view returns (address);\n\n function rewards(address) external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function userRewardPerTokenPaid(address) external view returns (uint256);\n\n function withdraw(uint256 amount) external;\n\n function withdrawAll() external;\n\n function withdrawAllAndHarvest() external;\n\n function withdrawExcess(address token, uint256 amount) external;\n\n function emergency() external returns (bool);\n\n function emergencyWithdraw() external;\n\n function activateEmergencyMode() external;\n\n function stopEmergencyMode() external;\n}\n" + }, + "contracts/interfaces/algebra/IAlgebraPair.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IPair {\n event Approval(address indexed src, address indexed guy, uint256 wad);\n event Transfer(address indexed src, address indexed dst, uint256 wad);\n\n event Mint(address indexed sender, uint256 amount0, uint256 amount1);\n event Burn(\n address indexed sender,\n uint256 amount0,\n uint256 amount1,\n address indexed to\n );\n event Swap(\n address indexed sender,\n uint256 amount0In,\n uint256 amount1In,\n uint256 amount0Out,\n uint256 amount1Out,\n address indexed to\n );\n event Claim(\n address indexed sender,\n address indexed recipient,\n uint256 amount0,\n uint256 amount1\n );\n\n function metadata()\n external\n view\n returns (\n uint256 dec0,\n uint256 dec1,\n uint256 r0,\n uint256 r1,\n bool st,\n address t0,\n address t1\n );\n\n function claimFees() external returns (uint256, uint256);\n\n function tokens() external view returns (address, address);\n\n function token0() external view returns (address);\n\n function token1() external view returns (address);\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n function swap(\n uint256 amount0Out,\n uint256 amount1Out,\n address to,\n bytes calldata data\n ) external;\n\n function burn(address to)\n external\n returns (uint256 amount0, uint256 amount1);\n\n function mint(address to) external returns (uint256 liquidity);\n\n function getReserves()\n external\n view\n returns (\n uint256 _reserve0,\n uint256 _reserve1,\n uint256 _blockTimestampLast\n );\n\n function getAmountOut(uint256, address) external view returns (uint256);\n\n // ERC20 methods\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address) external view returns (uint256);\n\n function transfer(address recipient, uint256 amount)\n external\n returns (bool);\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n function allowance(address owner, address spender)\n external\n view\n returns (uint256);\n\n function approve(address spender, uint256 value) external returns (bool);\n\n function claimable0(address _user) external view returns (uint256);\n\n function claimable1(address _user) external view returns (uint256);\n\n function isStable() external view returns (bool);\n\n function skim(address to) external;\n\n function sync() external;\n}\n" + }, + "contracts/interfaces/balancer/IBalancerVault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\n\ninterface IBalancerVault {\n enum WeightedPoolJoinKind {\n INIT,\n EXACT_TOKENS_IN_FOR_BPT_OUT,\n TOKEN_IN_FOR_EXACT_BPT_OUT,\n ALL_TOKENS_IN_FOR_EXACT_BPT_OUT,\n ADD_TOKEN\n }\n\n enum WeightedPoolExitKind {\n EXACT_BPT_IN_FOR_ONE_TOKEN_OUT,\n EXACT_BPT_IN_FOR_TOKENS_OUT,\n BPT_IN_FOR_EXACT_TOKENS_OUT,\n REMOVE_TOKEN\n }\n\n /**\n * @dev Called by users to join a Pool, which transfers tokens from `sender` into the Pool's balance. This will\n * trigger custom Pool behavior, which will typically grant something in return to `recipient` - often tokenized\n * Pool shares.\n *\n * If the caller is not `sender`, it must be an authorized relayer for them.\n *\n * The `assets` and `maxAmountsIn` arrays must have the same length, and each entry indicates the maximum amount\n * to send for each asset. The amounts to send are decided by the Pool and not the Vault: it just enforces\n * these maximums.\n *\n * If joining a Pool that holds WETH, it is possible to send ETH directly: the Vault will do the wrapping. To enable\n * this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead of the\n * WETH address. Note that it is not possible to combine ETH and WETH in the same join. Any excess ETH will be sent\n * back to the caller (not the sender, which is important for relayers).\n *\n * `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when\n * interacting with Pools that register and deregister tokens frequently. If sending ETH however, the array must be\n * sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the final\n * `assets` array might not be sorted. Pools with no registered tokens cannot be joined.\n *\n * If `fromInternalBalance` is true, the caller's Internal Balance will be preferred: ERC20 transfers will only\n * be made for the difference between the requested amount and Internal Balance (if any). Note that ETH cannot be\n * withdrawn from Internal Balance: attempting to do so will trigger a revert.\n *\n * This causes the Vault to call the `IBasePool.onJoinPool` hook on the Pool's contract, where Pools implement\n * their own custom logic. This typically requires additional information from the user (such as the expected number\n * of Pool shares). This can be encoded in the `userData` argument, which is ignored by the Vault and passed\n * directly to the Pool's contract, as is `recipient`.\n *\n * Emits a `PoolBalanceChanged` event.\n */\n function joinPool(\n bytes32 poolId,\n address sender,\n address recipient,\n JoinPoolRequest memory request\n ) external payable;\n\n struct JoinPoolRequest {\n address[] assets;\n uint256[] maxAmountsIn;\n bytes userData;\n bool fromInternalBalance;\n }\n\n /**\n * @dev Called by users to exit a Pool, which transfers tokens from the Pool's balance to `recipient`. This will\n * trigger custom Pool behavior, which will typically ask for something in return from `sender` - often tokenized\n * Pool shares. The amount of tokens that can be withdrawn is limited by the Pool's `cash` balance (see\n * `getPoolTokenInfo`).\n *\n * If the caller is not `sender`, it must be an authorized relayer for them.\n *\n * The `tokens` and `minAmountsOut` arrays must have the same length, and each entry in these indicates the minimum\n * token amount to receive for each token contract. The amounts to send are decided by the Pool and not the Vault:\n * it just enforces these minimums.\n *\n * If exiting a Pool that holds WETH, it is possible to receive ETH directly: the Vault will do the unwrapping. To\n * enable this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead\n * of the WETH address. Note that it is not possible to combine ETH and WETH in the same exit.\n *\n * `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when\n * interacting with Pools that register and deregister tokens frequently. If receiving ETH however, the array must\n * be sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the\n * final `assets` array might not be sorted. Pools with no registered tokens cannot be exited.\n *\n * If `toInternalBalance` is true, the tokens will be deposited to `recipient`'s Internal Balance. Otherwise,\n * an ERC20 transfer will be performed. Note that ETH cannot be deposited to Internal Balance: attempting to\n * do so will trigger a revert.\n *\n * `minAmountsOut` is the minimum amount of tokens the user expects to get out of the Pool, for each token in the\n * `tokens` array. This array must match the Pool's registered tokens.\n *\n * This causes the Vault to call the `IBasePool.onExitPool` hook on the Pool's contract, where Pools implement\n * their own custom logic. This typically requires additional information from the user (such as the expected number\n * of Pool shares to return). This can be encoded in the `userData` argument, which is ignored by the Vault and\n * passed directly to the Pool's contract.\n *\n * Emits a `PoolBalanceChanged` event.\n */\n function exitPool(\n bytes32 poolId,\n address sender,\n address payable recipient,\n ExitPoolRequest memory request\n ) external;\n\n struct ExitPoolRequest {\n address[] assets;\n uint256[] minAmountsOut;\n bytes userData;\n bool toInternalBalance;\n }\n\n /**\n * @dev Returns a Pool's registered tokens, the total balance for each, and the latest block when *any* of\n * the tokens' `balances` changed.\n *\n * The order of the `tokens` array is the same order that will be used in `joinPool`, `exitPool`, as well as in all\n * Pool hooks (where applicable). Calls to `registerTokens` and `deregisterTokens` may change this order.\n *\n * If a Pool only registers tokens once, and these are sorted in ascending order, they will be stored in the same\n * order as passed to `registerTokens`.\n *\n * Total balances include both tokens held by the Vault and those withdrawn by the Pool's Asset Managers. These are\n * the amounts used by joins, exits and swaps. For a detailed breakdown of token balances, use `getPoolTokenInfo`\n * instead.\n */\n function getPoolTokens(bytes32 poolId)\n external\n view\n returns (\n IERC20[] memory tokens,\n uint256[] memory balances,\n uint256 lastChangeBlock\n );\n\n /**\n * @dev Performs a set of user balance operations, which involve Internal Balance (deposit, withdraw or transfer)\n * and plain ERC20 transfers using the Vault's allowance. This last feature is particularly useful for relayers, as\n * it lets integrators reuse a user's Vault allowance.\n *\n * For each operation, if the caller is not `sender`, it must be an authorized relayer for them.\n */\n function manageUserBalance(UserBalanceOp[] memory ops) external payable;\n\n struct UserBalanceOp {\n UserBalanceOpKind kind;\n address asset;\n uint256 amount;\n address sender;\n address payable recipient;\n }\n\n enum UserBalanceOpKind {\n DEPOSIT_INTERNAL,\n WITHDRAW_INTERNAL,\n TRANSFER_INTERNAL,\n TRANSFER_EXTERNAL\n }\n\n enum SwapKind {\n GIVEN_IN,\n GIVEN_OUT\n }\n\n struct SingleSwap {\n bytes32 poolId;\n SwapKind kind;\n address assetIn;\n address assetOut;\n uint256 amount;\n bytes userData;\n }\n\n struct FundManagement {\n address sender;\n bool fromInternalBalance;\n address payable recipient;\n bool toInternalBalance;\n }\n\n function swap(\n SingleSwap calldata singleSwap,\n FundManagement calldata funds,\n uint256 limit,\n uint256 deadline\n ) external returns (uint256 amountCalculated);\n\n function getPoolTokenInfo(bytes32 poolId, address token)\n external\n view\n returns (\n uint256 cash,\n uint256 managed,\n uint256 lastChangeBlock,\n address assetManager\n );\n}\n" + }, + "contracts/interfaces/cctp/ICCTP.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface ICCTPTokenMessenger {\n function depositForBurn(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller,\n uint256 maxFee,\n uint32 minFinalityThreshold\n ) external;\n\n function depositForBurnWithHook(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller,\n uint256 maxFee,\n uint32 minFinalityThreshold,\n bytes memory hookData\n ) external;\n\n function getMinFeeAmount(uint256 amount) external view returns (uint256);\n}\n\ninterface ICCTPMessageTransmitter {\n function sendMessage(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n uint32 minFinalityThreshold,\n bytes memory messageBody\n ) external;\n\n function receiveMessage(bytes calldata message, bytes calldata attestation)\n external\n returns (bool);\n}\n\ninterface IMessageHandlerV2 {\n /**\n * @notice Handles an incoming finalized message from an IReceiverV2\n * @dev Finalized messages have finality threshold values greater than or equal to 2000\n * @param sourceDomain The source domain of the message\n * @param sender The sender of the message\n * @param finalityThresholdExecuted the finality threshold at which the message was attested to\n * @param messageBody The raw bytes of the message body\n * @return success True, if successful; false, if not.\n */\n function handleReceiveFinalizedMessage(\n uint32 sourceDomain,\n bytes32 sender,\n uint32 finalityThresholdExecuted,\n bytes calldata messageBody\n ) external returns (bool);\n\n /**\n * @notice Handles an incoming unfinalized message from an IReceiverV2\n * @dev Unfinalized messages have finality threshold values less than 2000\n * @param sourceDomain The source domain of the message\n * @param sender The sender of the message\n * @param finalityThresholdExecuted The finality threshold at which the message was attested to\n * @param messageBody The raw bytes of the message body\n * @return success True, if successful; false, if not.\n */\n function handleReceiveUnfinalizedMessage(\n uint32 sourceDomain,\n bytes32 sender,\n uint32 finalityThresholdExecuted,\n bytes calldata messageBody\n ) external returns (bool);\n}\n" + }, + "contracts/interfaces/chainlink/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n}\n" + }, + "contracts/interfaces/hydrex/IHydrexGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title IHydrexGauge\n * @notice Minimal interface exposing the staked-token getter used by the\n * Hydrex GaugeV2 (>= v2.5). Hydrex renamed `TOKEN()` to `stakeToken()`\n * in v2.5; the rest of the gauge surface (deposit / withdraw /\n * getReward / emergency / emergencyWithdraw / balanceOf) is\n * ABI-compatible with `IAlgebraGauge` and is invoked through that\n * interface elsewhere in the strategy.\n */\ninterface IHydrexGauge {\n function stakeToken() external view returns (address);\n}\n" + }, + "contracts/interfaces/IBasicToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IBasicToken {\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\n}\n" + }, + "contracts/interfaces/IBeaconProofs.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IBeaconProofs {\n function verifyValidator(\n bytes32 beaconBlockRoot,\n bytes32 pubKeyHash,\n bytes calldata validatorPubKeyProof,\n uint40 validatorIndex,\n bytes32 withdrawalCredentials\n ) external view;\n\n function verifyValidatorWithdrawable(\n bytes32 beaconBlockRoot,\n uint40 validatorIndex,\n uint64 withdrawableEpoch,\n bytes calldata withdrawableEpochProof\n ) external view;\n\n function verifyBalancesContainer(\n bytes32 beaconBlockRoot,\n bytes32 balancesContainerLeaf,\n bytes calldata balancesContainerProof\n ) external view;\n\n function verifyValidatorBalance(\n bytes32 balancesContainerRoot,\n bytes32 validatorBalanceLeaf,\n bytes calldata balanceProof,\n uint40 validatorIndex\n ) external view returns (uint256 validatorBalance);\n\n function verifyPendingDepositsContainer(\n bytes32 beaconBlockRoot,\n bytes32 pendingDepositsContainerRoot,\n bytes calldata proof\n ) external view;\n\n function verifyPendingDeposit(\n bytes32 pendingDepositsContainerRoot,\n bytes32 pendingDepositRoot,\n bytes calldata proof,\n uint32 pendingDepositIndex\n ) external view;\n\n function verifyFirstPendingDeposit(\n bytes32 beaconBlockRoot,\n uint64 slot,\n bytes calldata firstPendingDepositSlotProof\n ) external view returns (bool isEmptyDepositQueue);\n\n function merkleizePendingDeposit(\n bytes32 pubKeyHash,\n bytes calldata withdrawalCredentials,\n uint64 amountGwei,\n bytes calldata signature,\n uint64 slot\n ) external pure returns (bytes32 root);\n\n function merkleizeSignature(bytes calldata signature)\n external\n pure\n returns (bytes32 root);\n}\n" + }, + "contracts/interfaces/IChildLiquidityGaugeFactory.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface IChildLiquidityGaugeFactory {\n event DeployedGauge(\n address indexed _implementation,\n address indexed _lp_token,\n address indexed _deployer,\n bytes32 _salt,\n address _gauge\n );\n event Minted(\n address indexed _user,\n address indexed _gauge,\n uint256 _new_total\n );\n event TransferOwnership(address _old_owner, address _new_owner);\n event UpdateCallProxy(address _old_call_proxy, address _new_call_proxy);\n event UpdateImplementation(\n address _old_implementation,\n address _new_implementation\n );\n event UpdateManager(address _manager);\n event UpdateMirrored(address indexed _gauge, bool _mirrored);\n event UpdateRoot(address _factory, address _implementation);\n event UpdateVotingEscrow(\n address _old_voting_escrow,\n address _new_voting_escrow\n );\n\n function accept_transfer_ownership() external;\n\n function call_proxy() external view returns (address);\n\n function commit_transfer_ownership(address _future_owner) external;\n\n function crv() external view returns (address);\n\n function deploy_gauge(address _lp_token, bytes32 _salt)\n external\n returns (address);\n\n function deploy_gauge(\n address _lp_token,\n bytes32 _salt,\n address _manager\n ) external returns (address);\n\n function future_owner() external view returns (address);\n\n function gauge_data(address arg0) external view returns (uint256);\n\n function get_gauge(uint256 arg0) external view returns (address);\n\n function get_gauge_count() external view returns (uint256);\n\n function get_gauge_from_lp_token(address arg0)\n external\n view\n returns (address);\n\n function get_implementation() external view returns (address);\n\n function is_mirrored(address _gauge) external view returns (bool);\n\n function is_valid_gauge(address _gauge) external view returns (bool);\n\n function last_request(address _gauge) external view returns (uint256);\n\n function manager() external view returns (address);\n\n function mint(address _gauge) external;\n\n function mint_many(address[32] memory _gauges) external;\n\n function minted(address arg0, address arg1) external view returns (uint256);\n\n function owner() external view returns (address);\n\n function root_factory() external view returns (address);\n\n function root_implementation() external view returns (address);\n\n function set_call_proxy(address _new_call_proxy) external;\n\n function set_crv(address _crv) external;\n\n function set_implementation(address _implementation) external;\n\n function set_manager(address _new_manager) external;\n\n function set_mirrored(address _gauge, bool _mirrored) external;\n\n function set_root(address _factory, address _implementation) external;\n\n function set_voting_escrow(address _voting_escrow) external;\n\n function version() external view returns (string memory);\n\n function voting_escrow() external view returns (address);\n}\n" + }, + "contracts/interfaces/ICurveLiquidityGaugeV6.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface ICurveLiquidityGaugeV6 {\n event ApplyOwnership(address admin);\n event Approval(\n address indexed _owner,\n address indexed _spender,\n uint256 _value\n );\n event CommitOwnership(address admin);\n event Deposit(address indexed provider, uint256 value);\n event SetGaugeManager(address _gauge_manager);\n event Transfer(address indexed _from, address indexed _to, uint256 _value);\n event UpdateLiquidityLimit(\n address indexed user,\n uint256 original_balance,\n uint256 original_supply,\n uint256 working_balance,\n uint256 working_supply\n );\n event Withdraw(address indexed provider, uint256 value);\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n function add_reward(address _reward_token, address _distributor) external;\n\n function allowance(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function balanceOf(address arg0) external view returns (uint256);\n\n function claim_rewards() external;\n\n function claim_rewards(address _addr) external;\n\n function claim_rewards(address _addr, address _receiver) external;\n\n function claimable_reward(address _user, address _reward_token)\n external\n view\n returns (uint256);\n\n function claimable_tokens(address addr) external returns (uint256);\n\n function claimed_reward(address _addr, address _token)\n external\n view\n returns (uint256);\n\n function decimals() external view returns (uint256);\n\n function decreaseAllowance(address _spender, uint256 _subtracted_value)\n external\n returns (bool);\n\n function deposit(uint256 _value) external;\n\n function deposit(uint256 _value, address _addr) external;\n\n function deposit(\n uint256 _value,\n address _addr,\n bool _claim_rewards\n ) external;\n\n function deposit_reward_token(address _reward_token, uint256 _amount)\n external;\n\n function deposit_reward_token(\n address _reward_token,\n uint256 _amount,\n uint256 _epoch\n ) external;\n\n function factory() external view returns (address);\n\n function future_epoch_time() external view returns (uint256);\n\n function increaseAllowance(address _spender, uint256 _added_value)\n external\n returns (bool);\n\n function inflation_rate() external view returns (uint256);\n\n function integrate_checkpoint() external view returns (uint256);\n\n function integrate_checkpoint_of(address arg0)\n external\n view\n returns (uint256);\n\n function integrate_fraction(address arg0) external view returns (uint256);\n\n function integrate_inv_supply(uint256 arg0) external view returns (uint256);\n\n function integrate_inv_supply_of(address arg0)\n external\n view\n returns (uint256);\n\n function is_killed() external view returns (bool);\n\n function kick(address addr) external;\n\n function lp_token() external view returns (address);\n\n function manager() external view returns (address);\n\n function name() external view returns (string memory);\n\n function nonces(address arg0) external view returns (uint256);\n\n function period() external view returns (int128);\n\n function period_timestamp(uint256 arg0) external view returns (uint256);\n\n function permit(\n address _owner,\n address _spender,\n uint256 _value,\n uint256 _deadline,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) external returns (bool);\n\n function reward_count() external view returns (uint256);\n\n function reward_integral_for(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function reward_tokens(uint256 arg0) external view returns (address);\n\n function rewards_receiver(address arg0) external view returns (address);\n\n function salt() external view returns (bytes32);\n\n function set_gauge_manager(address _gauge_manager) external;\n\n function set_killed(bool _is_killed) external;\n\n function set_reward_distributor(address _reward_token, address _distributor)\n external;\n\n function set_rewards_receiver(address _receiver) external;\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function user_checkpoint(address addr) external returns (bool);\n\n function version() external view returns (string memory);\n\n function withdraw(uint256 _value) external;\n\n function withdraw(uint256 _value, bool _claim_rewards) external;\n\n function working_balances(address arg0) external view returns (uint256);\n\n function working_supply() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/ICurveMinter.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface ICurveMinter {\n event Minted(address indexed recipient, address gauge, uint256 minted);\n\n function allowed_to_mint_for(address arg0, address arg1)\n external\n view\n returns (bool);\n\n function controller() external view returns (address);\n\n function mint(address gauge_addr) external;\n\n function mint_for(address gauge_addr, address _for) external;\n\n function mint_many(address[8] memory gauge_addrs) external;\n\n function minted(address arg0, address arg1) external view returns (uint256);\n\n function toggle_approve_mint(address minting_user) external;\n\n function token() external view returns (address);\n}\n" + }, + "contracts/interfaces/ICurveStableSwapNG.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface ICurveStableSwapNG {\n event AddLiquidity(\n address indexed provider,\n uint256[] token_amounts,\n uint256[] fees,\n uint256 invariant,\n uint256 token_supply\n );\n event ApplyNewFee(uint256 fee, uint256 offpeg_fee_multiplier);\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n event RampA(\n uint256 old_A,\n uint256 new_A,\n uint256 initial_time,\n uint256 future_time\n );\n event RemoveLiquidity(\n address indexed provider,\n uint256[] token_amounts,\n uint256[] fees,\n uint256 token_supply\n );\n event RemoveLiquidityImbalance(\n address indexed provider,\n uint256[] token_amounts,\n uint256[] fees,\n uint256 invariant,\n uint256 token_supply\n );\n event RemoveLiquidityOne(\n address indexed provider,\n int128 token_id,\n uint256 token_amount,\n uint256 coin_amount,\n uint256 token_supply\n );\n event SetNewMATime(uint256 ma_exp_time, uint256 D_ma_time);\n event StopRampA(uint256 A, uint256 t);\n event TokenExchange(\n address indexed buyer,\n int128 sold_id,\n uint256 tokens_sold,\n int128 bought_id,\n uint256 tokens_bought\n );\n event TokenExchangeUnderlying(\n address indexed buyer,\n int128 sold_id,\n uint256 tokens_sold,\n int128 bought_id,\n uint256 tokens_bought\n );\n event Transfer(\n address indexed sender,\n address indexed receiver,\n uint256 value\n );\n\n function A() external view returns (uint256);\n\n function A_precise() external view returns (uint256);\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n function D_ma_time() external view returns (uint256);\n\n function D_oracle() external view returns (uint256);\n\n function N_COINS() external view returns (uint256);\n\n function add_liquidity(uint256[] memory _amounts, uint256 _min_mint_amount)\n external\n returns (uint256);\n\n function add_liquidity(\n uint256[] memory _amounts,\n uint256 _min_mint_amount,\n address _receiver\n ) external returns (uint256);\n\n function admin_balances(uint256 arg0) external view returns (uint256);\n\n function admin_fee() external view returns (uint256);\n\n function allowance(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function balanceOf(address arg0) external view returns (uint256);\n\n function balances(uint256 i) external view returns (uint256);\n\n function calc_token_amount(uint256[] memory _amounts, bool _is_deposit)\n external\n view\n returns (uint256);\n\n function calc_withdraw_one_coin(uint256 _burn_amount, int128 i)\n external\n view\n returns (uint256);\n\n function coins(uint256 arg0) external view returns (address);\n\n function decimals() external view returns (uint8);\n\n function dynamic_fee(int128 i, int128 j) external view returns (uint256);\n\n function ema_price(uint256 i) external view returns (uint256);\n\n function exchange(\n int128 i,\n int128 j,\n uint256 _dx,\n uint256 _min_dy\n ) external returns (uint256);\n\n function exchange(\n int128 i,\n int128 j,\n uint256 _dx,\n uint256 _min_dy,\n address _receiver\n ) external returns (uint256);\n\n function exchange_received(\n int128 i,\n int128 j,\n uint256 _dx,\n uint256 _min_dy\n ) external returns (uint256);\n\n function exchange_received(\n int128 i,\n int128 j,\n uint256 _dx,\n uint256 _min_dy,\n address _receiver\n ) external returns (uint256);\n\n function fee() external view returns (uint256);\n\n function future_A() external view returns (uint256);\n\n function future_A_time() external view returns (uint256);\n\n function get_balances() external view returns (uint256[] memory);\n\n function get_dx(\n int128 i,\n int128 j,\n uint256 dy\n ) external view returns (uint256);\n\n function get_dy(\n int128 i,\n int128 j,\n uint256 dx\n ) external view returns (uint256);\n\n function get_p(uint256 i) external view returns (uint256);\n\n function get_virtual_price() external view returns (uint256);\n\n function initial_A() external view returns (uint256);\n\n function initial_A_time() external view returns (uint256);\n\n function last_price(uint256 i) external view returns (uint256);\n\n function ma_exp_time() external view returns (uint256);\n\n function ma_last_time() external view returns (uint256);\n\n function name() external view returns (string memory);\n\n function nonces(address arg0) external view returns (uint256);\n\n function offpeg_fee_multiplier() external view returns (uint256);\n\n function permit(\n address _owner,\n address _spender,\n uint256 _value,\n uint256 _deadline,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) external returns (bool);\n\n function price_oracle(uint256 i) external view returns (uint256);\n\n function ramp_A(uint256 _future_A, uint256 _future_time) external;\n\n function remove_liquidity(\n uint256 _burn_amount,\n uint256[] memory _min_amounts\n ) external returns (uint256[] memory);\n\n function remove_liquidity(\n uint256 _burn_amount,\n uint256[] memory _min_amounts,\n address _receiver\n ) external returns (uint256[] memory);\n\n function remove_liquidity(\n uint256 _burn_amount,\n uint256[] memory _min_amounts,\n address _receiver,\n bool _claim_admin_fees\n ) external returns (uint256[] memory);\n\n function remove_liquidity_imbalance(\n uint256[] memory _amounts,\n uint256 _max_burn_amount\n ) external returns (uint256);\n\n function remove_liquidity_imbalance(\n uint256[] memory _amounts,\n uint256 _max_burn_amount,\n address _receiver\n ) external returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _burn_amount,\n int128 i,\n uint256 _min_received\n ) external returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _burn_amount,\n int128 i,\n uint256 _min_received,\n address _receiver\n ) external returns (uint256);\n\n function salt() external view returns (bytes32);\n\n function set_ma_exp_time(uint256 _ma_exp_time, uint256 _D_ma_time) external;\n\n function set_new_fee(uint256 _new_fee, uint256 _new_offpeg_fee_multiplier)\n external;\n\n function stop_ramp_A() external;\n\n function stored_rates() external view returns (uint256[] memory);\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function version() external view returns (string memory);\n\n function withdraw_admin_fees() external;\n}\n" + }, + "contracts/interfaces/ICurveXChainLiquidityGauge.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface ICurveXChainLiquidityGauge {\n event Approval(\n address indexed _owner,\n address indexed _spender,\n uint256 _value\n );\n event Deposit(address indexed provider, uint256 value);\n event SetGaugeManager(address _gauge_manager);\n event Transfer(address indexed _from, address indexed _to, uint256 _value);\n event UpdateLiquidityLimit(\n address indexed user,\n uint256 original_balance,\n uint256 original_supply,\n uint256 working_balance,\n uint256 working_supply\n );\n event Withdraw(address indexed provider, uint256 value);\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n function add_reward(address _reward_token, address _distributor) external;\n\n function allowance(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function balanceOf(address arg0) external view returns (uint256);\n\n function claim_rewards() external;\n\n function claim_rewards(address _addr) external;\n\n function claim_rewards(address _addr, address _receiver) external;\n\n function claimable_reward(address _user, address _reward_token)\n external\n view\n returns (uint256);\n\n function claimable_tokens(address addr) external returns (uint256);\n\n function claimed_reward(address _addr, address _token)\n external\n view\n returns (uint256);\n\n function decimals() external view returns (uint256);\n\n function decreaseAllowance(address _spender, uint256 _subtracted_value)\n external\n returns (bool);\n\n function deposit(uint256 _value) external;\n\n function deposit(uint256 _value, address _addr) external;\n\n function deposit(\n uint256 _value,\n address _addr,\n bool _claim_rewards\n ) external;\n\n function deposit_reward_token(address _reward_token, uint256 _amount)\n external;\n\n function deposit_reward_token(\n address _reward_token,\n uint256 _amount,\n uint256 _epoch\n ) external;\n\n function factory() external view returns (address);\n\n function increaseAllowance(address _spender, uint256 _added_value)\n external\n returns (bool);\n\n function inflation_rate(uint256 arg0) external view returns (uint256);\n\n function initialize(\n address _lp_token,\n address _root,\n address _manager\n ) external;\n\n function integrate_checkpoint() external view returns (uint256);\n\n function integrate_checkpoint_of(address arg0)\n external\n view\n returns (uint256);\n\n function integrate_fraction(address arg0) external view returns (uint256);\n\n function integrate_inv_supply(int128 arg0) external view returns (uint256);\n\n function integrate_inv_supply_of(address arg0)\n external\n view\n returns (uint256);\n\n function is_killed() external view returns (bool);\n\n function lp_token() external view returns (address);\n\n function manager() external view returns (address);\n\n function name() external view returns (string memory);\n\n function nonces(address arg0) external view returns (uint256);\n\n function period() external view returns (int128);\n\n function period_timestamp(int128 arg0) external view returns (uint256);\n\n function permit(\n address _owner,\n address _spender,\n uint256 _value,\n uint256 _deadline,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) external returns (bool);\n\n function recover_remaining(address _reward_token) external;\n\n function reward_count() external view returns (uint256);\n\n function reward_integral_for(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function reward_remaining(address arg0) external view returns (uint256);\n\n function reward_tokens(uint256 arg0) external view returns (address);\n\n function rewards_receiver(address arg0) external view returns (address);\n\n function root_gauge() external view returns (address);\n\n function set_gauge_manager(address _gauge_manager) external;\n\n function set_killed(bool _is_killed) external;\n\n function set_manager(address _gauge_manager) external;\n\n function set_reward_distributor(address _reward_token, address _distributor)\n external;\n\n function set_rewards_receiver(address _receiver) external;\n\n function set_root_gauge(address _root) external;\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function update_voting_escrow() external;\n\n function user_checkpoint(address addr) external returns (bool);\n\n function version() external view returns (string memory);\n\n function voting_escrow() external view returns (address);\n\n function withdraw(uint256 _value) external;\n\n function withdraw(uint256 _value, bool _claim_rewards) external;\n\n function withdraw(\n uint256 _value,\n bool _claim_rewards,\n address _receiver\n ) external;\n\n function working_balances(address arg0) external view returns (uint256);\n\n function working_supply() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IDepositContract.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IDepositContract {\n /// @notice A processed deposit event.\n event DepositEvent(\n bytes pubkey,\n bytes withdrawal_credentials,\n bytes amount,\n bytes signature,\n bytes index\n );\n\n /// @notice Submit a Phase 0 DepositData object.\n /// @param pubkey A BLS12-381 public key.\n /// @param withdrawal_credentials Commitment to a public key for withdrawals.\n /// @param signature A BLS12-381 signature.\n /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.\n /// Used as a protection against malformed input.\n function deposit(\n bytes calldata pubkey,\n bytes calldata withdrawal_credentials,\n bytes calldata signature,\n bytes32 deposit_data_root\n ) external payable;\n\n /// @notice Query the current deposit root hash.\n /// @return The deposit root hash.\n function get_deposit_root() external view returns (bytes32);\n\n /// @notice Query the current deposit count.\n /// @return The deposit count encoded as a little endian 64-bit number.\n function get_deposit_count() external view returns (bytes memory);\n}\n" + }, + "contracts/interfaces/IMerkl.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IDistributor {\n event Claimed(address indexed user, address indexed token, uint256 amount);\n\n function claim(\n address[] calldata users,\n address[] calldata tokens,\n uint256[] calldata amounts,\n bytes32[][] calldata proofs\n ) external;\n}\n" + }, + "contracts/interfaces/IMockVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IVault } from \"./IVault.sol\";\n\ninterface IMockVault is IVault {\n function outstandingWithdrawalsAmount() external view returns (uint256);\n\n function wethAvailable() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IOracle.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IOracle {\n /**\n * @dev returns the asset price in USD, in 8 decimal digits.\n *\n * The version of priceProvider deployed for OETH has 18 decimal digits\n */\n function price(address asset) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IOUSD.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IOUSD {\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n event GovernorshipTransferred(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n event PendingGovernorshipTransfer(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n event TotalSupplyUpdatedHighres(\n uint256 totalSupply,\n uint256 rebasingCredits,\n uint256 rebasingCreditsPerToken\n );\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n function _totalSupply() external view returns (uint256);\n\n function allowance(address _owner, address _spender)\n external\n view\n returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function balanceOf(address _account) external view returns (uint256);\n\n function burn(address account, uint256 amount) external;\n\n function changeSupply(uint256 _newTotalSupply) external;\n\n function claimGovernance() external;\n\n function creditsBalanceOf(address _account)\n external\n view\n returns (uint256, uint256);\n\n function creditsBalanceOfHighres(address _account)\n external\n view\n returns (\n uint256,\n uint256,\n bool\n );\n\n function decimals() external view returns (uint8);\n\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\n external\n returns (bool);\n\n function governor() external view returns (address);\n\n function increaseAllowance(address _spender, uint256 _addedValue)\n external\n returns (bool);\n\n function initialize(\n string memory _nameArg,\n string memory _symbolArg,\n address _vaultAddress\n ) external;\n\n function isGovernor() external view returns (bool);\n\n function isUpgraded(address) external view returns (uint256);\n\n function mint(address _account, uint256 _amount) external;\n\n function name() external view returns (string memory);\n\n function nonRebasingCreditsPerToken(address)\n external\n view\n returns (uint256);\n\n function nonRebasingSupply() external view returns (uint256);\n\n function rebaseOptIn() external;\n\n function rebaseOptOut() external;\n\n function rebaseState(address) external view returns (uint8);\n\n function rebasingCredits() external view returns (uint256);\n\n function rebasingCreditsHighres() external view returns (uint256);\n\n function rebasingCreditsPerToken() external view returns (uint256);\n\n function rebasingCreditsPerTokenHighres() external view returns (uint256);\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function transferGovernance(address _newGovernor) external;\n\n function vaultAddress() external view returns (address);\n}\n" + }, + "contracts/interfaces/ISafe.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface ISafe {\n function execTransactionFromModule(\n address,\n uint256,\n bytes memory,\n uint8\n ) external returns (bool);\n}\n" + }, + "contracts/interfaces/ISSVNetwork.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nstruct Cluster {\n uint32 validatorCount;\n uint64 networkFeeIndex;\n uint64 index;\n bool active;\n uint256 balance;\n}\n\ninterface ISSVNetwork {\n /**********/\n /* Errors */\n /**********/\n\n error CallerNotOwner(); // 0x5cd83192\n error CallerNotWhitelisted(); // 0x8c6e5d71\n error FeeTooLow(); // 0x732f9413\n error FeeExceedsIncreaseLimit(); // 0x958065d9\n error NoFeeDeclared(); // 0x1d226c30\n error ApprovalNotWithinTimeframe(); // 0x97e4b518\n error OperatorDoesNotExist(); // 0x961e3e8c\n error InsufficientBalance(); // 0xf4d678b8\n error ValidatorDoesNotExist(); // 0xe51315d2\n error ClusterNotLiquidatable(); // 0x60300a8d\n error InvalidPublicKeyLength(); // 0x637297a4\n error InvalidOperatorIdsLength(); // 0x38186224\n error ClusterAlreadyEnabled(); // 0x3babafd2\n error ClusterIsLiquidated(); // 0x95a0cf33\n error ClusterDoesNotExists(); // 0x185e2b16\n error IncorrectClusterState(); // 0x12e04c87\n error UnsortedOperatorsList(); // 0xdd020e25\n error NewBlockPeriodIsBelowMinimum(); // 0x6e6c9cac\n error ExceedValidatorLimit(); // 0x6df5ab76\n error TokenTransferFailed(); // 0x045c4b02\n error SameFeeChangeNotAllowed(); // 0xc81272f8\n error FeeIncreaseNotAllowed(); // 0x410a2b6c\n error NotAuthorized(); // 0xea8e4eb5\n error OperatorsListNotUnique(); // 0xa5a1ff5d\n error OperatorAlreadyExists(); // 0x289c9494\n error TargetModuleDoesNotExist(); // 0x8f9195fb\n error MaxValueExceeded(); // 0x91aa3017\n error FeeTooHigh(); // 0xcd4e6167\n error PublicKeysSharesLengthMismatch(); // 0x9ad467b8\n error IncorrectValidatorStateWithData(bytes publicKey); // 0x89307938\n error ValidatorAlreadyExistsWithData(bytes publicKey); // 0x388e7999\n error EmptyPublicKeysList(); // df83e679\n\n // legacy errors\n error ValidatorAlreadyExists(); // 0x8d09a73e\n error IncorrectValidatorState(); // 0x2feda3c1\n\n event AdminChanged(address previousAdmin, address newAdmin);\n event BeaconUpgraded(address indexed beacon);\n event ClusterDeposited(\n address indexed owner,\n uint64[] operatorIds,\n uint256 value,\n Cluster cluster\n );\n event ClusterLiquidated(\n address indexed owner,\n uint64[] operatorIds,\n Cluster cluster\n );\n event ClusterReactivated(\n address indexed owner,\n uint64[] operatorIds,\n Cluster cluster\n );\n event ClusterWithdrawn(\n address indexed owner,\n uint64[] operatorIds,\n uint256 value,\n Cluster cluster\n );\n event DeclareOperatorFeePeriodUpdated(uint64 value);\n event ExecuteOperatorFeePeriodUpdated(uint64 value);\n event FeeRecipientAddressUpdated(\n address indexed owner,\n address recipientAddress\n );\n event Initialized(uint8 version);\n event LiquidationThresholdPeriodUpdated(uint64 value);\n event MinimumLiquidationCollateralUpdated(uint256 value);\n event NetworkEarningsWithdrawn(uint256 value, address recipient);\n event NetworkFeeUpdated(uint256 oldFee, uint256 newFee);\n event OperatorAdded(\n uint64 indexed operatorId,\n address indexed owner,\n bytes publicKey,\n uint256 fee\n );\n event OperatorFeeDeclarationCancelled(\n address indexed owner,\n uint64 indexed operatorId\n );\n event OperatorFeeDeclared(\n address indexed owner,\n uint64 indexed operatorId,\n uint256 blockNumber,\n uint256 fee\n );\n event OperatorFeeExecuted(\n address indexed owner,\n uint64 indexed operatorId,\n uint256 blockNumber,\n uint256 fee\n );\n event OperatorFeeIncreaseLimitUpdated(uint64 value);\n event OperatorMaximumFeeUpdated(uint64 maxFee);\n event OperatorRemoved(uint64 indexed operatorId);\n event OperatorWhitelistUpdated(\n uint64 indexed operatorId,\n address whitelisted\n );\n event OperatorWithdrawn(\n address indexed owner,\n uint64 indexed operatorId,\n uint256 value\n );\n event OwnershipTransferStarted(\n address indexed previousOwner,\n address indexed newOwner\n );\n event OwnershipTransferred(\n address indexed previousOwner,\n address indexed newOwner\n );\n event Upgraded(address indexed implementation);\n event ValidatorAdded(\n address indexed owner,\n uint64[] operatorIds,\n bytes publicKey,\n bytes shares,\n Cluster cluster\n );\n event ValidatorExited(\n address indexed owner,\n uint64[] operatorIds,\n bytes publicKey\n );\n event ValidatorRemoved(\n address indexed owner,\n uint64[] operatorIds,\n bytes publicKey,\n Cluster cluster\n );\n\n fallback() external;\n\n function acceptOwnership() external;\n\n function cancelDeclaredOperatorFee(uint64 operatorId) external;\n\n function declareOperatorFee(uint64 operatorId, uint256 fee) external;\n\n function deposit(\n address clusterOwner,\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function executeOperatorFee(uint64 operatorId) external;\n\n function exitValidator(bytes memory publicKey, uint64[] memory operatorIds)\n external;\n\n function bulkExitValidator(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds\n ) external;\n\n function getVersion() external pure returns (string memory version);\n\n function initialize(\n address token_,\n address ssvOperators_,\n address ssvClusters_,\n address ssvDAO_,\n address ssvViews_,\n uint64 minimumBlocksBeforeLiquidation_,\n uint256 minimumLiquidationCollateral_,\n uint32 validatorsPerOperatorLimit_,\n uint64 declareOperatorFeePeriod_,\n uint64 executeOperatorFeePeriod_,\n uint64 operatorMaxFeeIncrease_\n ) external;\n\n function liquidate(\n address clusterOwner,\n uint64[] memory operatorIds,\n Cluster memory cluster\n ) external;\n\n function owner() external view returns (address);\n\n function pendingOwner() external view returns (address);\n\n function proxiableUUID() external view returns (bytes32);\n\n function reactivate(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function reduceOperatorFee(uint64 operatorId, uint256 fee) external;\n\n function registerOperator(bytes memory publicKey, uint256 fee)\n external\n returns (uint64 id);\n\n function registerValidator(\n bytes memory publicKey,\n uint64[] memory operatorIds,\n bytes memory sharesData,\n Cluster memory cluster\n ) external payable;\n\n function bulkRegisterValidator(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds,\n bytes[] calldata sharesData,\n Cluster memory cluster\n ) external payable;\n\n function migrateClusterToETH(\n uint64[] calldata operatorIds,\n Cluster memory cluster\n ) external payable;\n\n function removeOperator(uint64 operatorId) external;\n\n function removeValidator(\n bytes memory publicKey,\n uint64[] memory operatorIds,\n Cluster memory cluster\n ) external;\n\n function bulkRemoveValidator(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds,\n Cluster memory cluster\n ) external;\n\n function renounceOwnership() external;\n\n function setFeeRecipientAddress(address recipientAddress) external;\n\n function setOperatorWhitelist(uint64 operatorId, address whitelisted)\n external;\n\n function transferOwnership(address newOwner) external;\n\n function updateDeclareOperatorFeePeriod(uint64 timeInSeconds) external;\n\n function updateExecuteOperatorFeePeriod(uint64 timeInSeconds) external;\n\n function updateLiquidationThresholdPeriod(uint64 blocks) external;\n\n function updateMaximumOperatorFee(uint64 maxFee) external;\n\n function updateMinimumLiquidationCollateral(uint256 amount) external;\n\n function updateModule(uint8 moduleId, address moduleAddress) external;\n\n function updateNetworkFee(uint256 fee) external;\n\n function updateOperatorFeeIncreaseLimit(uint64 percentage) external;\n\n function upgradeTo(address newImplementation) external;\n\n function upgradeToAndCall(address newImplementation, bytes memory data)\n external\n payable;\n\n function withdraw(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function withdrawAllOperatorEarnings(uint64 operatorId) external;\n\n function withdrawNetworkEarnings(uint256 amount) external;\n\n function withdrawOperatorEarnings(uint64 operatorId, uint256 amount)\n external;\n}\n" + }, + "contracts/interfaces/IStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\n */\ninterface IStrategy {\n /**\n * @dev Deposit the given asset to platform\n * @param _asset asset address\n * @param _amount Amount to deposit\n */\n function deposit(address _asset, uint256 _amount) external;\n\n /**\n * @dev Deposit the entire balance of all supported assets in the Strategy\n * to the platform\n */\n function depositAll() external;\n\n /**\n * @dev Withdraw given asset from Lending platform\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external;\n\n /**\n * @dev Liquidate all assets in strategy and return them to Vault.\n */\n function withdrawAll() external;\n\n /**\n * @dev Returns the current balance of the given asset.\n */\n function checkBalance(address _asset)\n external\n view\n returns (uint256 balance);\n\n /**\n * @dev Returns bool indicating whether strategy supports asset.\n */\n function supportsAsset(address _asset) external view returns (bool);\n\n /**\n * @dev Collect reward tokens from the Strategy.\n */\n function collectRewardTokens() external;\n\n /**\n * @dev The address array of the reward tokens for the Strategy.\n */\n function getRewardTokenAddresses() external view returns (address[] memory);\n\n function harvesterAddress() external view returns (address);\n\n function transferToken(address token, uint256 amount) external;\n\n function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\n external;\n}\n" + }, + "contracts/interfaces/IVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultStorage } from \"../vault/VaultStorage.sol\";\n\ninterface IVault {\n // slither-disable-start constable-states\n\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\n event StrategyApproved(address _addr);\n event StrategyRemoved(address _addr);\n event Mint(address _addr, uint256 _value);\n event Redeem(address _addr, uint256 _value);\n event CapitalPaused();\n event CapitalUnpaused();\n event DefaultStrategyUpdated(address _strategy);\n event RebasePaused();\n event RebaseUnpaused();\n event VaultBufferUpdated(uint256 _vaultBuffer);\n event AllocateThresholdUpdated(uint256 _threshold);\n event StrategistUpdated(address _address);\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\n event TrusteeFeeBpsChanged(uint256 _basis);\n event TrusteeAddressChanged(address _address);\n event StrategyAddedToMintWhitelist(address indexed strategy);\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\n event DripDurationChanged(uint256 dripDuration);\n event WithdrawalRequested(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount,\n uint256 _queued\n );\n event WithdrawalClaimed(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount\n );\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\n\n // Governable.sol\n function transferGovernance(address _newGovernor) external;\n\n function claimGovernance() external;\n\n function governor() external view returns (address);\n\n // VaultAdmin.sol\n function setVaultBuffer(uint256 _vaultBuffer) external;\n\n function vaultBuffer() external view returns (uint256);\n\n function setAutoAllocateThreshold(uint256 _threshold) external;\n\n function autoAllocateThreshold() external view returns (uint256);\n\n function setStrategistAddr(address _address) external;\n\n function strategistAddr() external view returns (address);\n\n function setOperatorAddr(address _operator) external;\n\n function operatorAddr() external view returns (address);\n\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\n\n function maxSupplyDiff() external view returns (uint256);\n\n function setTrusteeAddress(address _address) external;\n\n function trusteeAddress() external view returns (address);\n\n function setTrusteeFeeBps(uint256 _basis) external;\n\n function trusteeFeeBps() external view returns (uint256);\n\n function approveStrategy(address _addr) external;\n\n function removeStrategy(address _addr) external;\n\n function setDefaultStrategy(address _strategy) external;\n\n function defaultStrategy() external view returns (address);\n\n function pauseRebase() external;\n\n function unpauseRebase() external;\n\n function rebasePaused() external view returns (bool);\n\n function pauseCapital() external;\n\n function unpauseCapital() external;\n\n function capitalPaused() external view returns (bool);\n\n function transferToken(address _asset, uint256 _amount) external;\n\n function withdrawAllFromStrategy(address _strategyAddr) external;\n\n function withdrawAllFromStrategies() external;\n\n function withdrawFromStrategy(\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external;\n\n function depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external;\n\n // VaultCore.sol\n function mint(uint256 _amount) external;\n\n function mintForStrategy(uint256 _amount) external;\n\n function burnForStrategy(uint256 _amount) external;\n\n function allocate() external;\n\n function rebase() external;\n\n function totalValue() external view returns (uint256 value);\n\n function checkBalance(address _asset) external view returns (uint256);\n\n function getAssetCount() external view returns (uint256);\n\n function getAllAssets() external view returns (address[] memory);\n\n function getStrategyCount() external view returns (uint256);\n\n function getAllStrategies() external view returns (address[] memory);\n\n function strategies(address _addr)\n external\n view\n returns (VaultStorage.Strategy memory);\n\n /// @notice Deprecated: use `asset()` instead.\n function isSupportedAsset(address _asset) external view returns (bool);\n\n function asset() external view returns (address);\n\n function oToken() external view returns (address);\n\n function initialize(address) external;\n\n function addWithdrawalQueueLiquidity() external;\n\n function requestWithdrawal(uint256 _amount)\n external\n returns (uint256 requestId, uint256 queued);\n\n function claimWithdrawal(uint256 requestId)\n external\n returns (uint256 amount);\n\n function claimWithdrawals(uint256[] memory requestIds)\n external\n returns (uint256[] memory amounts, uint256 totalAmount);\n\n function withdrawalQueueMetadata()\n external\n view\n returns (VaultStorage.WithdrawalQueueMetadata memory);\n\n function withdrawalRequests(uint256 requestId)\n external\n view\n returns (VaultStorage.WithdrawalRequest memory);\n\n function addStrategyToMintWhitelist(address strategyAddr) external;\n\n function removeStrategyFromMintWhitelist(address strategyAddr) external;\n\n function isMintWhitelistedStrategy(address strategyAddr)\n external\n view\n returns (bool);\n\n function withdrawalClaimDelay() external view returns (uint256);\n\n function setWithdrawalClaimDelay(uint256 newDelay) external;\n\n function lastRebase() external view returns (uint64);\n\n function dripDuration() external view returns (uint64);\n\n function setDripDuration(uint256 _dripDuration) external;\n\n function rebasePerSecondMax() external view returns (uint64);\n\n function setRebaseRateMax(uint256 yearlyApr) external;\n\n function rebasePerSecondTarget() external view returns (uint64);\n\n function previewYield() external view returns (uint256 yield);\n\n // slither-disable-end constable-states\n}\n" + }, + "contracts/interfaces/IWETH9.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IWETH9 {\n event Approval(address indexed src, address indexed guy, uint256 wad);\n event Deposit(address indexed dst, uint256 wad);\n event Transfer(address indexed src, address indexed dst, uint256 wad);\n event Withdrawal(address indexed src, uint256 wad);\n\n function allowance(address, address) external view returns (uint256);\n\n function approve(address guy, uint256 wad) external returns (bool);\n\n function balanceOf(address) external view returns (uint256);\n\n function decimals() external view returns (uint8);\n\n function deposit() external payable;\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address dst, uint256 wad) external returns (bool);\n\n function transferFrom(\n address src,\n address dst,\n uint256 wad\n ) external returns (bool);\n\n function withdraw(uint256 wad) external;\n}\n" + }, + "contracts/interfaces/morpho/IMorphoV2Adapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IMorphoV2Adapter {\n // address of the underlying vault\n function morphoVaultV1() external view returns (address);\n\n // address of the parent Morpho V2 vault\n function parentVault() external view returns (address);\n}\n" + }, + "contracts/interfaces/morpho/IVaultV2.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC4626 } from \"../../../lib/openzeppelin/interfaces/IERC4626.sol\";\n\ninterface IVaultV2 is IERC4626 {\n function liquidityAdapter() external view returns (address);\n}\n" + }, + "contracts/interfaces/sonic/ISFC.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\n\n/**\n * @title Special Fee Contract for Sonic network\n * @notice The SFC maintains a list of validators and delegators and distributes rewards to them.\n * @custom:security-contact security@fantom.foundation\n */\ninterface ISFC {\n error StakeIsFullySlashed();\n\n event CreatedValidator(\n uint256 indexed validatorID,\n address indexed auth,\n uint256 createdEpoch,\n uint256 createdTime\n );\n event Delegated(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 amount\n );\n event Undelegated(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 indexed wrID,\n uint256 amount\n );\n event Withdrawn(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 indexed wrID,\n uint256 amount,\n uint256 penalty\n );\n event ClaimedRewards(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 rewards\n );\n event RestakedRewards(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 rewards\n );\n event BurntFTM(uint256 amount);\n event UpdatedSlashingRefundRatio(\n uint256 indexed validatorID,\n uint256 refundRatio\n );\n event RefundedSlashedLegacyDelegation(\n address indexed delegator,\n uint256 indexed validatorID,\n uint256 amount\n );\n\n event DeactivatedValidator(\n uint256 indexed validatorID,\n uint256 deactivatedEpoch,\n uint256 deactivatedTime\n );\n event ChangedValidatorStatus(uint256 indexed validatorID, uint256 status);\n event AnnouncedRedirection(address indexed from, address indexed to);\n\n function currentSealedEpoch() external view returns (uint256);\n\n function getEpochSnapshot(uint256 epoch)\n external\n view\n returns (\n uint256 endTime,\n uint256 endBlock,\n uint256 epochFee,\n uint256 baseRewardPerSecond,\n uint256 totalStake,\n uint256 totalSupply\n );\n\n function getStake(address delegator, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function getValidator(uint256 validatorID)\n external\n view\n returns (\n uint256 status,\n uint256 receivedStake,\n address auth,\n uint256 createdEpoch,\n uint256 createdTime,\n uint256 deactivatedTime,\n uint256 deactivatedEpoch\n );\n\n function getValidatorID(address auth) external view returns (uint256);\n\n function getValidatorPubkey(uint256 validatorID)\n external\n view\n returns (bytes memory);\n\n function pubkeyAddressvalidatorID(address pubkeyAddress)\n external\n view\n returns (uint256);\n\n function getWithdrawalRequest(\n address delegator,\n uint256 validatorID,\n uint256 wrID\n )\n external\n view\n returns (\n uint256 epoch,\n uint256 time,\n uint256 amount\n );\n\n function isOwner() external view returns (bool);\n\n function lastValidatorID() external view returns (uint256);\n\n function minGasPrice() external view returns (uint256);\n\n function owner() external view returns (address);\n\n function renounceOwnership() external;\n\n function slashingRefundRatio(uint256 validatorID)\n external\n view\n returns (uint256);\n\n function stashedRewardsUntilEpoch(address delegator, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function totalActiveStake() external view returns (uint256);\n\n function totalStake() external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function transferOwnership(address newOwner) external;\n\n function treasuryAddress() external view returns (address);\n\n function version() external pure returns (bytes3);\n\n function currentEpoch() external view returns (uint256);\n\n function updateConstsAddress(address v) external;\n\n function constsAddress() external view returns (address);\n\n function getEpochValidatorIDs(uint256 epoch)\n external\n view\n returns (uint256[] memory);\n\n function getEpochReceivedStake(uint256 epoch, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function getEpochAccumulatedRewardPerToken(\n uint256 epoch,\n uint256 validatorID\n ) external view returns (uint256);\n\n function getEpochAccumulatedUptime(uint256 epoch, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function getEpochAverageUptime(uint256 epoch, uint256 validatorID)\n external\n view\n returns (uint32);\n\n function getEpochAccumulatedOriginatedTxsFee(\n uint256 epoch,\n uint256 validatorID\n ) external view returns (uint256);\n\n function getEpochOfflineTime(uint256 epoch, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function getEpochOfflineBlocks(uint256 epoch, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function getEpochEndBlock(uint256 epoch) external view returns (uint256);\n\n function rewardsStash(address delegator, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function createValidator(bytes calldata pubkey) external payable;\n\n function getSelfStake(uint256 validatorID) external view returns (uint256);\n\n function delegate(uint256 validatorID) external payable;\n\n function undelegate(\n uint256 validatorID,\n uint256 wrID,\n uint256 amount\n ) external;\n\n function isSlashed(uint256 validatorID) external view returns (bool);\n\n function withdraw(uint256 validatorID, uint256 wrID) external;\n\n function deactivateValidator(uint256 validatorID, uint256 status) external;\n\n function pendingRewards(address delegator, uint256 validatorID)\n external\n view\n returns (uint256);\n\n function stashRewards(address delegator, uint256 validatorID) external;\n\n function claimRewards(uint256 validatorID) external;\n\n function restakeRewards(uint256 validatorID) external;\n\n function updateSlashingRefundRatio(uint256 validatorID, uint256 refundRatio)\n external;\n\n function updateTreasuryAddress(address v) external;\n\n function burnFTM(uint256 amount) external;\n\n function sealEpoch(\n uint256[] calldata offlineTime,\n uint256[] calldata offlineBlocks,\n uint256[] calldata uptimes,\n uint256[] calldata originatedTxsFee\n ) external;\n\n function sealEpochValidators(uint256[] calldata nextValidatorIDs) external;\n\n function initialize(\n uint256 sealedEpoch,\n uint256 _totalSupply,\n address nodeDriver,\n address consts,\n address _owner\n ) external;\n\n function setGenesisValidator(\n address auth,\n uint256 validatorID,\n bytes calldata pubkey,\n uint256 createdTime\n ) external;\n\n function setGenesisDelegation(\n address delegator,\n uint256 validatorID,\n uint256 stake\n ) external;\n\n function updateStakeSubscriberAddress(address v) external;\n\n function stakeSubscriberAddress() external view returns (address);\n\n function setRedirectionAuthorizer(address v) external;\n\n function announceRedirection(address to) external;\n\n function initiateRedirection(address from, address to) external;\n\n function redirect(address to) external;\n}\n" + }, + "contracts/interfaces/sonic/IWrappedSonic.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IWrappedSonic {\n event Deposit(address indexed account, uint256 value);\n event Withdrawal(address indexed account, uint256 value);\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n\n function allowance(address owner, address spender)\n external\n view\n returns (uint256);\n\n function approve(address spender, uint256 value) external returns (bool);\n\n function balanceOf(address account) external view returns (uint256);\n\n function decimals() external view returns (uint8);\n\n function deposit() external payable;\n\n function depositFor(address account) external payable returns (bool);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address to, uint256 value) external returns (bool);\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external returns (bool);\n\n function withdraw(uint256 value) external;\n\n function withdrawTo(address account, uint256 value) external returns (bool);\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV2Router02.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IUniswapV2Router {\n function WETH() external pure returns (address);\n\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n\n function addLiquidity(\n address tokenA,\n address tokenB,\n uint256 amountADesired,\n uint256 amountBDesired,\n uint256 amountAMin,\n uint256 amountBMin,\n address to,\n uint256 deadline\n )\n external\n returns (\n uint256 amountA,\n uint256 amountB,\n uint256 liquidity\n );\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV3Router.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// -- Solididy v0.5.x compatible interface\ninterface IUniswapV3Router {\n struct ExactInputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n }\n\n /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path\n /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata\n /// @return amountOut The amount of the received token\n function exactInput(ExactInputParams calldata params)\n external\n payable\n returns (uint256 amountOut);\n}\n" + }, + "contracts/mocks/crosschain/CCTPMessageTransmitterMock.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ICCTPMessageTransmitter } from \"../../interfaces/cctp/ICCTP.sol\";\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { BytesHelper } from \"../../utils/BytesHelper.sol\";\nimport { AbstractCCTPIntegrator } from \"../../strategies/crosschain/AbstractCCTPIntegrator.sol\";\n\n/**\n * @title Mock conctract simulating the functionality of the CCTPTokenMessenger contract\n * for the porposes of unit testing.\n * @author Origin Protocol Inc\n */\n\ncontract CCTPMessageTransmitterMock is ICCTPMessageTransmitter {\n using BytesHelper for bytes;\n\n IERC20 public usdc;\n uint256 public nonce = 0;\n // Sender index in the burn message v2\n // Ref: https://github.com/circlefin/evm-cctp-contracts/blob/master/src/messages/v2/BurnMessageV2.sol\n uint8 constant BURN_MESSAGE_V2_MESSAGE_SENDER_INDEX = 100;\n uint8 constant BURN_MESSAGE_V2_HOOK_DATA_INDEX = 228;\n\n uint16 public messageFinality = 2000;\n address public messageSender;\n uint32 public sourceDomain = 4294967295; // 0xFFFFFFFF\n\n // Full message with header\n struct Message {\n uint32 version;\n uint32 sourceDomain;\n uint32 destinationDomain;\n bytes32 recipient;\n bytes32 messageHeaderRecipient;\n bytes32 sender;\n bytes32 destinationCaller;\n uint32 minFinalityThreshold;\n bool isTokenTransfer;\n uint256 tokenAmount;\n bytes messageBody;\n }\n\n Message[] public messages;\n // map of encoded messages to the corresponding message structs\n mapping(bytes32 => Message) public encodedMessages;\n\n constructor(address _usdc) {\n usdc = IERC20(_usdc);\n }\n\n // @dev for the porposes of unit tests queues the message to be mock-sent using\n // the cctp bridge.\n function sendMessage(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n uint32 minFinalityThreshold,\n bytes memory messageBody\n ) external virtual override {\n bytes32 nonceHash = keccak256(abi.encodePacked(nonce));\n nonce++;\n\n // If destination is mainnet, source is base and vice versa\n uint32 sourceDomain = destinationDomain == 0 ? 6 : 0;\n\n Message memory message = Message({\n version: 1,\n sourceDomain: sourceDomain,\n destinationDomain: destinationDomain,\n recipient: recipient,\n messageHeaderRecipient: recipient,\n sender: bytes32(uint256(uint160(msg.sender))),\n destinationCaller: destinationCaller,\n minFinalityThreshold: minFinalityThreshold,\n isTokenTransfer: false,\n tokenAmount: 0,\n messageBody: messageBody\n });\n\n messages.push(message);\n }\n\n // @dev for the porposes of unit tests queues the USDC burn/mint to be executed\n // using the cctp bridge.\n function sendTokenTransferMessage(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n uint32 minFinalityThreshold,\n uint256 tokenAmount,\n bytes memory messageBody\n ) external {\n bytes32 nonceHash = keccak256(abi.encodePacked(nonce));\n nonce++;\n\n // If destination is mainnet, source is base and vice versa\n uint32 sourceDomain = destinationDomain == 0 ? 6 : 0;\n\n Message memory message = Message({\n version: 1,\n sourceDomain: sourceDomain,\n destinationDomain: destinationDomain,\n recipient: recipient,\n messageHeaderRecipient: recipient,\n sender: bytes32(uint256(uint160(msg.sender))),\n destinationCaller: destinationCaller,\n minFinalityThreshold: minFinalityThreshold,\n isTokenTransfer: true,\n tokenAmount: tokenAmount,\n messageBody: messageBody\n });\n\n messages.push(message);\n }\n\n function receiveMessage(bytes memory message, bytes memory attestation)\n public\n virtual\n override\n returns (bool)\n {\n Message memory storedMsg = encodedMessages[keccak256(message)];\n AbstractCCTPIntegrator recipient = AbstractCCTPIntegrator(\n address(uint160(uint256(storedMsg.recipient)))\n );\n\n bytes32 sender = storedMsg.sender;\n bytes memory messageBody = storedMsg.messageBody;\n\n // Credit USDC in this step as it is done in the live cctp contracts\n if (storedMsg.isTokenTransfer) {\n usdc.transfer(address(recipient), storedMsg.tokenAmount);\n // override the sender with the one stored in the Burn message as the sender int he\n // message header is the TokenMessenger.\n sender = bytes32(\n uint256(\n uint160(\n storedMsg.messageBody.extractAddress(\n BURN_MESSAGE_V2_MESSAGE_SENDER_INDEX\n )\n )\n )\n );\n messageBody = storedMsg.messageBody.extractSlice(\n BURN_MESSAGE_V2_HOOK_DATA_INDEX,\n storedMsg.messageBody.length\n );\n } else {\n bytes32 overrideSenderBytes = bytes32(\n uint256(uint160(messageSender))\n );\n if (messageFinality >= 2000) {\n recipient.handleReceiveFinalizedMessage(\n sourceDomain == 4294967295\n ? storedMsg.sourceDomain\n : sourceDomain,\n messageSender == address(0) ? sender : overrideSenderBytes,\n messageFinality,\n messageBody\n );\n } else {\n recipient.handleReceiveUnfinalizedMessage(\n sourceDomain == 4294967295\n ? storedMsg.sourceDomain\n : sourceDomain,\n messageSender == address(0) ? sender : overrideSenderBytes,\n messageFinality,\n messageBody\n );\n }\n }\n\n return true;\n }\n\n function addMessage(Message memory storedMsg) external {\n messages.push(storedMsg);\n }\n\n function _encodeMessageHeader(\n uint32 version,\n uint32 sourceDomain,\n bytes32 sender,\n bytes32 recipient,\n bytes memory messageBody\n ) internal pure returns (bytes memory) {\n bytes memory header = abi.encodePacked(\n version, // 0-3\n sourceDomain, // 4-7\n bytes32(0), // 8-39 destinationDomain\n bytes4(0), // 40-43 nonce\n sender, // 44-75 sender\n recipient, // 76-107 recipient\n bytes32(0), // other stuff\n bytes8(0) // other stuff\n );\n return abi.encodePacked(header, messageBody);\n }\n\n function _removeFront() internal returns (Message memory) {\n require(messages.length > 0, \"No messages\");\n Message memory removed = messages[0];\n // Shift array\n for (uint256 i = 0; i < messages.length - 1; i++) {\n messages[i] = messages[i + 1];\n }\n messages.pop();\n return removed;\n }\n\n function _processMessage(Message memory storedMsg) internal {\n bytes memory encodedMessage = _encodeMessageHeader(\n storedMsg.version,\n storedMsg.sourceDomain,\n storedMsg.sender,\n storedMsg.messageHeaderRecipient,\n storedMsg.messageBody\n );\n\n encodedMessages[keccak256(encodedMessage)] = storedMsg;\n\n address recipient = address(uint160(uint256(storedMsg.recipient)));\n\n AbstractCCTPIntegrator(recipient).relay(encodedMessage, bytes(\"\"));\n }\n\n function _removeBack() internal returns (Message memory) {\n require(messages.length > 0, \"No messages\");\n Message memory last = messages[messages.length - 1];\n messages.pop();\n return last;\n }\n\n function messagesInQueue() external view returns (uint256) {\n return messages.length;\n }\n\n function processFrontOverrideHeader(bytes4 customHeader) external {\n Message memory storedMsg = _removeFront();\n\n bytes memory modifiedBody = abi.encodePacked(\n customHeader,\n storedMsg.messageBody.extractSlice(4, storedMsg.messageBody.length)\n );\n\n storedMsg.messageBody = modifiedBody;\n\n _processMessage(storedMsg);\n }\n\n function processFrontOverrideVersion(uint32 customVersion) external {\n Message memory storedMsg = _removeFront();\n storedMsg.version = customVersion;\n _processMessage(storedMsg);\n }\n\n function processFrontOverrideSender(address customSender) external {\n Message memory storedMsg = _removeFront();\n storedMsg.sender = bytes32(uint256(uint160(customSender)));\n _processMessage(storedMsg);\n }\n\n function processFrontOverrideRecipient(address customRecipient) external {\n Message memory storedMsg = _removeFront();\n storedMsg.messageHeaderRecipient = bytes32(\n uint256(uint160(customRecipient))\n );\n _processMessage(storedMsg);\n }\n\n function processFrontOverrideMessageBody(bytes memory customMessageBody)\n external\n {\n Message memory storedMsg = _removeFront();\n storedMsg.messageBody = customMessageBody;\n _processMessage(storedMsg);\n }\n\n function processFront() external {\n Message memory storedMsg = _removeFront();\n _processMessage(storedMsg);\n }\n\n function processBack() external {\n Message memory storedMsg = _removeBack();\n _processMessage(storedMsg);\n }\n\n function getMessagesLength() external view returns (uint256) {\n return messages.length;\n }\n\n function overrideMessageFinality(uint16 _finality) external {\n messageFinality = _finality;\n }\n\n function overrideSender(address _sender) external {\n messageSender = _sender;\n }\n\n function overrideSourceDomain(uint32 _sourceDomain) external {\n sourceDomain = _sourceDomain;\n }\n}\n" + }, + "contracts/mocks/crosschain/CCTPMessageTransmitterMock2.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IMessageHandlerV2 } from \"../../interfaces/cctp/ICCTP.sol\";\nimport { BytesHelper } from \"../../utils/BytesHelper.sol\";\nimport { CCTPMessageTransmitterMock } from \"./CCTPMessageTransmitterMock.sol\";\n\nuint8 constant SOURCE_DOMAIN_INDEX = 4;\nuint8 constant RECIPIENT_INDEX = 76;\nuint8 constant SENDER_INDEX = 44;\nuint8 constant MESSAGE_BODY_INDEX = 148;\n\n/**\n * @title Mock conctract simulating the functionality of the CCTPTokenMessenger contract\n * for the porposes of unit testing.\n * @author Origin Protocol Inc\n */\n\ncontract CCTPMessageTransmitterMock2 is CCTPMessageTransmitterMock {\n using BytesHelper for bytes;\n\n address public cctpTokenMessenger;\n uint32 public peerDomainId;\n\n event MessageReceivedInMockTransmitter(bytes message);\n event MessageSent(bytes message);\n\n constructor(address _usdc, uint32 _peerDomainId)\n CCTPMessageTransmitterMock(_usdc)\n {\n peerDomainId = _peerDomainId;\n }\n\n function setCCTPTokenMessenger(address _cctpTokenMessenger) external {\n cctpTokenMessenger = _cctpTokenMessenger;\n }\n\n function setPeerDomainId(uint32 _peerDomainId) external {\n peerDomainId = _peerDomainId;\n }\n\n function sendMessage(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n uint32 minFinalityThreshold,\n bytes memory messageBody\n ) external virtual override {\n bytes memory message = abi.encodePacked(\n uint32(1), // version\n destinationDomain == 0 ? peerDomainId : 0, // source domain\n uint32(destinationDomain), // destination domain\n uint256(0),\n bytes32(uint256(uint160(msg.sender))), // sender\n recipient, // recipient\n destinationCaller, // destination caller\n minFinalityThreshold, // min finality threshold\n uint32(0),\n messageBody // message body\n );\n emit MessageSent(message);\n }\n\n function receiveMessage(bytes memory message, bytes memory attestation)\n public\n virtual\n override\n returns (bool)\n {\n uint32 sourceDomain = message.extractUint32(SOURCE_DOMAIN_INDEX);\n address recipient = message.extractAddress(RECIPIENT_INDEX);\n address sender = message.extractAddress(SENDER_INDEX);\n\n bytes memory messageBody = message.extractSlice(\n MESSAGE_BODY_INDEX,\n message.length\n );\n\n bool isBurnMessage = recipient == cctpTokenMessenger;\n\n if (isBurnMessage) {\n // recipient = messageBody.extractAddress(BURN_MESSAGE_V2_RECIPIENT_INDEX);\n // This step won't mint USDC, transfer it to the recipient address\n // in your tests\n } else {\n IMessageHandlerV2(recipient).handleReceiveFinalizedMessage(\n sourceDomain,\n bytes32(uint256(uint160(sender))),\n 2000,\n messageBody\n );\n }\n\n // This step won't mint USDC, transfer it to the recipient address\n // in your tests\n emit MessageReceivedInMockTransmitter(message);\n\n return true;\n }\n}\n" + }, + "contracts/mocks/crosschain/CCTPTokenMessengerMock.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ICCTPTokenMessenger } from \"../../interfaces/cctp/ICCTP.sol\";\nimport { CCTPMessageTransmitterMock } from \"./CCTPMessageTransmitterMock.sol\";\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\n\n/**\n * @title Mock conctract simulating the functionality of the CCTPTokenMessenger contract\n * for the porposes of unit testing.\n * @author Origin Protocol Inc\n */\n\ncontract CCTPTokenMessengerMock is ICCTPTokenMessenger {\n IERC20 public usdc;\n CCTPMessageTransmitterMock public cctpMessageTransmitterMock;\n\n constructor(address _usdc, address _cctpMessageTransmitterMock) {\n usdc = IERC20(_usdc);\n cctpMessageTransmitterMock = CCTPMessageTransmitterMock(\n _cctpMessageTransmitterMock\n );\n }\n\n function depositForBurn(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller,\n uint256 maxFee,\n uint32 minFinalityThreshold\n ) external override {\n revert(\"Not implemented\");\n }\n\n /**\n * @dev mocks the depositForBurnWithHook function by sending the USDC to the CCTPMessageTransmitterMock\n * called by the AbstractCCTPIntegrator contract.\n */\n function depositForBurnWithHook(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller,\n uint256 maxFee,\n uint32 minFinalityThreshold,\n bytes memory hookData\n ) external override {\n require(burnToken == address(usdc), \"Invalid burn token\");\n\n usdc.transferFrom(msg.sender, address(this), maxFee);\n uint256 destinationAmount = amount - maxFee;\n usdc.transferFrom(\n msg.sender,\n address(cctpMessageTransmitterMock),\n destinationAmount\n );\n\n bytes memory burnMessage = _encodeBurnMessageV2(\n mintRecipient,\n amount,\n msg.sender,\n maxFee,\n maxFee,\n hookData\n );\n\n cctpMessageTransmitterMock.sendTokenTransferMessage(\n destinationDomain,\n mintRecipient,\n destinationCaller,\n minFinalityThreshold,\n destinationAmount,\n burnMessage\n );\n }\n\n function _encodeBurnMessageV2(\n bytes32 mintRecipient,\n uint256 amount,\n address messageSender,\n uint256 maxFee,\n uint256 feeExecuted,\n bytes memory hookData\n ) internal view returns (bytes memory) {\n bytes32 burnTokenBytes32 = bytes32(\n abi.encodePacked(bytes12(0), bytes20(uint160(address(usdc))))\n );\n bytes32 messageSenderBytes32 = bytes32(\n abi.encodePacked(bytes12(0), bytes20(uint160(messageSender)))\n );\n bytes32 expirationBlock = bytes32(0);\n\n // Ref: https://developers.circle.com/cctp/technical-guide#message-body\n return\n abi.encodePacked(\n uint32(1), // 0-3: version\n burnTokenBytes32, // 4-35: burnToken (bytes32 left-padded address)\n mintRecipient, // 36-67: mintRecipient (bytes32 left-padded address)\n amount, // 68-99: uint256 amount\n messageSenderBytes32, // 100-131: messageSender (bytes32 left-padded address)\n maxFee, // 132-163: uint256 maxFee\n feeExecuted, // 164-195: uint256 feeExecuted\n expirationBlock, // 196-227: bytes32 expirationBlock\n hookData // 228+: dynamic hookData\n );\n }\n\n function getMinFeeAmount(uint256 amount)\n external\n view\n override\n returns (uint256)\n {\n return 0;\n }\n}\n" + }, + "contracts/mocks/MockAutoWithdrawalVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultStorage } from \"../vault/VaultStorage.sol\";\n\ncontract MockAutoWithdrawalVault {\n address public asset;\n\n VaultStorage.WithdrawalQueueMetadata public withdrawalQueueMetadata;\n\n uint256 private _totalValue;\n bool private _revertNextWithdraw;\n bool private _revertNextDeposit;\n\n event MockedWithdrawal(address strategy, address asset, uint256 amount);\n event MockedDeposit(address strategy, address asset, uint256 amount);\n\n constructor(address _asset) {\n asset = _asset;\n }\n\n function setWithdrawalQueueMetadata(uint256 queued, uint256 claimable)\n external\n {\n withdrawalQueueMetadata.queued = uint128(queued);\n withdrawalQueueMetadata.claimable = uint128(claimable);\n }\n\n function revertNextWithdraw() external {\n _revertNextWithdraw = true;\n }\n\n function revertNextDeposit() external {\n _revertNextDeposit = true;\n }\n\n function setTotalValue(uint256 val) external {\n _totalValue = val;\n }\n\n function totalValue() external view returns (uint256) {\n return _totalValue;\n }\n\n function addWithdrawalQueueLiquidity() external {\n // Do nothing\n }\n\n function withdrawFromStrategy(\n address strategy,\n address[] memory assets,\n uint256[] memory amounts\n ) external {\n if (_revertNextWithdraw) {\n _revertNextWithdraw = false;\n revert(\"Mocked withdrawal revert\");\n }\n emit MockedWithdrawal(strategy, assets[0], amounts[0]);\n }\n\n function depositToStrategy(\n address strategy,\n address[] memory assets,\n uint256[] memory amounts\n ) external {\n if (_revertNextDeposit) {\n _revertNextDeposit = false;\n revert(\"Mocked deposit revert\");\n }\n emit MockedDeposit(strategy, assets[0], amounts[0]);\n }\n}\n" + }, + "contracts/mocks/MockLimitedWrappedOusd.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { WrappedOusd } from \"../token/WrappedOusd.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockLimitedWrappedOusd is WrappedOusd {\n constructor(ERC20 underlying_) WrappedOusd(underlying_) {}\n\n function maxDeposit(address)\n public\n view\n virtual\n override\n returns (uint256)\n {\n return 1e18;\n }\n}\n" + }, + "contracts/mocks/MockNonRebasing.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nimport { OUSD } from \"../token/OUSD.sol\";\n\ncontract MockNonRebasing {\n OUSD oUSD;\n\n function setOUSD(address _oUSDAddress) public {\n oUSD = OUSD(_oUSDAddress);\n }\n\n function rebaseOptIn() public {\n oUSD.rebaseOptIn();\n }\n\n function rebaseOptOut() public {\n oUSD.rebaseOptOut();\n }\n\n function transfer(address _to, uint256 _value) public {\n oUSD.transfer(_to, _value);\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public {\n oUSD.transferFrom(_from, _to, _value);\n }\n\n function approve(address _spender, uint256 _addedValue) public {\n oUSD.approve(_spender, _addedValue);\n }\n\n function mintOusd(address _vaultContract, uint256 _amount) public {\n IVault(_vaultContract).mint(_amount);\n }\n\n function redeemOusd(address _vaultContract, uint256 _amount) public {\n IVault(_vaultContract).requestWithdrawal(_amount);\n }\n\n function approveFor(\n address _contract,\n address _spender,\n uint256 _addedValue\n ) public {\n IERC20(_contract).approve(_spender, _addedValue);\n }\n}\n" + }, + "contracts/mocks/MockRebornMinter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n// solhint-disable-next-line no-console\nimport \"hardhat/console.sol\";\n\ncontract Sanctum {\n address public asset;\n address public vault;\n address public reborner;\n bool public shouldAttack = false;\n // should selfdestruct in the constructor\n bool public shouldDestruct = false;\n uint256 public targetMethod;\n address public ousdContract;\n\n constructor(address _asset, address _vault) {\n asset = _asset;\n vault = _vault;\n }\n\n function deploy(uint256 salt, bytes memory bytecode)\n public\n returns (address addr)\n {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)\n }\n require(addr != address(0), \"Create2: Failed on deploy\");\n }\n\n function computeAddress(uint256 salt, bytes memory bytecode)\n public\n view\n returns (address)\n {\n bytes32 bytecodeHashHash = keccak256(bytecode);\n bytes32 _data = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n bytecodeHashHash\n )\n );\n return address(bytes20(_data << 96));\n }\n\n function setShouldAttack(bool _shouldAttack) public {\n shouldAttack = _shouldAttack;\n }\n\n // should call selfdestruct in the constructor\n function setShouldDesctruct(bool _shouldDestruct) public {\n shouldDestruct = _shouldDestruct;\n }\n\n function setTargetMethod(uint256 target) public {\n targetMethod = target;\n }\n\n function setOUSDAddress(address _ousdContract) public {\n ousdContract = _ousdContract;\n }\n}\n\ncontract Reborner {\n Sanctum sanctum;\n bool logging = false;\n\n constructor(address _sanctum) {\n log(\"We are created...\");\n sanctum = Sanctum(_sanctum);\n if (sanctum.shouldAttack()) {\n log(\"We are attacking now...\");\n\n uint256 target = sanctum.targetMethod();\n\n if (target == 1) {\n redeem();\n } else if (target == 2) {\n transfer();\n } else {\n mint();\n }\n }\n\n if (sanctum.shouldDestruct()) {\n bye();\n }\n }\n\n function mint() public {\n log(\"We are attempting to mint..\");\n address asset = sanctum.asset();\n address vault = sanctum.vault();\n IERC20(asset).approve(vault, 1e6);\n IVault(vault).mint(1e6);\n log(\"We are now minting..\");\n }\n\n function redeem() public {\n log(\"We are attempting to request withdrawal..\");\n address vault = sanctum.vault();\n IVault(vault).requestWithdrawal(1e18);\n log(\"We are now requesting withdrawal..\");\n }\n\n function transfer() public {\n log(\"We are attempting to transfer..\");\n address ousd = sanctum.ousdContract();\n require(IERC20(ousd).transfer(address(1), 1e18), \"transfer failed\");\n log(\"We are now transfering..\");\n }\n\n function bye() public {\n log(\"We are now destructing..\");\n selfdestruct(payable(msg.sender));\n }\n\n function log(string memory message) internal view {\n if (logging) {\n // solhint-disable-next-line no-console\n console.log(message);\n }\n }\n}\n" + }, + "contracts/mocks/MockVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"../vault/VaultAdmin.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport \"../utils/Helpers.sol\";\n\ncontract MockVault is VaultAdmin {\n using StableMath for uint256;\n\n uint256 storedTotalValue;\n\n constructor(address _asset) VaultAdmin(_asset) {}\n\n function setTotalValue(uint256 _value) public {\n storedTotalValue = _value;\n }\n\n function totalValue() external view override returns (uint256) {\n return storedTotalValue;\n }\n\n function _totalValue() internal view override returns (uint256) {\n return storedTotalValue;\n }\n\n function _checkBalance(address _asset)\n internal\n view\n override\n returns (uint256 balance)\n {\n // Avoids rounding errors by returning the total value\n // in a single currency\n if (asset == _asset) {\n uint256 decimals = Helpers.getDecimals(_asset);\n return storedTotalValue.scaleBy(decimals, 18);\n } else {\n return 0;\n }\n }\n}\n" + }, + "contracts/mocks/MockVaultCoreInstantRebase.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultCore } from \"../vault/VaultCore.sol\";\n\ncontract MockVaultCoreInstantRebase is VaultCore {\n constructor(address _asset) VaultCore(_asset) {}\n\n function _nextYield(uint256 supply, uint256 vaultValue)\n internal\n view\n override\n returns (uint256 yield, uint256 targetRate)\n {\n if (vaultValue <= supply) {\n return (0, 0);\n }\n yield = vaultValue - supply;\n return (yield, 0);\n }\n}\n" + }, + "contracts/mocks/TestUpgradedOUSD.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../token/OUSD.sol\";\n\n// used to alter internal state of OUSD contract\ncontract TestUpgradedOUSD is OUSD {\n constructor() OUSD() {}\n\n function overwriteCreditBalances(address _account, uint256 _creditBalance)\n public\n {\n creditBalances[_account] = _creditBalance;\n }\n\n function overwriteAlternativeCPT(address _account, uint256 _acpt) public {\n alternativeCreditsPerToken[_account] = _acpt;\n }\n\n function overwriteRebaseState(address _account, RebaseOptions _rebaseOption)\n public\n {\n rebaseState[_account] = _rebaseOption;\n }\n}\n" + }, + "contracts/strategies/aerodrome/AerodromeAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Aerodrome AMO strategy\n * @author Origin Protocol Inc\n */\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\n\nimport { ISugarHelper } from \"../../interfaces/aerodrome/ISugarHelper.sol\";\nimport { INonfungiblePositionManager } from \"../../interfaces/aerodrome/INonfungiblePositionManager.sol\";\nimport { ISwapRouter } from \"../../interfaces/aerodrome/ISwapRouter.sol\";\nimport { ICLPool } from \"../../interfaces/aerodrome/ICLPool.sol\";\nimport { ICLGauge } from \"../../interfaces/aerodrome/ICLGauge.sol\";\nimport { IVault } from \"../../interfaces/IVault.sol\";\n\ncontract AerodromeAMOStrategy is InitializableAbstractStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n using SafeCast for uint256;\n\n /************************************************\n Important (!) setup configuration\n *************************************************/\n\n /**\n * In order to be able to remove a reasonable amount of complexity from the contract one of the\n * preconditions for this contract to function correctly is to have an outside account mint a small\n * amount of liquidity in the tick space where the contract will deploy's its liquidity and then send\n * that NFT LP position to a dead address (transfer to zero address not allowed.) See example of such\n * NFT LP token:\n * https://basescan.org/token/0x827922686190790b37229fd06084350e74485b72?a=413296#inventory\n */\n\n /***************************************\n Storage slot members\n ****************************************/\n\n /// @notice tokenId of the liquidity position\n uint256 public tokenId;\n /// @dev Minimum amount of tokens the strategy would be able to withdraw from the pool.\n /// minimum amount of tokens are withdrawn at a 1:1 price\n uint256 public underlyingAssets;\n /// @notice Marks the start of the interval that defines the allowed range of WETH share in\n /// the pre-configured pool's liquidity ticker\n uint256 public allowedWethShareStart;\n /// @notice Marks the end of the interval that defines the allowed range of WETH share in\n /// the pre-configured pool's liquidity ticker\n uint256 public allowedWethShareEnd;\n /// @dev reserved for inheritance\n int256[46] private __reserved;\n\n /***************************************\n Constants, structs and events\n ****************************************/\n\n /// @notice The address of the Wrapped ETH (WETH) token contract\n address public immutable WETH;\n /// @notice The address of the OETHb token contract\n address public immutable OETHb;\n /// @notice lower tick set to -1 representing the price of 1.0001 of WETH for 1 OETHb.\n int24 public immutable lowerTick;\n /// @notice lower tick set to 0 representing the price of 1.0000 of WETH for 1 OETHb.\n int24 public immutable upperTick;\n /// @notice tick spacing of the pool (set to 1)\n int24 public immutable tickSpacing;\n /// @notice the swapRouter for performing swaps\n ISwapRouter public immutable swapRouter;\n /// @notice the underlying AMO Slipstream pool\n ICLPool public immutable clPool;\n /// @notice the gauge for the corresponding Slipstream pool (clPool)\n /// @dev can become an immutable once the gauge is created on the base main-net\n ICLGauge public immutable clGauge;\n /// @notice the Position manager contract that is used to manage the pool's position\n INonfungiblePositionManager public immutable positionManager;\n /// @notice helper contract for liquidity and ticker math\n ISugarHelper public immutable helper;\n /// @notice sqrtRatioX96TickLower\n /// @dev tick lower has value -1 and represents the lowest price of WETH priced in OETHb. Meaning the pool\n /// offers less than 1 OETHb for 1 WETH. In other terms to get 1 OETHB the swap needs to offer 1.0001 WETH\n /// this is where purchasing OETHb with WETH within the liquidity position is most expensive\n uint160 public immutable sqrtRatioX96TickLower;\n /// @notice sqrtRatioX96TickHigher\n /// @dev tick higher has value 0 and represents 1:1 price parity of WETH to OETHb\n uint160 public immutable sqrtRatioX96TickHigher;\n /// @dev tick closest to 1:1 price parity\n /// Correctly assessing which tick is closer to 1:1 price parity is important since it affects\n /// the way we calculate the underlying assets in check Balance. The underlying aerodrome pool\n /// orders the tokens depending on the values of their addresses. If OETH token is token0 in the pool\n /// then sqrtRatioX96TickClosestToParity=sqrtRatioX96TickLower. If it is token1 in the pool then\n /// sqrtRatioX96TickClosestToParity=sqrtRatioX96TickHigher\n uint160 public immutable sqrtRatioX96TickClosestToParity;\n\n /// @dev a threshold under which the contract no longer allows for the protocol to rebalance. Guarding\n /// against a strategist / guardian being taken over and with multiple transactions draining the\n /// protocol funds.\n uint256 public constant SOLVENCY_THRESHOLD = 0.998 ether;\n\n error NotEnoughWethForSwap(uint256 wethBalance, uint256 requiredWeth); // 0x989e5ca8\n error NotEnoughWethLiquidity(uint256 wethBalance, uint256 requiredWeth); // 0xa6737d87\n error PoolRebalanceOutOfBounds(\n uint256 currentPoolWethShare,\n uint256 allowedWethShareStart,\n uint256 allowedWethShareEnd\n ); // 0x3681e8e0\n error OutsideExpectedTickRange(int24 currentTick); // 0x5a2eba75\n\n event PoolRebalanced(uint256 currentPoolWethShare);\n\n event PoolWethShareIntervalUpdated(\n uint256 allowedWethShareStart,\n uint256 allowedWethShareEnd\n );\n\n event LiquidityRemoved(\n uint256 withdrawLiquidityShare,\n uint256 removedWETHAmount,\n uint256 removedOETHbAmount,\n uint256 wethAmountCollected,\n uint256 oethbAmountCollected,\n uint256 underlyingAssets\n );\n\n event LiquidityAdded(\n uint256 wethAmountDesired,\n uint256 oethbAmountDesired,\n uint256 wethAmountSupplied,\n uint256 oethbAmountSupplied,\n uint256 tokenId,\n uint256 underlyingAssets\n );\n\n event UnderlyingAssetsUpdated(uint256 underlyingAssets);\n\n /**\n * @dev Un-stakes the token from the gauge for the execution duration of\n * the function and after that re-stakes it back in.\n *\n * It is important that the token is unstaked and owned by the strategy contract\n * during any liquidity altering operations and that it is re-staked back into the\n * gauge after liquidity changes. If the token fails to re-stake back to the\n * gauge it is not earning incentives.\n */\n // all functions using this modifier are used by functions with reentrancy check\n // slither-disable-start reentrancy-no-eth\n modifier gaugeUnstakeAndRestake() {\n // because of solidity short-circuit _isLpTokenStakedInGauge doesn't get called\n // when tokenId == 0\n if (tokenId != 0 && _isLpTokenStakedInGauge()) {\n clGauge.withdraw(tokenId);\n }\n _;\n // because of solidity short-circuit _isLpTokenStakedInGauge doesn't get called\n // when tokenId == 0\n if (tokenId != 0 && !_isLpTokenStakedInGauge()) {\n /**\n * It can happen that a withdrawal (or a full withdrawal) transactions would\n * remove all of the liquidity from the token with a NFT token still existing.\n * In that case the token can not be staked into the gauge, as some liquidity\n * needs to be added to it first.\n */\n if (_getLiquidity() > 0) {\n // if token liquidity changes the positionManager requires re-approval.\n // to any contract pre-approved to handle the token.\n positionManager.approve(address(clGauge), tokenId);\n clGauge.deposit(tokenId);\n }\n }\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice the constructor\n /// @dev This contract is intended to be used as a proxy. To prevent the\n /// potential confusion of having a functional implementation contract\n /// the constructor has the `initializer` modifier. This way the\n /// `initialize` function can not be called on the implementation contract.\n /// For the same reason the implementation contract also has the governor\n /// set to a zero address.\n /// @param _stratConfig the basic strategy configuration\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _oethbAddress Address of the Erc20 OETHb Token contract\n /// @param _swapRouter Address of the Aerodrome Universal Swap Router\n /// @param _nonfungiblePositionManager Address of position manager to add/remove\n /// the liquidity\n /// @param _clPool Address of the Aerodrome concentrated liquidity pool\n /// @param _clGauge Address of the Aerodrome slipstream pool gauge\n /// @param _sugarHelper Address of the Aerodrome Sugar helper contract\n /// @param _lowerBoundingTick Smaller bounding tick of our liquidity position\n /// @param _upperBoundingTick Larger bounding tick of our liquidity position\n /// @param _tickClosestToParity Tick that is closer to 1:1 price parity\n constructor(\n BaseStrategyConfig memory _stratConfig,\n address _wethAddress,\n address _oethbAddress,\n address _swapRouter,\n address _nonfungiblePositionManager,\n address _clPool,\n address _clGauge,\n address _sugarHelper,\n int24 _lowerBoundingTick,\n int24 _upperBoundingTick,\n int24 _tickClosestToParity\n ) initializer InitializableAbstractStrategy(_stratConfig) {\n require(\n _lowerBoundingTick == _tickClosestToParity ||\n _upperBoundingTick == _tickClosestToParity,\n \"Misconfigured tickClosestToParity\"\n );\n require(\n ICLPool(_clPool).token0() == _wethAddress,\n \"Only WETH supported as token0\"\n );\n require(\n ICLPool(_clPool).token1() == _oethbAddress,\n \"Only OETHb supported as token1\"\n );\n int24 _tickSpacing = ICLPool(_clPool).tickSpacing();\n // when we generalize AMO we might support other tick spacings\n require(_tickSpacing == 1, \"Unsupported tickSpacing\");\n\n WETH = _wethAddress;\n OETHb = _oethbAddress;\n swapRouter = ISwapRouter(_swapRouter);\n positionManager = INonfungiblePositionManager(\n _nonfungiblePositionManager\n );\n clPool = ICLPool(_clPool);\n clGauge = ICLGauge(_clGauge);\n helper = ISugarHelper(_sugarHelper);\n sqrtRatioX96TickLower = ISugarHelper(_sugarHelper).getSqrtRatioAtTick(\n _lowerBoundingTick\n );\n sqrtRatioX96TickHigher = ISugarHelper(_sugarHelper).getSqrtRatioAtTick(\n _upperBoundingTick\n );\n sqrtRatioX96TickClosestToParity = ISugarHelper(_sugarHelper)\n .getSqrtRatioAtTick(_tickClosestToParity);\n\n lowerTick = _lowerBoundingTick;\n upperTick = _upperBoundingTick;\n tickSpacing = _tickSpacing;\n\n // prevent implementation contract to be governed\n _setGovernor(address(0));\n }\n\n /**\n * @notice initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n */\n function initialize(address[] memory _rewardTokenAddresses)\n external\n onlyGovernor\n initializer\n {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n new address[](0),\n new address[](0)\n );\n }\n\n /***************************************\n Configuration \n ****************************************/\n\n /**\n * @notice Set allowed pool weth share interval. After the rebalance happens\n * the share of WETH token in the ticker needs to be withing the specifications\n * of the interval.\n *\n * @param _allowedWethShareStart Start of WETH share interval expressed as 18 decimal amount\n * @param _allowedWethShareEnd End of WETH share interval expressed as 18 decimal amount\n */\n function setAllowedPoolWethShareInterval(\n uint256 _allowedWethShareStart,\n uint256 _allowedWethShareEnd\n ) external onlyGovernor {\n require(\n _allowedWethShareStart < _allowedWethShareEnd,\n \"Invalid interval\"\n );\n // can not go below 1% weth share\n require(_allowedWethShareStart > 0.01 ether, \"Invalid interval start\");\n // can not go above 95% weth share\n require(_allowedWethShareEnd < 0.95 ether, \"Invalid interval end\");\n\n allowedWethShareStart = _allowedWethShareStart;\n allowedWethShareEnd = _allowedWethShareEnd;\n emit PoolWethShareIntervalUpdated(\n allowedWethShareStart,\n allowedWethShareEnd\n );\n }\n\n /***************************************\n Periphery utils\n ****************************************/\n\n function _isLpTokenStakedInGauge() internal view returns (bool) {\n require(tokenId != 0, \"Missing NFT LP token\");\n\n address owner = positionManager.ownerOf(tokenId);\n require(\n owner == address(clGauge) || owner == address(this),\n \"Unexpected token owner\"\n );\n return owner == address(clGauge);\n }\n\n /***************************************\n Strategy overrides \n ****************************************/\n\n /**\n * @notice Deposit an amount of assets into the strategy contract. Calling deposit doesn't\n * automatically deposit funds into the underlying Aerodrome pool\n * @param _asset Address for the asset\n * @param _amount Units of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /**\n * @notice Deposit WETH to the strategy contract. This function does not add liquidity to the\n * underlying Aerodrome pool.\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 _wethBalance = IERC20(WETH).balanceOf(address(this));\n if (_wethBalance > 1e12) {\n _deposit(WETH, _wethBalance);\n }\n }\n\n /**\n * @dev Deposit WETH to the contract. This function doesn't deposit the liquidity to the\n * pool, that is done via the rebalance call.\n * @param _asset Address of the asset to deposit\n * @param _amount Amount of assets to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal {\n require(_asset == WETH, \"Unsupported asset\");\n require(_amount > 0, \"Must deposit something\");\n emit Deposit(_asset, address(0), _amount);\n\n // if the pool price is not within the expected interval leave the WETH on the contract\n // as to not break the mints\n (bool _isExpectedRange, ) = _checkForExpectedPoolPrice(false);\n if (_isExpectedRange) {\n // deposit funds into the underlying pool\n _rebalance(0, false, 0);\n }\n }\n\n /**\n * @notice Rebalance the pool to the desired token split and Deposit any WETH on the contract to the\n * underlying aerodrome pool. Print the required amount of corresponding OETHb. After the rebalancing is\n * done burn any potentially remaining OETHb tokens still on the strategy contract.\n *\n * This function has a slightly different behaviour depending on the status of the underlying Aerodrome\n * slipstream pool. The function consists of the following 3 steps:\n * 1. withdrawPartialLiquidity -> so that moving the activeTrading price via a swap is cheaper\n * 2. swapToDesiredPosition -> move active trading price in the pool to be able to deposit WETH & OETHb\n * tokens with the desired pre-configured shares\n * 3. addLiquidity -> add liquidity into the pool respecting share split configuration\n *\n * Scenario 1: When there is no liquidity in the pool from the strategy but there is from other LPs then\n * only step 1 is skipped. (It is important to note that liquidity needs to exist in the configured\n * strategy tick ranges in order for the swap to be possible) Step 3 mints new liquidity position\n * instead of adding to an existing one.\n * Scenario 2: When there is strategy's liquidity in the pool all 3 steps are taken\n *\n *\n * Exact _amountToSwap, _swapWeth & _minTokenReceived parameters shall be determined by simulating the\n * transaction off-chain. The strategy checks that after the swap the share of the tokens is in the\n * expected ranges.\n *\n * @param _amountToSwap The amount of the token to swap\n * @param _swapWeth Swap using WETH when true, use OETHb when false\n * @param _minTokenReceived Slippage check -> minimum amount of token expected in return\n */\n function rebalance(\n uint256 _amountToSwap,\n bool _swapWeth,\n uint256 _minTokenReceived\n ) external nonReentrant onlyGovernorOrStrategist {\n _rebalance(_amountToSwap, _swapWeth, _minTokenReceived);\n }\n\n function _rebalance(\n uint256 _amountToSwap,\n bool _swapWeth,\n uint256 _minTokenReceived\n ) internal {\n /**\n * Would be nice to check if there is any total liquidity in the pool before performing this swap\n * but there is no easy way to do that in UniswapV3:\n * - clPool.liquidity() -> only liquidity in the active tick\n * - asset[1&2].balanceOf(address(clPool)) -> will include uncollected tokens of LP providers\n * after their liquidity position has been decreased\n */\n\n /**\n * When rebalance is called for the first time there is no strategy\n * liquidity in the pool yet. The liquidity removal is thus skipped.\n * Also execute this function when WETH is required for the swap.\n */\n if (tokenId != 0 && _swapWeth && _amountToSwap > 0) {\n _ensureWETHBalance(_amountToSwap);\n }\n\n // in some cases we will just want to add liquidity and not issue a swap to move the\n // active trading position within the pool\n if (_amountToSwap > 0) {\n _swapToDesiredPosition(_amountToSwap, _swapWeth, _minTokenReceived);\n }\n // calling check liquidity early so we don't get unexpected errors when adding liquidity\n // in the later stages of this function\n _checkForExpectedPoolPrice(true);\n\n _addLiquidity();\n\n // this call shouldn't be necessary, since adding liquidity shouldn't affect the active\n // trading price. It is a defensive programming measure.\n (, uint256 _wethSharePct) = _checkForExpectedPoolPrice(true);\n\n // revert if protocol insolvent\n _solvencyAssert();\n\n emit PoolRebalanced(_wethSharePct);\n }\n\n /**\n * Checks that the protocol is solvent, protecting from a rogue Strategist / Guardian that can\n * keep rebalancing the pool in both directions making the protocol lose a tiny amount of\n * funds each time.\n *\n * Protocol must be at least SOLVENCY_THRESHOLD (99,8 %) backed in order for the rebalances to\n * function.\n */\n function _solvencyAssert() internal view {\n uint256 _totalVaultValue = IVault(vaultAddress).totalValue();\n uint256 _totalOethbSupply = IERC20(OETHb).totalSupply();\n\n if (\n _totalVaultValue.divPrecisely(_totalOethbSupply) <\n SOLVENCY_THRESHOLD\n ) {\n revert(\"Protocol insolvent\");\n }\n }\n\n /**\n * @dev Decrease partial or all liquidity from the pool.\n * @param _liquidityToDecrease The amount of liquidity to remove expressed in 18 decimal point\n */\n function _removeLiquidity(uint256 _liquidityToDecrease)\n internal\n gaugeUnstakeAndRestake\n {\n require(_liquidityToDecrease > 0, \"Must remove some liquidity\");\n\n uint128 _liquidity = _getLiquidity();\n // need to convert to uint256 since intermittent result is to big for uint128 to handle\n uint128 _liquidityToRemove = uint256(_liquidity)\n .mulTruncate(_liquidityToDecrease)\n .toUint128();\n\n /**\n * There is no liquidity to remove -> exit function early. This can happen after a\n * withdraw/withdrawAll removes all of the liquidity while retaining the NFT token.\n */\n if (_liquidity == 0 || _liquidityToRemove == 0) {\n return;\n }\n\n (uint256 _amountWeth, uint256 _amountOethb) = positionManager\n .decreaseLiquidity(\n // Both expected amounts can be 0 since we don't really care if any swaps\n // happen just before the liquidity removal.\n INonfungiblePositionManager.DecreaseLiquidityParams({\n tokenId: tokenId,\n liquidity: _liquidityToRemove,\n amount0Min: 0,\n amount1Min: 0,\n deadline: block.timestamp\n })\n );\n\n (\n uint256 _amountWethCollected,\n uint256 _amountOethbCollected\n ) = positionManager.collect(\n INonfungiblePositionManager.CollectParams({\n tokenId: tokenId,\n recipient: address(this),\n amount0Max: type(uint128).max, // defaults to all tokens owed\n amount1Max: type(uint128).max // defaults to all tokens owed\n })\n );\n\n _updateUnderlyingAssets();\n\n emit LiquidityRemoved(\n _liquidityToDecrease,\n _amountWeth, //removedWethAmount\n _amountOethb, //removedOethbAmount\n _amountWethCollected,\n _amountOethbCollected,\n underlyingAssets\n );\n\n _burnOethbOnTheContract();\n }\n\n /**\n * @dev Perform a swap so that after the swap the ticker has the desired WETH to OETHb token share.\n */\n function _swapToDesiredPosition(\n uint256 _amountToSwap,\n bool _swapWeth,\n uint256 _minTokenReceived\n ) internal {\n IERC20 _tokenToSwap = IERC20(_swapWeth ? WETH : OETHb);\n uint256 _balance = _tokenToSwap.balanceOf(address(this));\n\n if (_balance < _amountToSwap) {\n // This should never trigger since _ensureWETHBalance will already\n // throw an error if there is not enough WETH\n if (_swapWeth) {\n revert NotEnoughWethForSwap(_balance, _amountToSwap);\n }\n // if swapping OETHb\n uint256 mintForSwap = _amountToSwap - _balance;\n IVault(vaultAddress).mintForStrategy(mintForSwap);\n }\n\n // approve the specific amount of WETH required\n if (_swapWeth) {\n IERC20(WETH).approve(address(swapRouter), _amountToSwap);\n }\n\n // Swap it\n swapRouter.exactInputSingle(\n // sqrtPriceLimitX96 is just a rough sanity check that we are within 0 -> 1 tick\n // a more fine check is performed in _checkForExpectedPoolPrice\n // Note: this needs further work if we want to generalize this approach\n ISwapRouter.ExactInputSingleParams({\n tokenIn: address(_tokenToSwap),\n tokenOut: _swapWeth ? OETHb : WETH,\n tickSpacing: tickSpacing, // set to 1\n recipient: address(this),\n deadline: block.timestamp,\n amountIn: _amountToSwap,\n amountOutMinimum: _minTokenReceived, // slippage check\n sqrtPriceLimitX96: _swapWeth\n ? sqrtRatioX96TickLower\n : sqrtRatioX96TickHigher\n })\n );\n\n /**\n * In the interest of each function in _rebalance to leave the contract state as\n * clean as possible the OETHb tokens here are burned. This decreases the\n * dependence where `_swapToDesiredPosition` function relies on later functions\n * (`addLiquidity`) to burn the OETHb. Reducing the risk of error introduction.\n */\n _burnOethbOnTheContract();\n }\n\n /**\n * @dev Add liquidity into the pool in the pre-configured WETH to OETHb share ratios\n * defined by the allowedPoolWethShareStart|End interval. This function will respect\n * liquidity ratios when there is no liquidity yet in the pool. If liquidity is already\n * present then it relies on the `_swapToDesiredPosition` function in a step before\n * to already move the trading price to desired position (with some tolerance).\n */\n // rebalance already has re-entrency checks\n // slither-disable-start reentrancy-no-eth\n function _addLiquidity() internal gaugeUnstakeAndRestake {\n uint256 _wethBalance = IERC20(WETH).balanceOf(address(this));\n uint256 _oethbBalance = IERC20(OETHb).balanceOf(address(this));\n // don't deposit small liquidity amounts\n if (_wethBalance <= 1e12) {\n return;\n }\n\n uint160 _currentPrice = getPoolX96Price();\n /**\n * Sanity check active trading price is positioned within our desired tick.\n *\n * We revert when price is equal to the lower tick even though that is still\n * a valid amount in regards to ticker position by Sugar.estimateAmount call.\n * Current price equaling tick bound at the 1:1 price parity results in\n * uint overfow when calculating the OETHb balance to deposit.\n */\n if (\n _currentPrice <= sqrtRatioX96TickLower ||\n _currentPrice >= sqrtRatioX96TickHigher\n ) {\n revert OutsideExpectedTickRange(getCurrentTradingTick());\n }\n\n /**\n * If estimateAmount1 call fails it could be due to _currentPrice being really\n * close to a tick and amount1 is a larger number than the sugar helper is able\n * to compute.\n *\n * If token addresses were reversed estimateAmount0 would be required here\n */\n uint256 _oethbRequired = helper.estimateAmount1(\n _wethBalance,\n address(0), // no need to pass pool address when current price is specified\n _currentPrice,\n lowerTick,\n upperTick\n );\n\n if (_oethbRequired > _oethbBalance) {\n IVault(vaultAddress).mintForStrategy(\n _oethbRequired - _oethbBalance\n );\n }\n\n // approve the specific amount of WETH required\n IERC20(WETH).approve(address(positionManager), _wethBalance);\n\n uint256 _wethAmountSupplied;\n uint256 _oethbAmountSupplied;\n if (tokenId == 0) {\n (\n tokenId,\n ,\n _wethAmountSupplied,\n _oethbAmountSupplied\n ) = positionManager.mint(\n /** amount0Min & amount1Min are left at 0 because slippage protection is ensured by the\n * _checkForExpectedPoolPrice\n *›\n * Also sqrtPriceX96 is 0 because the pool is already created\n * non zero amount attempts to create a new instance of the pool\n */\n INonfungiblePositionManager.MintParams({\n token0: WETH,\n token1: OETHb,\n tickSpacing: tickSpacing,\n tickLower: lowerTick,\n tickUpper: upperTick,\n amount0Desired: _wethBalance,\n amount1Desired: _oethbRequired,\n amount0Min: 0,\n amount1Min: 0,\n recipient: address(this),\n deadline: block.timestamp,\n sqrtPriceX96: 0\n })\n );\n } else {\n (, _wethAmountSupplied, _oethbAmountSupplied) = positionManager\n .increaseLiquidity(\n /** amount0Min & amount1Min are left at 0 because slippage protection is ensured by the\n * _checkForExpectedPoolPrice\n */\n INonfungiblePositionManager.IncreaseLiquidityParams({\n tokenId: tokenId,\n amount0Desired: _wethBalance,\n amount1Desired: _oethbRequired,\n amount0Min: 0,\n amount1Min: 0,\n deadline: block.timestamp\n })\n );\n }\n\n _updateUnderlyingAssets();\n emit LiquidityAdded(\n _wethBalance, // wethAmountDesired\n _oethbRequired, // oethbAmountDesired\n _wethAmountSupplied, // wethAmountSupplied\n _oethbAmountSupplied, // oethbAmountSupplied\n tokenId, // tokenId\n underlyingAssets\n );\n\n // burn remaining OETHb\n _burnOethbOnTheContract();\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /**\n * @dev Check that the Aerodrome pool price is within the expected\n * parameters.\n * This function works whether the strategy contract has liquidity\n * position in the pool or not. The function returns _wethSharePct\n * as a gas optimization measure.\n * @param throwException when set to true the function throws an exception\n * when pool's price is not within expected range.\n * @return _isExpectedRange Bool expressing price is within expected range\n * @return _wethSharePct Share of WETH owned by this strategy contract in the\n * configured ticker.\n */\n function _checkForExpectedPoolPrice(bool throwException)\n internal\n view\n returns (bool _isExpectedRange, uint256 _wethSharePct)\n {\n require(\n allowedWethShareStart != 0 && allowedWethShareEnd != 0,\n \"Weth share interval not set\"\n );\n\n uint160 _currentPrice = getPoolX96Price();\n\n /**\n * First check we are in expected tick range\n *\n * We revert even though price being equal to the lower tick would still\n * count being within lower tick for the purpose of Sugar.estimateAmount calls\n */\n if (\n _currentPrice <= sqrtRatioX96TickLower ||\n _currentPrice >= sqrtRatioX96TickHigher\n ) {\n if (throwException) {\n revert OutsideExpectedTickRange(getCurrentTradingTick());\n }\n return (false, 0);\n }\n\n // 18 decimal number expressed WETH tick share\n _wethSharePct = _getWethShare(_currentPrice);\n\n if (\n _wethSharePct < allowedWethShareStart ||\n _wethSharePct > allowedWethShareEnd\n ) {\n if (throwException) {\n revert PoolRebalanceOutOfBounds(\n _wethSharePct,\n allowedWethShareStart,\n allowedWethShareEnd\n );\n }\n return (false, _wethSharePct);\n }\n\n return (true, _wethSharePct);\n }\n\n /**\n * Burns any OETHb tokens remaining on the strategy contract\n */\n function _burnOethbOnTheContract() internal {\n uint256 _oethbBalance = IERC20(OETHb).balanceOf(address(this));\n if (_oethbBalance > 1e12) {\n IVault(vaultAddress).burnForStrategy(_oethbBalance);\n }\n }\n\n /// @dev This function assumes there are no uncollected tokens in the clPool owned by the strategy contract.\n /// For that reason any liquidity withdrawals must also collect the tokens.\n function _updateUnderlyingAssets() internal {\n if (tokenId == 0) {\n underlyingAssets = 0;\n emit UnderlyingAssetsUpdated(underlyingAssets);\n return;\n }\n\n uint128 _liquidity = _getLiquidity();\n\n /**\n * Our net value represent the smallest amount of tokens we are able to extract from the position\n * given our liquidity.\n *\n * The least amount of tokens extraditable from the position is where the active trading price is\n * at the ticker 0 meaning the pool is offering 1:1 trades between WETH & OETHb. At that moment the pool\n * consists completely of OETHb and no WETH.\n *\n * The more swaps from WETH -> OETHb happen on the pool the more the price starts to move towards the -1\n * ticker making OETHb (priced in WETH) more expensive.\n *\n * An additional note: when liquidity is 0 then the helper returns 0 for both token amounts. And the\n * function set underlying assets to 0.\n */\n (uint256 _wethAmount, uint256 _oethbAmount) = helper\n .getAmountsForLiquidity(\n sqrtRatioX96TickClosestToParity, // sqrtRatioX96\n sqrtRatioX96TickLower, // sqrtRatioAX96\n sqrtRatioX96TickHigher, // sqrtRatioBX96\n _liquidity\n );\n\n require(_wethAmount == 0, \"Non zero wethAmount\");\n underlyingAssets = _oethbAmount;\n emit UnderlyingAssetsUpdated(underlyingAssets);\n }\n\n /**\n * @dev This function removes the appropriate amount of liquidity to assure that the required\n * amount of WETH is available on the contract\n *\n * @param _amount WETH balance required on the contract\n */\n function _ensureWETHBalance(uint256 _amount) internal {\n uint256 _wethBalance = IERC20(WETH).balanceOf(address(this));\n if (_wethBalance >= _amount) {\n return;\n }\n\n require(tokenId != 0, \"No liquidity available\");\n uint256 _additionalWethRequired = _amount - _wethBalance;\n (uint256 _wethInThePool, ) = getPositionPrincipal();\n\n if (_wethInThePool < _additionalWethRequired) {\n revert NotEnoughWethLiquidity(\n _wethInThePool,\n _additionalWethRequired\n );\n }\n\n uint256 shareOfWethToRemove = Math.min(\n _additionalWethRequired.divPrecisely(_wethInThePool) + 1,\n 1e18\n );\n _removeLiquidity(shareOfWethToRemove);\n }\n\n /**\n * @notice Withdraw an `amount` of assets from the platform and\n * send to the `_recipient`.\n * @param _recipient Address to which the asset should be sent\n * @param _asset WETH address\n * @param _amount Amount of WETH to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_asset == WETH, \"Unsupported asset\");\n require(_recipient == vaultAddress, \"Only withdraw to vault allowed\");\n\n _ensureWETHBalance(_amount);\n\n _withdraw(_recipient, _amount);\n }\n\n /**\n * @notice Withdraw WETH and sends it to the Vault.\n */\n function withdrawAll() external override onlyVault nonReentrant {\n if (tokenId != 0) {\n _removeLiquidity(1e18);\n }\n\n uint256 _balance = IERC20(WETH).balanceOf(address(this));\n if (_balance > 0) {\n _withdraw(vaultAddress, _balance);\n }\n }\n\n function _withdraw(address _recipient, uint256 _amount) internal {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient == vaultAddress, \"Only withdraw to vault allowed\");\n\n IERC20(WETH).safeTransfer(_recipient, _amount);\n emit Withdrawal(WETH, address(0), _amount);\n }\n\n /**\n * @dev Collect the AERO token from the gauge\n */\n function _collectRewardTokens() internal override {\n if (tokenId != 0 && _isLpTokenStakedInGauge()) {\n clGauge.getReward(tokenId);\n }\n super._collectRewardTokens();\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == WETH;\n }\n\n /**\n * @dev Approve the spending of all assets\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n // to add liquidity to the clPool\n IERC20(OETHb).approve(address(positionManager), type(uint256).max);\n // to be able to rebalance using the swapRouter\n IERC20(OETHb).approve(address(swapRouter), type(uint256).max);\n\n /* the behaviour of this strategy has slightly changed and WETH could be\n * present on the contract between the transactions. For that reason we are\n * un-approving WETH to the swapRouter & positionManager and only approving\n * the required amount before a transaction\n */\n IERC20(WETH).approve(address(swapRouter), 0);\n IERC20(WETH).approve(address(positionManager), 0);\n }\n\n /***************************************\n Balances and Fees\n ****************************************/\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256)\n {\n require(_asset == WETH, \"Only WETH supported\");\n\n // we could in theory deposit to the strategy and forget to call rebalance in the same\n // governance transaction batch. In that case the WETH that is on the strategy contract\n // also needs to be accounted for.\n uint256 _wethBalance = IERC20(WETH).balanceOf(address(this));\n // just paranoia check, in case there is OETHb in the strategy that for some reason hasn't\n // been burned yet.\n uint256 _oethbBalance = IERC20(OETHb).balanceOf(address(this));\n return underlyingAssets + _wethBalance + _oethbBalance;\n }\n\n /**\n * @dev Returns the balance of both tokens in a given position (excluding fees)\n * @return _amountWeth Amount of WETH in position\n * @return _amountOethb Amount of OETHb in position\n */\n function getPositionPrincipal()\n public\n view\n returns (uint256 _amountWeth, uint256 _amountOethb)\n {\n if (tokenId == 0) {\n return (0, 0);\n }\n\n uint160 _sqrtRatioX96 = getPoolX96Price();\n (_amountWeth, _amountOethb) = helper.principal(\n positionManager,\n tokenId,\n _sqrtRatioX96\n );\n }\n\n /**\n * @notice Returns the current pool price in X96 format\n * @return _sqrtRatioX96 Pool price\n */\n function getPoolX96Price() public view returns (uint160 _sqrtRatioX96) {\n (_sqrtRatioX96, , , , , ) = clPool.slot0();\n }\n\n /**\n * @notice Returns the current active trading tick of the underlying pool\n * @return _currentTick Current pool trading tick\n */\n function getCurrentTradingTick() public view returns (int24 _currentTick) {\n (, _currentTick, , , , ) = clPool.slot0();\n }\n\n /**\n * @notice Returns the percentage of WETH liquidity in the configured ticker\n * owned by this strategy contract.\n * @return uint256 1e18 denominated percentage expressing the share\n */\n function getWETHShare() external view returns (uint256) {\n uint160 _currentPrice = getPoolX96Price();\n return _getWethShare(_currentPrice);\n }\n\n /**\n * @notice Returns the amount of liquidity in the contract's LP position\n * @return _liquidity Amount of liquidity in the position\n */\n function _getLiquidity() internal view returns (uint128 _liquidity) {\n if (tokenId == 0) {\n revert(\"No LP position\");\n }\n\n (, , , , , , , _liquidity, , , , ) = positionManager.positions(tokenId);\n }\n\n function _getWethShare(uint160 _currentPrice)\n internal\n view\n returns (uint256)\n {\n /**\n * If estimateAmount1 call fails it could be due to _currentPrice being really\n * close to a tick and amount1 too big to compute.\n *\n * If token addresses were reversed estimateAmount0 would be required here\n */\n uint256 _normalizedWethAmount = 1 ether;\n uint256 _correspondingOethAmount = helper.estimateAmount1(\n _normalizedWethAmount,\n address(0), // no need to pass pool address when current price is specified\n _currentPrice,\n lowerTick,\n upperTick\n );\n\n // 18 decimal number expressed weth tick share\n return\n _normalizedWethAmount.divPrecisely(\n _normalizedWethAmount + _correspondingOethAmount\n );\n }\n\n /***************************************\n Hidden functions\n ****************************************/\n /// @inheritdoc InitializableAbstractStrategy\n function setPTokenAddress(address, address) external override {\n // The pool tokens can never change.\n revert(\"Unsupported method\");\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function removePToken(uint256) external override {\n // The pool tokens can never change.\n revert(\"Unsupported method\");\n }\n\n /**\n * @dev Not supported\n */\n function _abstractSetPToken(address, address) internal override {\n // the deployer shall call safeApproveAllTokens() to set necessary approvals\n revert(\"Unsupported method\");\n }\n\n /***************************************\n ERC721 management\n ****************************************/\n\n /// @notice Callback function for whenever a NFT is transferred to this contract\n // solhint-disable-next-line max-line-length\n /// Ref: https://docs.openzeppelin.com/contracts/3.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-\n function onERC721Received(\n address,\n address,\n uint256,\n bytes calldata\n ) external returns (bytes4) {\n return this.onERC721Received.selector;\n }\n}\n" + }, + "contracts/strategies/algebra/OETHSupernovaAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Supernova OETH Algorithmic Market Maker (AMO) Strategy\n * @notice AMO strategy for the Supernova OETH/WETH stable pool\n * @author Origin Protocol Inc\n */\nimport { StableSwapAMMStrategy } from \"./StableSwapAMMStrategy.sol\";\nimport { IGauge } from \"../../interfaces/algebra/IAlgebraGauge.sol\";\n\ncontract OETHSupernovaAMOStrategy is StableSwapAMMStrategy {\n /**\n * @param _baseConfig The `platformAddress` is the address of the Supernova OETH/WETH pool.\n * The `vaultAddress` is the address of the OETH Vault.\n * @param _gauge Address of the Supernova gauge for the pool.\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _gauge)\n StableSwapAMMStrategy(_baseConfig, _gauge, IGauge(_gauge).TOKEN())\n {}\n}\n" + }, + "contracts/strategies/algebra/StableSwapAMMStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Algebra Algorithmic Market Maker (AMO) Strategy\n * @notice AMO strategy for the Algebra stable swap pool\n * @author Origin Protocol Inc\n */\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\nimport { sqrt } from \"../../utils/PRBMath.sol\";\nimport { IBasicToken } from \"../../interfaces/IBasicToken.sol\";\nimport { IPair } from \"../../interfaces/algebra/IAlgebraPair.sol\";\nimport { IGauge } from \"../../interfaces/algebra/IAlgebraGauge.sol\";\nimport { IVault } from \"../../interfaces/IVault.sol\";\n\ncontract StableSwapAMMStrategy is InitializableAbstractStrategy {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n using SafeCast for uint256;\n\n /**\n * @notice a threshold under which the contract no longer allows for the protocol to manually rebalance.\n * Guarding against a strategist / guardian being taken over and with multiple transactions\n * draining the protocol funds.\n */\n uint256 public constant SOLVENCY_THRESHOLD = 0.998 ether;\n\n /// @notice Precision for the Algebra Stable AMM (sAMM) invariant k.\n uint256 public constant PRECISION = 1e18;\n\n /// @notice Address of the asset (non OToken) token contract\n address public immutable asset;\n\n /// @notice Address of the OToken token contract.\n address public immutable oToken;\n\n /// @notice Address of the Algebra Stable pool contract.\n address public immutable pool;\n\n /// @notice Address of the Algebra Gauge contract.\n address public immutable gauge;\n\n /// @notice Index of the OToken in the Algebra pool.\n uint256 public immutable oTokenPoolIndex;\n\n /// @notice The max amount the OToken/asset price can deviate from peg (1e18)\n /// before deposits are reverted scaled to 18 decimals.\n /// eg 0.01e18 or 1e16 is 1% which is 100 basis points.\n /// This is the amount below and above peg so a 50 basis point deviation (0.005e18)\n /// allows a price range from 0.995 to 1.005.\n uint256 public maxDepeg;\n\n event SwapOTokensToPool(\n uint256 oTokenMinted,\n uint256 assetDepositAmount,\n uint256 oTokenDepositAmount,\n uint256 lpTokens\n );\n event SwapAssetsToPool(\n uint256 assetSwapped,\n uint256 lpTokens,\n uint256 oTokenBurnt\n );\n event MaxDepegUpdated(uint256 maxDepeg);\n\n /**\n * @dev Verifies that the caller is the Strategist of the Vault.\n */\n modifier onlyStrategist() {\n require(\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n _;\n }\n\n /**\n * @dev Skim the Algebra pool in case any extra asset or OToken tokens were added\n */\n modifier skimPool() {\n IPair(pool).skim(address(this));\n _;\n }\n\n /**\n * @dev Checks the pool is balanced enough to allow deposits.\n */\n modifier nearBalancedPool() {\n // OToken/asset price = asset / OToken\n // Get the OToken/asset price for selling 1 OToken for asset\n // As OToken is 1, the asset amount is the OToken/asset price\n uint256 sellPrice = IPair(pool).getAmountOut(1e18, oToken);\n\n // Get the amount of OToken received from selling 1 asset. This is buying OToken.\n uint256 oTokenAmount = IPair(pool).getAmountOut(1e18, asset);\n\n // If the pool is degenerate, then the pool is not valid and we can't deposit.\n require(oTokenAmount > 0, \"Pool degenerate\");\n\n // Convert to a OToken/asset price = asset / OToken\n uint256 buyPrice = 1e36 / oTokenAmount;\n\n uint256 pegPrice = 1e18;\n\n require(\n sellPrice >= pegPrice - maxDepeg && buyPrice <= pegPrice + maxDepeg,\n \"price out of range\"\n );\n _;\n }\n\n /**\n * @dev Checks the pool's balances have improved and the balances\n * have not tipped to the other side.\n * This modifier is only applied to functions that do swaps against the pool.\n * Deposits and withdrawals are proportional to the pool's balances hence don't need this check.\n */\n modifier improvePoolBalance() {\n // Get the asset and OToken balances in the pool\n (\n uint256 assetReserveBefore,\n uint256 oTokenReserveBefore\n ) = _getPoolReserves();\n // diff = asset balance - OToken balance\n int256 diffBefore = assetReserveBefore.toInt256() -\n oTokenReserveBefore.toInt256();\n\n _;\n\n // Get the asset and OToken balances in the pool\n (\n uint256 assetReserveAfter,\n uint256 oTokenReserveAfter\n ) = _getPoolReserves();\n // diff = asset balance - OToken balance\n int256 diffAfter = assetReserveAfter.toInt256() -\n oTokenReserveAfter.toInt256();\n\n if (diffBefore == 0) {\n require(diffAfter == 0, \"Position balance is worsened\");\n } else if (diffBefore < 0) {\n // If the pool was originally imbalanced in favor of OToken, then\n // we want to check that the pool is now more balanced\n require(diffAfter <= 0, \"Assets overshot peg\");\n require(diffBefore < diffAfter, \"OTokens balance worse\");\n } else if (diffBefore > 0) {\n // If the pool was originally imbalanced in favor of asset, then\n // we want to check that the pool is now more balanced\n require(diffAfter >= 0, \"OTokens overshot peg\");\n require(diffAfter < diffBefore, \"Assets balance worse\");\n }\n }\n\n /**\n * @param _baseConfig The `platformAddress` is the address of the Algebra pool.\n * The `vaultAddress` is the address of the Origin Vault.\n * @param _gauge Address of the Algebra gauge for the pool.\n * @param _gaugeStakeToken The pool LP token address as reported by the\n * gauge. The inheriting contract is expected to resolve this via\n * whichever getter its gauge exposes (e.g. `IGauge.TOKEN()` for\n * legacy GaugeV2 ≤ v2.4 or `IHydrexGauge.stakeToken()` for\n * Hydrex GaugeV2 ≥ v2.5) and pass the result here. The constructor\n * verifies it matches `_baseConfig.platformAddress`.\n */\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _gauge,\n address _gaugeStakeToken\n ) InitializableAbstractStrategy(_baseConfig) {\n // Read the oToken address from the Vault\n address oTokenMem = IVault(_baseConfig.vaultAddress).oToken();\n address assetMem = IVault(_baseConfig.vaultAddress).asset();\n\n // Checked both tokens are to 18 decimals\n require(\n IBasicToken(assetMem).decimals() == 18 &&\n IBasicToken(oTokenMem).decimals() == 18,\n \"Incorrect token decimals\"\n );\n // Check the Algebra pool is a Stable AMM (sAMM)\n require(\n IPair(_baseConfig.platformAddress).isStable() == true,\n \"Pool not stable\"\n );\n // Check the gauge is wired to the expected pool LP token. The\n // inheriting contract is responsible for fetching `_gaugeStakeToken`\n // from whichever getter the underlying gauge variant exposes.\n require(\n _gaugeStakeToken == _baseConfig.platformAddress,\n \"Incorrect gauge\"\n );\n oTokenPoolIndex = IPair(_baseConfig.platformAddress).token0() ==\n oTokenMem\n ? 0\n : 1;\n // Check the pool tokens are correct\n require(\n IPair(_baseConfig.platformAddress).token0() ==\n (oTokenPoolIndex == 0 ? oTokenMem : assetMem) &&\n IPair(_baseConfig.platformAddress).token1() ==\n (oTokenPoolIndex == 0 ? assetMem : oTokenMem),\n \"Incorrect pool tokens\"\n );\n\n // Set the immutable variables\n oToken = oTokenMem;\n asset = assetMem;\n pool = _baseConfig.platformAddress;\n gauge = _gauge;\n\n // This is an implementation contract. The governor is set in the proxy contract.\n _setGovernor(address(0));\n }\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Algebra strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Array containing SWPx token address\n * @param _maxDepeg The max amount the OToken/asset price can deviate from peg (1e18) before deposits are reverted.\n */\n function initialize(\n address[] calldata _rewardTokenAddresses,\n uint256 _maxDepeg\n ) external onlyGovernor initializer {\n address[] memory pTokens = new address[](1);\n pTokens[0] = pool;\n\n address[] memory _assets = new address[](1);\n _assets[0] = asset;\n\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n pTokens\n );\n\n maxDepeg = _maxDepeg;\n\n _approveBase();\n }\n\n /***************************************\n Deposit\n ****************************************/\n\n /**\n * @notice Deposit an amount of asset into the Algebra pool.\n * Mint OToken in proportion to the pool's asset and OToken reserves,\n * transfer asset and OToken to the pool,\n * mint the pool's LP token and deposit in the gauge.\n * @dev This tx must be wrapped by the VaultValueChecker.\n * To minimize loses, the pool should be rebalanced before depositing.\n * The pool's oToken/asset price must be within the maxDepeg range.\n * @param _asset Address of asset token.\n * @param _assetAmount Amount of asset tokens to deposit.\n */\n function deposit(address _asset, uint256 _assetAmount)\n external\n override\n onlyVault\n nonReentrant\n skimPool\n nearBalancedPool\n {\n require(_asset == asset, \"Unsupported asset\");\n require(_assetAmount > 0, \"Must deposit something\");\n\n (uint256 oTokenDepositAmount, ) = _deposit(_assetAmount);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n // Emit event for the deposited asset tokens\n emit Deposit(asset, pool, _assetAmount);\n // Emit event for the minted OToken tokens\n emit Deposit(oToken, pool, oTokenDepositAmount);\n }\n\n /**\n * @notice Deposit all the strategy's asset tokens into the Algebra pool.\n * Mint OToken in proportion to the pool's asset and OToken reserves,\n * transfer asset and OToken to the pool,\n * mint the pool's LP token and deposit in the gauge.\n * @dev This tx must be wrapped by the VaultValueChecker.\n * To minimize loses, the pool should be rebalanced before depositing.\n * The pool's oToken/asset price must be within the maxDepeg range.\n */\n function depositAll()\n external\n override\n onlyVault\n nonReentrant\n skimPool\n nearBalancedPool\n {\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\n if (assetBalance > 0) {\n (uint256 oTokenDepositAmount, ) = _deposit(assetBalance);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n // Emit event for the deposited asset tokens\n emit Deposit(asset, pool, assetBalance);\n // Emit event for the minted OToken tokens\n emit Deposit(oToken, pool, oTokenDepositAmount);\n }\n }\n\n /**\n * @dev Mint OToken in proportion to the pool's asset and OToken reserves,\n * transfer asset and OToken to the pool,\n * mint the pool's LP token and deposit in the gauge.\n * @param _assetAmount Amount of asset tokens to deposit.\n * @return oTokenDepositAmount Amount of OToken tokens minted and deposited into the pool.\n * @return lpTokens Amount of Algebra pool LP tokens minted and deposited into the gauge.\n */\n function _deposit(uint256 _assetAmount)\n internal\n returns (uint256 oTokenDepositAmount, uint256 lpTokens)\n {\n // Calculate the required amount of OToken to mint based on the asset amount.\n oTokenDepositAmount = _calcTokensToMint(_assetAmount);\n\n // Mint the required OToken tokens to this strategy\n IVault(vaultAddress).mintForStrategy(oTokenDepositAmount);\n\n // Add asset and OToken liquidity to the pool and stake in gauge\n lpTokens = _depositToPoolAndGauge(_assetAmount, oTokenDepositAmount);\n }\n\n /***************************************\n Withdraw\n ****************************************/\n\n /**\n * @notice Withdraw asset and OToken from the Algebra pool, burn the OToken,\n * and transfer the asset to the recipient.\n * @param _recipient Address of the Vault.\n * @param _asset Address of the asset token.\n * @param _assetAmount Amount of asset tokens to withdraw.\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _assetAmount\n ) external override onlyVault nonReentrant skimPool {\n require(_assetAmount > 0, \"Must withdraw something\");\n require(_asset == asset, \"Unsupported asset\");\n // This strategy can't be set as a default strategy for asset in the Vault.\n // This means the recipient must always be the Vault.\n require(_recipient == vaultAddress, \"Only withdraw to vault allowed\");\n\n // Calculate how much pool LP tokens to burn to get the required amount of asset tokens back\n uint256 lpTokens = _calcTokensToBurn(_assetAmount);\n\n // Withdraw pool LP tokens from the gauge and remove assets from from the pool\n _withdrawFromGaugeAndPool(lpTokens);\n\n // Burn all the removed OToken and any that was left in the strategy\n uint256 oTokenToBurn = IERC20(oToken).balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oTokenToBurn);\n\n // Transfer asset to the recipient\n // Note there can be a dust amount of asset left in the strategy as\n // the burn of the pool's LP tokens is rounded up\n require(\n IERC20(asset).balanceOf(address(this)) >= _assetAmount,\n \"Not enough asset removed\"\n );\n IERC20(asset).safeTransfer(_recipient, _assetAmount);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n // Emit event for the withdrawn asset tokens\n emit Withdrawal(asset, pool, _assetAmount);\n // Emit event for the burnt OToken tokens\n emit Withdrawal(oToken, pool, oTokenToBurn);\n }\n\n /**\n * @notice Withdraw all pool LP tokens from the gauge,\n * remove all asset and OToken from the Algebra pool,\n * burn all the OToken,\n * and transfer all the asset to the Vault contract.\n * @dev There is no solvency check here as withdrawAll can be called to\n * quickly secure assets to the Vault in emergencies.\n */\n function withdrawAll()\n external\n override\n onlyVaultOrGovernor\n nonReentrant\n skimPool\n {\n // Get all the pool LP tokens the strategy has staked in the gauge\n uint256 lpTokens = IGauge(gauge).balanceOf(address(this));\n // Can not withdraw zero LP tokens from the gauge\n if (lpTokens == 0) return;\n\n if (IGauge(gauge).emergency()) {\n // The gauge is in emergency mode\n _emergencyWithdrawFromGaugeAndPool();\n } else {\n // Withdraw pool LP tokens from the gauge and remove assets from from the pool\n _withdrawFromGaugeAndPool(lpTokens);\n }\n\n // Burn all OToken in this strategy contract\n uint256 oTokenToBurn = IERC20(oToken).balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oTokenToBurn);\n\n // Get the strategy contract's asset balance.\n // This includes all that was removed from the Algebra pool and\n // any that was sitting in the strategy contract before the removal.\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\n IERC20(asset).safeTransfer(vaultAddress, assetBalance);\n\n // Emit event for the withdrawn asset tokens\n emit Withdrawal(asset, pool, assetBalance);\n // Emit event for the burnt OToken tokens\n emit Withdrawal(oToken, pool, oTokenToBurn);\n }\n\n /***************************************\n Pool Rebalancing\n ****************************************/\n\n /** @notice Used when there is more OToken than asset in the pool.\n * asset and OToken is removed from the pool, the received asset is swapped for OToken\n * and the left over OToken in the strategy is burnt.\n * The OToken/asset price is < 1.0 so OToken is being bought at a discount.\n * @param _assetAmount Amount of asset tokens to swap into the pool.\n */\n function swapAssetsToPool(uint256 _assetAmount)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n skimPool\n {\n require(_assetAmount > 0, \"Must swap something\");\n\n // 1. Partially remove liquidity so there’s enough asset for the swap\n\n // Calculate how much pool LP tokens to burn to get the required amount of asset tokens back\n uint256 lpTokens = _calcTokensToBurn(_assetAmount);\n require(lpTokens > 0, \"No LP tokens to burn\");\n\n _withdrawFromGaugeAndPool(lpTokens);\n\n // 2. Swap asset for OToken against the pool\n // Swap exact amount of asset for OToken against the pool\n // There can be a dust amount of asset left in the strategy as the burn of the pool's LP tokens is rounded up\n _swapExactTokensForTokens(_assetAmount, asset, oToken);\n\n // 3. Burn all the OToken left in the strategy from the remove liquidity and swap\n uint256 oTokenToBurn = IERC20(oToken).balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oTokenToBurn);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n // Emit event for the burnt OToken tokens\n emit Withdrawal(oToken, pool, oTokenToBurn);\n // Emit event for the swap\n emit SwapAssetsToPool(_assetAmount, lpTokens, oTokenToBurn);\n }\n\n /**\n * @notice Used when there is more asset than OToken in the pool.\n * OToken is minted and swapped for asset against the pool,\n * more OToken is minted and added back into the pool with the swapped out asset.\n * The OToken/asset price is > 1.0 so OToken is being sold at a premium.\n * @param _oTokenAmount Amount of OToken to swap into the pool.\n */\n function swapOTokensToPool(uint256 _oTokenAmount)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n skimPool\n {\n require(_oTokenAmount > 0, \"Must swap something\");\n\n // 1. Mint OToken so it can be swapped into the pool\n\n // There can be OToken in the strategy from skimming the pool\n uint256 oTokenInStrategy = IERC20(oToken).balanceOf(address(this));\n require(\n _oTokenAmount >= oTokenInStrategy,\n \"Too much OToken in strategy\"\n );\n uint256 oTokenToMint = _oTokenAmount - oTokenInStrategy;\n\n // Mint the required OToken tokens to this strategy\n IVault(vaultAddress).mintForStrategy(oTokenToMint);\n\n // 2. Swap OToken for asset against the pool\n _swapExactTokensForTokens(_oTokenAmount, oToken, asset);\n\n // The asset is from the swap and any asset that was sitting in the strategy\n uint256 assetDepositAmount = IERC20(asset).balanceOf(address(this));\n\n // 3. Add asset and OToken back to the pool in proportion to the pool's reserves\n (uint256 oTokenDepositAmount, uint256 lpTokens) = _deposit(\n assetDepositAmount\n );\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n // Emit event for the minted OToken tokens\n emit Deposit(oToken, pool, oTokenToMint + oTokenDepositAmount);\n // Emit event for the swap\n emit SwapOTokensToPool(\n oTokenToMint,\n assetDepositAmount,\n oTokenDepositAmount,\n lpTokens\n );\n }\n\n /***************************************\n Assets and Rewards\n ****************************************/\n\n /**\n * @notice Get the asset value of assets in the strategy and Algebra pool.\n * The value of the assets in the pool is calculated assuming the pool is balanced.\n * This way the value can not be manipulated by changing the pool's token balances.\n * @param _asset Address of the asset token\n * @return balance Total value in asset.\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == asset, \"Unsupported asset\");\n\n // asset balance needed here for the balance check that happens from vault during depositing.\n balance = IERC20(asset).balanceOf(address(this));\n\n // This assumes 1 gauge LP token = 1 pool LP token\n uint256 lpTokens = IGauge(gauge).balanceOf(address(this));\n if (lpTokens == 0) return balance;\n\n // Add the strategy’s share of the asset and OToken tokens in the Algebra pool if the pool was balanced.\n balance += _lpValue(lpTokens);\n }\n\n /**\n * @notice Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == asset;\n }\n\n /**\n * @notice Collect accumulated SWPx (and other) rewards and send to the Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvesterOrStrategist\n nonReentrant\n {\n // Collect SWPx rewards from the gauge\n IGauge(gauge).getReward();\n\n _collectRewardTokens();\n }\n\n /***************************************\n Internal Algebra Pool and Gauge Functions\n ****************************************/\n\n /**\n * @dev Calculate the required amount of OToken to mint based on the asset amount.\n * This ensures the proportion of OToken tokens being added to the pool matches the proportion of asset tokens.\n * For example, if the added asset tokens is 10% of existing asset tokens in the pool,\n * then the OToken tokens being added should also be 10% of the OToken tokens in the pool.\n * @param _assetAmount Amount of asset tokens to be added to the pool.\n * @return oTokenAmount Amount of OToken tokens to be minted and added to the pool.\n */\n function _calcTokensToMint(uint256 _assetAmount)\n internal\n view\n returns (uint256 oTokenAmount)\n {\n (uint256 assetReserves, uint256 oTokenReserves) = _getPoolReserves();\n require(assetReserves > 0, \"Empty pool\");\n\n // OToken to add = (asset being added * OToken in pool) / asset in pool\n oTokenAmount = (_assetAmount * oTokenReserves) / assetReserves;\n }\n\n /**\n * @dev Calculate how much pool LP tokens to burn to get the required amount of asset tokens back\n * from the pool.\n * @param _assetAmount Amount of asset tokens to be removed from the pool.\n * @return lpTokens Amount of Algebra pool LP tokens to burn.\n */\n function _calcTokensToBurn(uint256 _assetAmount)\n internal\n view\n returns (uint256 lpTokens)\n {\n /* The Algebra pool proportionally returns the reserve tokens when removing liquidity.\n * First, calculate the proportion of required asset tokens against the pools asset reserves.\n * That same proportion is used to calculate the required amount of pool LP tokens.\n * For example, if the required asset tokens is 10% of the pool's asset reserves,\n * then 10% of the pool's LP supply needs to be burned.\n *\n * Because we are doing balanced removal we should be making profit when removing liquidity in a\n * pool tilted to either side.\n *\n * Important: A downside is that the Strategist / Governor needs to be\n * cognizant of not removing too much liquidity. And while the proposal to remove liquidity\n * is being voted on, the pool tilt might change so much that the proposal that has been valid while\n * created is no longer valid.\n */\n\n (uint256 assetReserves, ) = _getPoolReserves();\n require(assetReserves > 0, \"Empty pool\");\n\n lpTokens = (_assetAmount * IPair(pool).totalSupply()) / assetReserves;\n lpTokens += 1; // Add 1 to ensure we get enough LP tokens with rounding\n }\n\n /**\n * @dev Deposit asset and OToken liquidity to the Algebra pool\n * and stake the pool's LP token in the gauge.\n * @param _assetAmount Amount of asset to deposit.\n * @param _oTokenAmount Amount of OToken to deposit.\n * @return lpTokens Amount of Algebra pool LP tokens minted.\n */\n function _depositToPoolAndGauge(uint256 _assetAmount, uint256 _oTokenAmount)\n internal\n returns (uint256 lpTokens)\n {\n // Transfer asset to the pool\n IERC20(asset).safeTransfer(pool, _assetAmount);\n // Transfer OToken to the pool\n IERC20(oToken).safeTransfer(pool, _oTokenAmount);\n\n // Mint LP tokens from the pool\n lpTokens = IPair(pool).mint(address(this));\n\n // Deposit the pool's LP tokens into the gauge\n IGauge(gauge).deposit(lpTokens);\n }\n\n /**\n * @dev Withdraw pool LP tokens from the gauge and remove asset and OToken from the pool.\n * @param _lpTokens Amount of Algebra pool LP tokens to withdraw from the gauge\n */\n function _withdrawFromGaugeAndPool(uint256 _lpTokens) internal {\n require(\n IGauge(gauge).balanceOf(address(this)) >= _lpTokens,\n \"Not enough LP tokens in gauge\"\n );\n\n // Withdraw pool LP tokens from the gauge\n IGauge(gauge).withdraw(_lpTokens);\n\n // Transfer the pool LP tokens to the pool\n IERC20(pool).safeTransfer(pool, _lpTokens);\n\n // Burn the LP tokens and transfer the asset and OToken back to the strategy\n IPair(pool).burn(address(this));\n }\n\n /**\n * @dev Withdraw all pool LP tokens from the gauge when it's in emergency mode\n * and remove asset and OToken from the pool.\n */\n function _emergencyWithdrawFromGaugeAndPool() internal {\n // Withdraw all pool LP tokens from the gauge\n IGauge(gauge).emergencyWithdraw();\n\n // Get the pool LP tokens in strategy\n uint256 _lpTokens = IERC20(pool).balanceOf(address(this));\n\n // Transfer the pool LP tokens to the pool\n IERC20(pool).safeTransfer(pool, _lpTokens);\n\n // Burn the LP tokens and transfer the asset and OToken back to the strategy\n IPair(pool).burn(address(this));\n }\n\n /**\n * @dev Swap exact amount of tokens for another token against the pool.\n * @param _amountIn Amount of tokens to swap into the pool.\n * @param _tokenIn Address of the token going into the pool.\n * @param _tokenOut Address of the token being swapped out of the pool.\n */\n function _swapExactTokensForTokens(\n uint256 _amountIn,\n address _tokenIn,\n address _tokenOut\n ) internal {\n // Calculate how much out tokens we get from the swap\n uint256 amountOut = IPair(pool).getAmountOut(_amountIn, _tokenIn);\n\n // Transfer in tokens to the pool after the amountOut calculation has been mde.\n // This way we don't have to worry about sending tokens to pool confusing the pool's reserves.\n IERC20(_tokenIn).safeTransfer(pool, _amountIn);\n\n // Safety check that we are dealing with the correct pool tokens\n require(\n (_tokenIn == asset && _tokenOut == oToken) ||\n (_tokenIn == oToken && _tokenOut == asset),\n \"Unsupported swap\"\n );\n\n uint256 amount0;\n uint256 amount1;\n\n // Work out the correct order of the amounts for the pool\n if (_tokenIn == asset) {\n if (oTokenPoolIndex == 0) {\n amount0 = amountOut;\n amount1 = 0;\n } else {\n amount0 = 0;\n amount1 = amountOut;\n }\n } else {\n if (oTokenPoolIndex == 0) {\n amount0 = 0;\n amount1 = amountOut;\n } else {\n amount0 = amountOut;\n amount1 = 0;\n }\n }\n\n // Perform the swap on the pool\n IPair(pool).swap(amount0, amount1, address(this), new bytes(0));\n\n // The slippage protection against the amount out is indirectly done\n // via the improvePoolBalance\n }\n\n /// @dev Calculate the value of a LP position in a Algebra stable pool\n /// if the pool was balanced.\n /// @param _lpTokens Amount of LP tokens in the Algebra pool\n /// @return value The asset value of the LP tokens when the pool is balanced\n function _lpValue(uint256 _lpTokens) internal view returns (uint256 value) {\n // Get total supply of LP tokens\n uint256 totalSupply = IPair(pool).totalSupply();\n if (totalSupply == 0) return 0;\n\n // Get the current reserves of the pool\n (uint256 assetReserves, uint256 oTokenReserves) = _getPoolReserves();\n\n // Calculate the invariant of the pool assuming both tokens have 18 decimals.\n // k is scaled to 18 decimals.\n uint256 k = _invariant(assetReserves, oTokenReserves);\n\n // If x = y, let’s denote x = y = z (where z is the common reserve value)\n // Substitute z into the invariant:\n // k = z^3 * z + z * z^3\n // k = 2 * z^4\n // Going back the other way to calculate the common reserve value z\n // z = (k / 2) ^ (1/4)\n // the total value of the pool when x = y is 2 * z, which is 2 * (k / 2) ^ (1/4)\n uint256 zSquared = sqrt((k * 1e18) / 2); // 18 + 18 = 36 decimals becomes 18 decimals after sqrt\n uint256 z = sqrt(zSquared * 1e18); // 18 + 18 = 36 decimals becomes 18 decimals after sqrt\n uint256 totalValueOfPool = 2 * z;\n\n // lp value = lp tokens * value of pool / total supply\n value = (_lpTokens * totalValueOfPool) / totalSupply;\n }\n\n /**\n * @dev Compute the invariant for a Algebra stable pool.\n * This assumed both x and y tokens are to 18 decimals which is checked in the constructor.\n * invariant: k = x^3 * y + x * y^3\n * @dev This implementation is copied from Algebra's Pair contract.\n * @param _x The amount of asset tokens in the pool\n * @param _y The amount of the OToken tokens in the pool\n * @return k The invariant of the Algebra stable pool\n */\n function _invariant(uint256 _x, uint256 _y)\n internal\n pure\n returns (uint256 k)\n {\n uint256 _a = (_x * _y) / PRECISION;\n uint256 _b = ((_x * _x) / PRECISION + (_y * _y) / PRECISION);\n // slither-disable-next-line divide-before-multiply\n k = (_a * _b) / PRECISION;\n }\n\n /**\n * @dev Checks that the protocol is solvent, protecting from a rogue Strategist / Guardian that can\n * keep rebalancing the pool in both directions making the protocol lose a tiny amount of\n * funds each time.\n *\n * Protocol must be at least SOLVENCY_THRESHOLD (99,8 %) backed in order for the rebalances to\n * function.\n */\n function _solvencyAssert() internal view {\n uint256 _totalVaultValue = IVault(vaultAddress).totalValue();\n uint256 _totalSupply = IERC20(oToken).totalSupply();\n\n if (\n _totalSupply > 0 &&\n _totalVaultValue.divPrecisely(_totalSupply) < SOLVENCY_THRESHOLD\n ) {\n revert(\"Protocol insolvent\");\n }\n }\n\n /**\n * @dev Get the reserves of the pool no matter the order of tokens in the underlying\n * Algebra pool.\n * @return assetReserves The reserves of the asset token in the pool.\n * @return oTokenReserves The reserves of the OToken token in the pool.\n */\n function _getPoolReserves()\n internal\n view\n returns (uint256 assetReserves, uint256 oTokenReserves)\n {\n (uint256 reserve0, uint256 reserve1, ) = IPair(pool).getReserves();\n assetReserves = oTokenPoolIndex == 0 ? reserve1 : reserve0;\n oTokenReserves = oTokenPoolIndex == 0 ? reserve0 : reserve1;\n }\n\n /***************************************\n Setters\n ****************************************/\n\n /**\n * @notice Set the maximum deviation from the OToken/asset peg (1e18) before deposits are reverted.\n * @param _maxDepeg the OToken/asset price from peg (1e18) in 18 decimals.\n * eg 0.01e18 or 1e16 is 1% which is 100 basis points.\n */\n function setMaxDepeg(uint256 _maxDepeg) external onlyGovernor {\n require(\n _maxDepeg >= 0.001 ether && _maxDepeg <= 0.1 ether,\n \"Invalid max depeg range\"\n );\n maxDepeg = _maxDepeg;\n\n emit MaxDepegUpdated(_maxDepeg);\n }\n\n /***************************************\n Approvals\n ****************************************/\n\n /**\n * @notice Approve the spending of all assets by their corresponding pool tokens,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n _approveBase();\n }\n\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {}\n\n function _approveBase() internal {\n // Approve Algebra gauge contract to transfer Algebra pool LP tokens\n // This is needed for deposits of Algebra pool LP tokens into the gauge.\n // slither-disable-next-line unused-return\n IPair(pool).approve(address(gauge), type(uint256).max);\n }\n}\n" + }, + "contracts/strategies/BaseCurveAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Curve Automated Market Maker (AMO) Strategy\n * @notice AMO strategy for the Curve OETH/WETH pool\n * @author Origin Protocol Inc\n */\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { ICurveStableSwapNG } from \"../interfaces/ICurveStableSwapNG.sol\";\nimport { ICurveXChainLiquidityGauge } from \"../interfaces/ICurveXChainLiquidityGauge.sol\";\nimport { IChildLiquidityGaugeFactory } from \"../interfaces/IChildLiquidityGaugeFactory.sol\";\n\ncontract BaseCurveAMOStrategy is InitializableAbstractStrategy {\n using StableMath for uint256;\n using SafeCast for uint256;\n\n /**\n * @dev a threshold under which the contract no longer allows for the protocol to manually rebalance.\n * Guarding against a strategist / guardian being taken over and with multiple transactions\n * draining the protocol funds.\n */\n uint256 public constant SOLVENCY_THRESHOLD = 0.998 ether;\n\n // New immutable variables that must be set in the constructor\n /**\n * @notice Address of the Wrapped ETH (WETH) contract.\n */\n IWETH9 public immutable weth;\n\n /**\n * @notice Address of the OETH token contract.\n */\n IERC20 public immutable oeth;\n\n /**\n * @notice Address of the LP (Liquidity Provider) token contract.\n */\n IERC20 public immutable lpToken;\n\n /**\n * @notice Address of the Curve StableSwap NG pool contract.\n */\n ICurveStableSwapNG public immutable curvePool;\n\n /**\n * @notice Address of the Curve X-Chain Liquidity Gauge contract.\n */\n ICurveXChainLiquidityGauge public immutable gauge;\n\n /**\n * @notice Address of the Child Liquidity Gauge Factory contract.\n */\n IChildLiquidityGaugeFactory public immutable gaugeFactory;\n\n // Ordered list of pool assets\n uint128 public immutable oethCoinIndex;\n uint128 public immutable wethCoinIndex;\n\n /**\n * @notice Maximum slippage allowed for adding/removing liquidity from the Curve pool.\n */\n uint256 public maxSlippage;\n\n event MaxSlippageUpdated(uint256 newMaxSlippage);\n\n /**\n * @dev Verifies that the caller is the Strategist.\n */\n modifier onlyStrategist() {\n require(\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n _;\n }\n\n /**\n * @dev Checks the Curve pool's balances have improved and the balances\n * have not tipped to the other side.\n * This modifier is only applied to functions that do a single sided add or remove.\n * The standard deposit function adds to both sides of the pool in a way that\n * the pool's balance is not worsened.\n * Withdrawals are proportional so doesn't change the pools asset balance.\n */\n modifier improvePoolBalance() {\n // Get the asset and OToken balances in the Curve pool\n uint256[] memory balancesBefore = curvePool.get_balances();\n // diff = ETH balance - OETH balance\n int256 diffBefore = balancesBefore[wethCoinIndex].toInt256() -\n balancesBefore[oethCoinIndex].toInt256();\n\n _;\n\n // Get the asset and OToken balances in the Curve pool\n uint256[] memory balancesAfter = curvePool.get_balances();\n // diff = ETH balance - OETH balance\n int256 diffAfter = balancesAfter[wethCoinIndex].toInt256() -\n balancesAfter[oethCoinIndex].toInt256();\n\n if (diffBefore == 0) {\n require(diffAfter == 0, \"Position balance is worsened\");\n } else if (diffBefore < 0) {\n // If the pool was originally imbalanced in favor of OETH, then\n // we want to check that the pool is now more balanced\n require(diffAfter <= 0, \"OTokens overshot peg\");\n require(diffBefore < diffAfter, \"OTokens balance worse\");\n } else if (diffBefore > 0) {\n // If the pool was originally imbalanced in favor of ETH, then\n // we want to check that the pool is now more balanced\n require(diffAfter >= 0, \"Assets overshot peg\");\n require(diffAfter < diffBefore, \"Assets balance worse\");\n }\n }\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _oeth,\n address _weth,\n address _gauge,\n address _gaugeFactory,\n uint128 _oethCoinIndex,\n uint128 _wethCoinIndex\n ) InitializableAbstractStrategy(_baseConfig) {\n oethCoinIndex = _oethCoinIndex;\n wethCoinIndex = _wethCoinIndex;\n\n lpToken = IERC20(_baseConfig.platformAddress);\n curvePool = ICurveStableSwapNG(_baseConfig.platformAddress);\n\n oeth = IERC20(_oeth);\n weth = IWETH9(_weth);\n gauge = ICurveXChainLiquidityGauge(_gauge);\n gaugeFactory = IChildLiquidityGaugeFactory(_gaugeFactory);\n\n _setGovernor(address(0));\n }\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Curve strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Address of CRV\n * @param _maxSlippage Maximum slippage allowed for adding/removing liquidity from the Curve pool.\n */\n function initialize(\n address[] calldata _rewardTokenAddresses, // CRV\n uint256 _maxSlippage\n ) external onlyGovernor initializer {\n address[] memory pTokens = new address[](1);\n pTokens[0] = address(curvePool);\n\n address[] memory _assets = new address[](1);\n _assets[0] = address(weth);\n\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n pTokens\n );\n\n _approveBase();\n _setMaxSlippage(_maxSlippage);\n }\n\n /***************************************\n Deposit\n ****************************************/\n\n /**\n * @notice Deposit WETH into the Curve pool\n * @param _weth Address of Wrapped ETH (WETH) contract.\n * @param _amount Amount of WETH to deposit.\n */\n function deposit(address _weth, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_weth, _amount);\n }\n\n function _deposit(address _weth, uint256 _wethAmount) internal {\n require(_wethAmount > 0, \"Must deposit something\");\n require(_weth == address(weth), \"Can only deposit WETH\");\n\n emit Deposit(_weth, address(lpToken), _wethAmount);\n\n // Get the asset and OToken balances in the Curve pool\n uint256[] memory balances = curvePool.get_balances();\n // safe to cast since min value is at least 0\n uint256 oethToAdd = uint256(\n _max(\n 0,\n balances[wethCoinIndex].toInt256() +\n _wethAmount.toInt256() -\n balances[oethCoinIndex].toInt256()\n )\n );\n\n /* Add so much OETH so that the pool ends up being balanced. And at minimum\n * add as much OETH as WETH and at maximum twice as much OETH.\n */\n oethToAdd = Math.max(oethToAdd, _wethAmount);\n oethToAdd = Math.min(oethToAdd, _wethAmount * 2);\n\n /* Mint OETH with a strategy that attempts to contribute to stability of OETH/WETH pool. Try\n * to mint so much OETH that after deployment of liquidity pool ends up being balanced.\n *\n * To manage unpredictability minimal OETH minted will always be at least equal or greater\n * to WETH amount deployed. And never larger than twice the WETH amount deployed even if\n * it would have a further beneficial effect on pool stability.\n */\n IVault(vaultAddress).mintForStrategy(oethToAdd);\n\n emit Deposit(address(oeth), address(lpToken), oethToAdd);\n\n uint256[] memory _amounts = new uint256[](2);\n _amounts[wethCoinIndex] = _wethAmount;\n _amounts[oethCoinIndex] = oethToAdd;\n\n uint256 valueInLpTokens = (_wethAmount + oethToAdd).divPrecisely(\n curvePool.get_virtual_price()\n );\n uint256 minMintAmount = valueInLpTokens.mulTruncate(\n uint256(1e18) - maxSlippage\n );\n\n // Do the deposit to the Curve pool\n uint256 lpDeposited = curvePool.add_liquidity(_amounts, minMintAmount);\n require(lpDeposited >= minMintAmount, \"Min LP amount error\");\n\n // Deposit the Curve pool's LP tokens into the Curve gauge\n gauge.deposit(lpDeposited);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n }\n\n /**\n * @notice Deposit the strategy's entire balance of WETH into the Curve pool\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 balance = weth.balanceOf(address(this));\n if (balance > 0) {\n _deposit(address(weth), balance);\n }\n }\n\n /***************************************\n Withdraw\n ****************************************/\n\n /**\n * @notice Withdraw ETH and OETH from the Curve pool, burn the OETH,\n * convert the ETH to WETH and transfer to the recipient.\n * @param _recipient Address to receive withdrawn asset which is normally the Vault.\n * @param _weth Address of the Wrapped ETH (WETH) contract.\n * @param _amount Amount of WETH to withdraw.\n */\n function withdraw(\n address _recipient,\n address _weth,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(_weth == address(weth), \"Can only withdraw WETH\");\n\n emit Withdrawal(_weth, address(lpToken), _amount);\n\n uint256 requiredLpTokens = calcTokenToBurn(_amount);\n\n _lpWithdraw(requiredLpTokens);\n\n /* math in requiredLpTokens should correctly calculate the amount of LP to remove\n * in that the strategy receives enough WETH on balanced removal\n */\n uint256[] memory _minWithdrawalAmounts = new uint256[](2);\n _minWithdrawalAmounts[wethCoinIndex] = _amount;\n // slither-disable-next-line unused-return\n curvePool.remove_liquidity(requiredLpTokens, _minWithdrawalAmounts);\n\n // Burn all the removed OETH and any that was left in the strategy\n uint256 oethToBurn = oeth.balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n\n emit Withdrawal(address(oeth), address(lpToken), oethToBurn);\n\n // Transfer WETH to the recipient\n require(\n weth.transfer(_recipient, _amount),\n \"Transfer of WETH not successful\"\n );\n\n // Ensure solvency of the vault\n _solvencyAssert();\n }\n\n function calcTokenToBurn(uint256 _wethAmount)\n internal\n view\n returns (uint256 lpToBurn)\n {\n /* The rate between coins in the pool determines the rate at which pool returns\n * tokens when doing balanced removal (remove_liquidity call). And by knowing how much WETH\n * we want we can determine how much of OETH we receive by removing liquidity.\n *\n * Because we are doing balanced removal we should be making profit when removing liquidity in a\n * pool tilted to either side.\n *\n * Important: A downside is that the Strategist / Governor needs to be\n * cognisant of not removing too much liquidity. And while the proposal to remove liquidity\n * is being voted on the pool tilt might change so much that the proposal that has been valid while\n * created is no longer valid.\n */\n\n uint256 poolWETHBalance = curvePool.balances(wethCoinIndex);\n /* K is multiplied by 1e36 which is used for higher precision calculation of required\n * pool LP tokens. Without it the end value can have rounding errors up to precision of\n * 10 digits. This way we move the decimal point by 36 places when doing the calculation\n * and again by 36 places when we are done with it.\n */\n uint256 k = (1e36 * lpToken.totalSupply()) / poolWETHBalance;\n // prettier-ignore\n // slither-disable-next-line divide-before-multiply\n uint256 diff = (_wethAmount + 1) * k;\n lpToBurn = diff / 1e36;\n }\n\n /**\n * @notice Remove all ETH and OETH from the Curve pool, burn the OETH,\n * convert the ETH to WETH and transfer to the Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 gaugeTokens = gauge.balanceOf(address(this));\n // Can not withdraw zero LP tokens from the gauge\n if (gaugeTokens == 0) return;\n _lpWithdraw(gaugeTokens);\n\n // Withdraws are proportional to assets held by 3Pool\n uint256[] memory minWithdrawAmounts = new uint256[](2);\n\n // Remove liquidity\n // slither-disable-next-line unused-return\n curvePool.remove_liquidity(\n lpToken.balanceOf(address(this)),\n minWithdrawAmounts\n );\n\n // Burn all OETH\n uint256 oethToBurn = oeth.balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n\n // Get the strategy contract's WETH balance.\n // This includes all that was removed from the Curve pool and\n // any ether that was sitting in the strategy contract before the removal.\n uint256 ethBalance = weth.balanceOf(address(this));\n require(\n weth.transfer(vaultAddress, ethBalance),\n \"Transfer of WETH not successful\"\n );\n\n emit Withdrawal(address(weth), address(lpToken), ethBalance);\n emit Withdrawal(address(oeth), address(lpToken), oethToBurn);\n }\n\n /***************************************\n Curve pool Rebalancing\n ****************************************/\n\n /**\n * @notice Mint OTokens and one-sided add to the Curve pool.\n * This is used when the Curve pool does not have enough OTokens and too many ETH.\n * The OToken/Asset, eg OETH/ETH, price with increase.\n * The amount of assets in the vault is unchanged.\n * The total supply of OTokens is increased.\n * The asset value of the strategy and vault is increased.\n * @param _oTokens The amount of OTokens to be minted and added to the pool.\n */\n function mintAndAddOTokens(uint256 _oTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n IVault(vaultAddress).mintForStrategy(_oTokens);\n\n uint256[] memory amounts = new uint256[](2);\n amounts[oethCoinIndex] = _oTokens;\n\n // Convert OETH to Curve pool LP tokens\n uint256 valueInLpTokens = (_oTokens).divPrecisely(\n curvePool.get_virtual_price()\n );\n // Apply slippage to LP tokens\n uint256 minMintAmount = valueInLpTokens.mulTruncate(\n uint256(1e18) - maxSlippage\n );\n\n // Add the minted OTokens to the Curve pool\n uint256 lpDeposited = curvePool.add_liquidity(amounts, minMintAmount);\n require(lpDeposited >= minMintAmount, \"Min LP amount error\");\n\n // Deposit the Curve pool LP tokens to the Curve gauge\n gauge.deposit(lpDeposited);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Deposit(address(oeth), address(lpToken), _oTokens);\n }\n\n /**\n * @notice One-sided remove of OTokens from the Curve pool which are then burned.\n * This is used when the Curve pool has too many OTokens and not enough ETH.\n * The amount of assets in the vault is unchanged.\n * The total supply of OTokens is reduced.\n * The asset value of the strategy and vault is reduced.\n * @param _lpTokens The amount of Curve pool LP tokens to be burned for OTokens.\n */\n function removeAndBurnOTokens(uint256 _lpTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n // Withdraw Curve pool LP tokens from Convex and remove OTokens from the Curve pool\n uint256 oethToBurn = _withdrawAndRemoveFromPool(\n _lpTokens,\n oethCoinIndex\n );\n\n // The vault burns the OTokens from this strategy\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Withdrawal(address(oeth), address(lpToken), oethToBurn);\n }\n\n /**\n * @notice One-sided remove of ETH from the Curve pool, convert to WETH\n * and transfer to the vault.\n * This is used when the Curve pool does not have enough OTokens and too many ETH.\n * The OToken/Asset, eg OETH/ETH, price with decrease.\n * The amount of assets in the vault increases.\n * The total supply of OTokens does not change.\n * The asset value of the strategy reduces.\n * The asset value of the vault should be close to the same.\n * @param _lpTokens The amount of Curve pool LP tokens to be burned for ETH.\n * @dev Curve pool LP tokens is used rather than WETH assets as Curve does not\n * have a way to accurately calculate the amount of LP tokens for a required\n * amount of ETH. Curve's `calc_token_amount` functioun does not include fees.\n * A 3rd party libary can be used that takes into account the fees, but this\n * is a gas intensive process. It's easier for the trusted strategist to\n * caclulate the amount of Curve pool LP tokens required off-chain.\n */\n function removeOnlyAssets(uint256 _lpTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n // Withdraw Curve pool LP tokens from Curve gauge and remove ETH from the Curve pool\n uint256 ethAmount = _withdrawAndRemoveFromPool(\n _lpTokens,\n wethCoinIndex\n );\n\n // Transfer WETH to the vault\n require(\n weth.transfer(vaultAddress, ethAmount),\n \"Transfer of WETH not successful\"\n );\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Withdrawal(address(weth), address(lpToken), ethAmount);\n }\n\n /**\n * @dev Remove Curve pool LP tokens from the Convex pool and\n * do a one-sided remove of ETH or OETH from the Curve pool.\n * @param _lpTokens The amount of Curve pool LP tokens to be removed from the Convex pool.\n * @param coinIndex The index of the coin to be removed from the Curve pool. 0 = ETH, 1 = OETH.\n * @return coinsRemoved The amount of ETH or OETH removed from the Curve pool.\n */\n function _withdrawAndRemoveFromPool(uint256 _lpTokens, uint128 coinIndex)\n internal\n returns (uint256 coinsRemoved)\n {\n // Withdraw Curve pool LP tokens from Curve gauge\n _lpWithdraw(_lpTokens);\n\n // Convert Curve pool LP tokens to ETH value\n uint256 valueInEth = _lpTokens.mulTruncate(\n curvePool.get_virtual_price()\n );\n // Apply slippage to ETH value\n uint256 minAmount = valueInEth.mulTruncate(uint256(1e18) - maxSlippage);\n\n // Remove just the ETH from the Curve pool\n coinsRemoved = curvePool.remove_liquidity_one_coin(\n _lpTokens,\n int128(coinIndex),\n minAmount,\n address(this)\n );\n }\n\n /**\n * Checks that the protocol is solvent, protecting from a rogue Strategist / Guardian that can\n * keep rebalancing the pool in both directions making the protocol lose a tiny amount of\n * funds each time.\n *\n * Protocol must be at least SOLVENCY_THRESHOLD (99,8 %) backed in order for the rebalances to\n * function.\n */\n function _solvencyAssert() internal view {\n uint256 _totalVaultValue = IVault(vaultAddress).totalValue();\n uint256 _totalOethbSupply = oeth.totalSupply();\n\n if (\n _totalVaultValue.divPrecisely(_totalOethbSupply) <\n SOLVENCY_THRESHOLD\n ) {\n revert(\"Protocol insolvent\");\n }\n }\n\n /***************************************\n Assets and Rewards\n ****************************************/\n\n /**\n * @notice Collect accumulated CRV (and other) rewards and send to the Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvesterOrStrategist\n nonReentrant\n {\n // CRV rewards flow.\n //---\n // CRV inflation:\n // Gauge receive CRV rewards from inflation.\n // Each checkpoint on the gauge send this CRV inflation to gauge factory.\n // This strategy should call mint on the gauge factory to collect the CRV rewards.\n // ---\n // Extra rewards:\n // Calling claim_rewards on the gauge will only claim extra rewards (outside of CRV).\n // ---\n\n // Mint CRV on Child Liquidity gauge factory\n gaugeFactory.mint(address(gauge));\n // Collect extra gauge rewards (outside of CRV)\n gauge.claim_rewards();\n\n _collectRewardTokens();\n }\n\n function _lpWithdraw(uint256 _lpAmount) internal {\n // withdraw lp tokens from the gauge without claiming rewards\n gauge.withdraw(_lpAmount);\n }\n\n /**\n * @notice Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == address(weth), \"Unsupported asset\");\n\n // WETH balance needed here for the balance check that happens from vault during depositing.\n balance = weth.balanceOf(address(this));\n uint256 lpTokens = gauge.balanceOf(address(this));\n if (lpTokens > 0) {\n balance += (lpTokens * curvePool.get_virtual_price()) / 1e18;\n }\n }\n\n /**\n * @notice Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == address(weth);\n }\n\n /***************************************\n Approvals\n ****************************************/\n\n /**\n * @notice Sets the maximum slippage allowed for any swap/liquidity operation\n * @param _maxSlippage Maximum slippage allowed, 1e18 = 100%.\n */\n function setMaxSlippage(uint256 _maxSlippage) external onlyGovernor {\n _setMaxSlippage(_maxSlippage);\n }\n\n function _setMaxSlippage(uint256 _maxSlippage) internal {\n require(_maxSlippage <= 5e16, \"Slippage must be less than 100%\");\n maxSlippage = _maxSlippage;\n emit MaxSlippageUpdated(_maxSlippage);\n }\n\n /**\n * @notice Approve the spending of all assets by their corresponding pool tokens,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n _approveBase();\n }\n\n /**\n * @dev Since we are unwrapping WETH before depositing it to Curve\n * there is no need to set an approval for WETH on the Curve\n * pool\n * @param _asset Address of the asset\n * @param _pToken Address of the Curve LP token\n */\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {}\n\n function _approveBase() internal {\n // Approve Curve pool for OETH (required for adding liquidity)\n // slither-disable-next-line unused-return\n oeth.approve(platformAddress, type(uint256).max);\n\n // Approve Curve pool for WETH (required for adding liquidity)\n // slither-disable-next-line unused-return\n weth.approve(platformAddress, type(uint256).max);\n\n // Approve Curve gauge contract to transfer Curve pool LP tokens\n // This is needed for deposits if Curve pool LP tokens into the Curve gauge.\n // slither-disable-next-line unused-return\n lpToken.approve(address(gauge), type(uint256).max);\n }\n\n /**\n * @dev Returns the largest of two numbers int256 version\n */\n function _max(int256 a, int256 b) internal pure returns (int256) {\n return a >= b ? a : b;\n }\n}\n" + }, + "contracts/strategies/BridgedWOETHStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20, SafeERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { AggregatorV3Interface } from \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\n\ncontract BridgedWOETHStrategy is InitializableAbstractStrategy {\n using StableMath for uint256;\n using StableMath for uint128;\n using SafeCast for uint256;\n using SafeERC20 for IERC20;\n\n event MaxPriceDiffBpsUpdated(uint128 oldValue, uint128 newValue);\n event WOETHPriceUpdated(uint128 oldValue, uint128 newValue);\n\n IWETH9 public immutable weth;\n IERC20 public immutable bridgedWOETH;\n IERC20 public immutable oethb;\n IOracle public immutable oracle;\n\n uint128 public lastOraclePrice;\n uint128 public maxPriceDiffBps;\n\n constructor(\n BaseStrategyConfig memory _stratConfig,\n address _weth,\n address _bridgedWOETH,\n address _oethb,\n address _oracle\n ) InitializableAbstractStrategy(_stratConfig) {\n weth = IWETH9(_weth);\n bridgedWOETH = IERC20(_bridgedWOETH);\n oethb = IERC20(_oethb);\n oracle = IOracle(_oracle);\n }\n\n function initialize(uint128 _maxPriceDiffBps)\n external\n onlyGovernor\n initializer\n {\n InitializableAbstractStrategy._initialize(\n new address[](0), // No reward tokens\n new address[](0), // No assets\n new address[](0) // No pTokens\n );\n\n _setMaxPriceDiffBps(_maxPriceDiffBps);\n }\n\n /**\n * @dev Sets the max price diff bps for the wOETH value appreciation\n * @param _maxPriceDiffBps Bps value, 10k == 100%\n */\n function setMaxPriceDiffBps(uint128 _maxPriceDiffBps)\n external\n onlyGovernor\n {\n _setMaxPriceDiffBps(_maxPriceDiffBps);\n }\n\n /**\n * @dev Sets the max price diff bps for the wOETH value appreciation\n * @param _maxPriceDiffBps Bps value, 10k == 100%\n */\n function _setMaxPriceDiffBps(uint128 _maxPriceDiffBps) internal {\n require(\n _maxPriceDiffBps > 0 && _maxPriceDiffBps <= 10000,\n \"Invalid bps value\"\n );\n\n emit MaxPriceDiffBpsUpdated(maxPriceDiffBps, _maxPriceDiffBps);\n\n maxPriceDiffBps = _maxPriceDiffBps;\n }\n\n /**\n * @dev Wrapper for _updateWOETHOraclePrice with nonReentrant flag\n * @return The latest price of wOETH from Oracle\n */\n function updateWOETHOraclePrice() external nonReentrant returns (uint256) {\n return _updateWOETHOraclePrice();\n }\n\n /**\n * @dev Finds the value of bridged wOETH from the Oracle.\n * Ensures that it's within the bounds and reasonable.\n * And stores it.\n *\n * NOTE: Intentionally not caching `Vault.priceProvider` here,\n * since doing so would mean that we also have to update this\n * strategy every time there's a change in oracle router.\n * Besides on L2, the gas is considerably cheaper than mainnet.\n *\n * @return Latest price from oracle\n */\n function _updateWOETHOraclePrice() internal returns (uint256) {\n // WETH price per unit of bridged wOETH\n uint256 oraclePrice = oracle.price(address(bridgedWOETH));\n\n // 1 wOETH > 1 WETH, always\n require(oraclePrice > 1 ether, \"Invalid wOETH value\");\n\n uint128 oraclePrice128 = oraclePrice.toUint128();\n\n // Do some checks\n if (lastOraclePrice > 0) {\n // Make sure the value only goes up\n require(oraclePrice128 >= lastOraclePrice, \"Negative wOETH yield\");\n\n // lastOraclePrice * (1 + maxPriceDiffBps)\n uint256 maxPrice = (lastOraclePrice * (1e4 + maxPriceDiffBps)) /\n 1e4;\n\n // And that it's within the bounds.\n require(oraclePrice128 <= maxPrice, \"Price diff beyond threshold\");\n }\n\n emit WOETHPriceUpdated(lastOraclePrice, oraclePrice128);\n\n // Store the price\n lastOraclePrice = oraclePrice128;\n\n return oraclePrice;\n }\n\n /**\n * @dev Computes & returns the value of given wOETH in WETH\n * @param woethAmount Amount of wOETH\n * @return Value of wOETH in WETH (using the last stored oracle price)\n */\n function getBridgedWOETHValue(uint256 woethAmount)\n public\n view\n returns (uint256)\n {\n return (woethAmount * lastOraclePrice) / 1 ether;\n }\n\n /**\n * @dev Takes in bridged wOETH and mints & returns\n * equivalent amount of OETHb.\n * @param woethAmount Amount of bridged wOETH to transfer in\n */\n function depositBridgedWOETH(uint256 woethAmount)\n external\n onlyGovernorOrStrategist\n nonReentrant\n {\n // Update wOETH price\n uint256 oraclePrice = _updateWOETHOraclePrice();\n\n // Figure out how much they are worth\n uint256 oethToMint = (woethAmount * oraclePrice) / 1 ether;\n\n require(oethToMint > 0, \"Invalid deposit amount\");\n\n // There's no pToken, however, it just uses WOETH address in the event\n emit Deposit(address(weth), address(bridgedWOETH), oethToMint);\n\n // Mint OETHb tokens and transfer it to the caller\n IVault(vaultAddress).mintForStrategy(oethToMint);\n\n // Transfer out minted OETHb\n // slither-disable-next-line unchecked-transfer unused-return\n oethb.transfer(msg.sender, oethToMint);\n\n // Transfer in all bridged wOETH tokens\n // slither-disable-next-line unchecked-transfer unused-return\n bridgedWOETH.transferFrom(msg.sender, address(this), woethAmount);\n }\n\n /**\n * @dev Takes in OETHb and burns it and returns\n * equivalent amount of bridged wOETH.\n * @param oethToBurn Amount of OETHb to burn\n */\n function withdrawBridgedWOETH(uint256 oethToBurn)\n external\n onlyGovernorOrStrategist\n nonReentrant\n {\n // Update wOETH price\n uint256 oraclePrice = _updateWOETHOraclePrice();\n\n // Figure out how much they are worth\n uint256 woethAmount = (oethToBurn * 1 ether) / oraclePrice;\n\n require(woethAmount > 0, \"Invalid withdraw amount\");\n\n // There's no pToken, however, it just uses WOETH address in the event\n emit Withdrawal(address(weth), address(bridgedWOETH), oethToBurn);\n\n // Transfer WOETH back\n // slither-disable-next-line unchecked-transfer unused-return\n bridgedWOETH.transfer(msg.sender, woethAmount);\n\n // Transfer in OETHb\n // slither-disable-next-line unchecked-transfer unused-return\n oethb.transferFrom(msg.sender, address(this), oethToBurn);\n\n // Burn OETHb\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n }\n\n /**\n * @notice Returns the amount of backing WETH the strategy holds\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == address(weth), \"Unsupported asset\");\n\n // Figure out how much wOETH is worth at the time.\n // Always uses the last stored oracle price.\n // Call updateWOETHOraclePrice manually to pull in latest yields.\n\n // NOTE: If the contract has been deployed but the call to\n // `updateWOETHOraclePrice()` has never been made, then this\n // will return zero. It should be fine because the strategy\n // should update the price whenever a deposit/withdraw happens.\n\n // If `updateWOETHOraclePrice()` hasn't been called in a while,\n // the strategy will underreport its holdings but never overreport it.\n\n balance =\n (bridgedWOETH.balanceOf(address(this)) * lastOraclePrice) /\n 1 ether;\n }\n\n /**\n * @notice Check if an asset is supported.\n * @param _asset Address of the asset\n * @return bool Whether asset is supported\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n // Strategist deposits bridged wOETH but the contract only\n // reports the balance in WETH. As far as Vault is concerned,\n // it isn't aware of bridged wOETH token\n return _asset == address(weth);\n }\n\n /***************************************\n Overridden methods\n ****************************************/\n /**\n * @inheritdoc InitializableAbstractStrategy\n */\n function transferToken(address _asset, uint256 _amount)\n public\n override\n onlyGovernor\n {\n require(\n _asset != address(bridgedWOETH) && _asset != address(weth),\n \"Cannot transfer supported asset\"\n );\n // Use SafeERC20 only for rescuing unknown assets; core tokens are standard.\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /**\n * @notice deposit() function not used for this strategy\n */\n function deposit(address, uint256)\n external\n override\n onlyVault\n nonReentrant\n {\n // Use depositBridgedWOETH() instead\n require(false, \"Deposit disabled\");\n }\n\n /**\n * @notice depositAll() function not used for this strategy\n */\n function depositAll() external override onlyVault nonReentrant {\n // Use depositBridgedWOETH() instead\n require(false, \"Deposit disabled\");\n }\n\n /**\n * @notice withdraw() function not used for this strategy\n */\n function withdraw(\n // solhint-disable-next-line no-unused-vars\n address _recipient,\n // solhint-disable-next-line no-unused-vars\n address _asset,\n // solhint-disable-next-line no-unused-vars\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(false, \"Withdrawal disabled\");\n }\n\n /**\n * @notice withdrawAll() function not used for this strategy\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n // Withdrawal disabled\n }\n\n function _abstractSetPToken(address, address) internal override {\n revert(\"No pTokens are used\");\n }\n\n function safeApproveAllTokens() external override {}\n\n /**\n * @inheritdoc InitializableAbstractStrategy\n */\n function removePToken(uint256) external override {\n revert(\"No pTokens are used\");\n }\n\n /**\n * @inheritdoc InitializableAbstractStrategy\n */\n function collectRewardTokens() external override {}\n}\n" + }, + "contracts/strategies/crosschain/AbstractCCTPIntegrator.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title AbstractCCTPIntegrator\n * @author Origin Protocol Inc\n *\n * @dev Abstract contract that contains all the logic used to integrate with CCTP.\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\n\nimport { ICCTPTokenMessenger, ICCTPMessageTransmitter, IMessageHandlerV2 } from \"../../interfaces/cctp/ICCTP.sol\";\n\nimport { CrossChainStrategyHelper } from \"./CrossChainStrategyHelper.sol\";\nimport { Governable } from \"../../governance/Governable.sol\";\nimport { BytesHelper } from \"../../utils/BytesHelper.sol\";\nimport \"../../utils/Helpers.sol\";\n\nabstract contract AbstractCCTPIntegrator is Governable, IMessageHandlerV2 {\n using SafeERC20 for IERC20;\n\n using BytesHelper for bytes;\n using CrossChainStrategyHelper for bytes;\n\n event LastTransferNonceUpdated(uint64 lastTransferNonce);\n event NonceProcessed(uint64 nonce);\n\n event CCTPMinFinalityThresholdSet(uint16 minFinalityThreshold);\n event CCTPFeePremiumBpsSet(uint16 feePremiumBps);\n event OperatorChanged(address operator);\n event TokensBridged(\n uint32 destinationDomain,\n address peerStrategy,\n address tokenAddress,\n uint256 tokenAmount,\n uint256 maxFee,\n uint32 minFinalityThreshold,\n bytes hookData\n );\n event MessageTransmitted(\n uint32 destinationDomain,\n address peerStrategy,\n uint32 minFinalityThreshold,\n bytes message\n );\n\n // Message body V2 fields\n // Ref: https://developers.circle.com/cctp/technical-guide#message-body\n // Ref: https://github.com/circlefin/evm-cctp-contracts/blob/master/src/messages/v2/BurnMessageV2.sol\n uint8 private constant BURN_MESSAGE_V2_VERSION_INDEX = 0;\n uint8 private constant BURN_MESSAGE_V2_BURN_TOKEN_INDEX = 4;\n uint8 private constant BURN_MESSAGE_V2_RECIPIENT_INDEX = 36;\n uint8 private constant BURN_MESSAGE_V2_AMOUNT_INDEX = 68;\n uint8 private constant BURN_MESSAGE_V2_MESSAGE_SENDER_INDEX = 100;\n uint8 private constant BURN_MESSAGE_V2_FEE_EXECUTED_INDEX = 164;\n uint8 private constant BURN_MESSAGE_V2_HOOK_DATA_INDEX = 228;\n\n /**\n * @notice Max transfer threshold imposed by the CCTP\n * Ref: https://developers.circle.com/cctp/evm-smart-contracts#depositforburn\n * @dev 10M USDC limit applies to both standard and fast transfer modes. The fast transfer mode has\n * an additional limitation that is not present on-chain and Circle may alter that amount off-chain\n * at their preference. The amount available for fast transfer can be queried here:\n * https://iris-api.circle.com/v2/fastBurn/USDC/allowance .\n * If a fast transfer token transaction has been issued and there is not enough allowance for it\n * the off-chain Iris component will re-attempt the transaction and if it fails it will fallback\n * to a standard transfer. Reference section 4.3 in the whitepaper:\n * https://6778953.fs1.hubspotusercontent-na1.net/hubfs/6778953/PDFs/Whitepapers/CCTPV2_White_Paper.pdf\n */\n uint256 public constant MAX_TRANSFER_AMOUNT = 10_000_000 * 10**6; // 10M USDC\n\n /// @notice Minimum transfer amount to avoid zero or dust transfers\n uint256 public constant MIN_TRANSFER_AMOUNT = 10**6;\n\n // CCTP contracts\n // This implementation assumes that remote and local chains have these contracts\n // deployed on the same addresses.\n /// @notice CCTP message transmitter contract\n ICCTPMessageTransmitter public immutable cctpMessageTransmitter;\n /// @notice CCTP token messenger contract\n ICCTPTokenMessenger public immutable cctpTokenMessenger;\n\n /// @notice USDC address on local chain\n address public immutable usdcToken;\n\n /// @notice USDC address on remote chain\n address public immutable peerUsdcToken;\n\n /// @notice Domain ID of the chain from which messages are accepted\n uint32 public immutable peerDomainID;\n\n /// @notice Strategy address on other chain\n address public immutable peerStrategy;\n\n /**\n * @notice Minimum finality threshold\n * Can be 1000 (safe, after 1 epoch) or 2000 (finalized, after 2 epochs).\n * Ref: https://developers.circle.com/cctp/technical-guide#finality-thresholds\n * @dev When configuring the contract for fast transfer we should check the available\n * allowance of USDC that can be bridged using fast mode:\n * wget https://iris-api.circle.com/v2/fastBurn/USDC/allowance\n */\n uint16 public minFinalityThreshold;\n\n /// @notice Fee premium in basis points\n uint16 public feePremiumBps;\n\n /// @notice Nonce of the last known deposit or withdrawal\n uint64 public lastTransferNonce;\n\n /// @notice Operator address: Can relay CCTP messages\n address public operator;\n\n /// @notice Mapping of processed nonces\n mapping(uint64 => bool) private nonceProcessed;\n\n // For future use\n uint256[48] private __gap;\n\n modifier onlyCCTPMessageTransmitter() {\n require(\n msg.sender == address(cctpMessageTransmitter),\n \"Caller is not CCTP transmitter\"\n );\n _;\n }\n\n modifier onlyOperator() {\n require(msg.sender == operator, \"Caller is not the Operator\");\n _;\n }\n\n /**\n * @notice Configuration for CCTP integration\n * @param cctpTokenMessenger Address of the CCTP token messenger contract\n * @param cctpMessageTransmitter Address of the CCTP message transmitter contract\n * @param peerDomainID Domain ID of the chain from which messages are accepted.\n * 0 for Ethereum, 6 for Base, etc.\n * Ref: https://developers.circle.com/cctp/cctp-supported-blockchains\n * @param peerStrategy Address of the master or remote strategy on the other chain\n * @param usdcToken USDC address on local chain\n */\n struct CCTPIntegrationConfig {\n address cctpTokenMessenger;\n address cctpMessageTransmitter;\n uint32 peerDomainID;\n address peerStrategy;\n address usdcToken;\n address peerUsdcToken;\n }\n\n constructor(CCTPIntegrationConfig memory _config) {\n require(_config.usdcToken != address(0), \"Invalid USDC address\");\n require(\n _config.peerUsdcToken != address(0),\n \"Invalid peer USDC address\"\n );\n require(\n _config.cctpTokenMessenger != address(0),\n \"Invalid CCTP config\"\n );\n require(\n _config.cctpMessageTransmitter != address(0),\n \"Invalid CCTP config\"\n );\n require(\n _config.peerStrategy != address(0),\n \"Invalid peer strategy address\"\n );\n\n cctpMessageTransmitter = ICCTPMessageTransmitter(\n _config.cctpMessageTransmitter\n );\n cctpTokenMessenger = ICCTPTokenMessenger(_config.cctpTokenMessenger);\n\n // Domain ID of the chain from which messages are accepted\n peerDomainID = _config.peerDomainID;\n\n // Strategy address on other chain, should\n // always be same as the proxy of this strategy\n peerStrategy = _config.peerStrategy;\n\n // USDC address on local chain\n usdcToken = _config.usdcToken;\n\n // Just a sanity check to ensure the base token is USDC\n uint256 _usdcTokenDecimals = Helpers.getDecimals(_config.usdcToken);\n string memory _usdcTokenSymbol = Helpers.getSymbol(_config.usdcToken);\n require(_usdcTokenDecimals == 6, \"Base token decimals must be 6\");\n require(\n keccak256(abi.encodePacked(_usdcTokenSymbol)) ==\n keccak256(abi.encodePacked(\"USDC\")),\n \"Token symbol must be USDC\"\n );\n\n // USDC address on remote chain\n peerUsdcToken = _config.peerUsdcToken;\n }\n\n /**\n * @dev Initialize the implementation contract\n * @param _operator Operator address\n * @param _minFinalityThreshold Minimum finality threshold\n * @param _feePremiumBps Fee premium in basis points\n */\n function _initialize(\n address _operator,\n uint16 _minFinalityThreshold,\n uint16 _feePremiumBps\n ) internal {\n _setOperator(_operator);\n _setMinFinalityThreshold(_minFinalityThreshold);\n _setFeePremiumBps(_feePremiumBps);\n\n // Nonce starts at 1, so assume nonce 0 as processed.\n // NOTE: This will cause the deposit/withdraw to fail if the\n // strategy is not initialized properly (which is expected).\n nonceProcessed[0] = true;\n }\n\n /***************************************\n Settings\n ****************************************/\n /**\n * @dev Set the operator address\n * @param _operator Operator address\n */\n function setOperator(address _operator) external onlyGovernor {\n _setOperator(_operator);\n }\n\n /**\n * @dev Set the operator address\n * @param _operator Operator address\n */\n function _setOperator(address _operator) internal {\n operator = _operator;\n emit OperatorChanged(_operator);\n }\n\n /**\n * @dev Set the minimum finality threshold at which\n * the message is considered to be finalized to relay.\n * Only accepts a value of 1000 (Safe, after 1 epoch) or\n * 2000 (Finalized, after 2 epochs).\n * @param _minFinalityThreshold Minimum finality threshold\n */\n function setMinFinalityThreshold(uint16 _minFinalityThreshold)\n external\n onlyGovernor\n {\n _setMinFinalityThreshold(_minFinalityThreshold);\n }\n\n /**\n * @dev Set the minimum finality threshold\n * @param _minFinalityThreshold Minimum finality threshold\n */\n function _setMinFinalityThreshold(uint16 _minFinalityThreshold) internal {\n // 1000 for fast transfer and 2000 for standard transfer\n require(\n _minFinalityThreshold == 1000 || _minFinalityThreshold == 2000,\n \"Invalid threshold\"\n );\n\n minFinalityThreshold = _minFinalityThreshold;\n emit CCTPMinFinalityThresholdSet(_minFinalityThreshold);\n }\n\n /**\n * @dev Set the fee premium in basis points.\n * Cannot be higher than 30% (3000 basis points).\n * @param _feePremiumBps Fee premium in basis points\n */\n function setFeePremiumBps(uint16 _feePremiumBps) external onlyGovernor {\n _setFeePremiumBps(_feePremiumBps);\n }\n\n /**\n * @dev Set the fee premium in basis points\n * Cannot be higher than 30% (3000 basis points).\n * Ref: https://developers.circle.com/cctp/technical-guide#fees\n * @param _feePremiumBps Fee premium in basis points\n */\n function _setFeePremiumBps(uint16 _feePremiumBps) internal {\n require(_feePremiumBps <= 3000, \"Fee premium too high\"); // 30%\n\n feePremiumBps = _feePremiumBps;\n emit CCTPFeePremiumBpsSet(_feePremiumBps);\n }\n\n /***************************************\n CCTP message handling\n ****************************************/\n\n /**\n * @dev Handles a finalized CCTP message\n * @param sourceDomain Source domain of the message\n * @param sender Sender of the message\n * @param finalityThresholdExecuted Fidelity threshold executed\n * @param messageBody Message body\n */\n function handleReceiveFinalizedMessage(\n uint32 sourceDomain,\n bytes32 sender,\n uint32 finalityThresholdExecuted,\n bytes memory messageBody\n ) external override onlyCCTPMessageTransmitter returns (bool) {\n // Make sure the finality threshold at execution is at least 2000\n require(\n finalityThresholdExecuted >= 2000,\n \"Finality threshold too low\"\n );\n\n return _handleReceivedMessage(sourceDomain, sender, messageBody);\n }\n\n /**\n * @dev Handles an unfinalized but safe CCTP message\n * @param sourceDomain Source domain of the message\n * @param sender Sender of the message\n * @param finalityThresholdExecuted Fidelity threshold executed\n * @param messageBody Message body\n */\n function handleReceiveUnfinalizedMessage(\n uint32 sourceDomain,\n bytes32 sender,\n uint32 finalityThresholdExecuted,\n bytes memory messageBody\n ) external override onlyCCTPMessageTransmitter returns (bool) {\n // Make sure the contract is configured to handle unfinalized messages\n require(\n minFinalityThreshold == 1000,\n \"Unfinalized messages are not supported\"\n );\n // Make sure the finality threshold at execution is at least 1000\n require(\n finalityThresholdExecuted >= 1000,\n \"Finality threshold too low\"\n );\n\n return _handleReceivedMessage(sourceDomain, sender, messageBody);\n }\n\n /**\n * @dev Handles a CCTP message\n * @param sourceDomain Source domain of the message\n * @param sender Sender of the message\n * @param messageBody Message body\n */\n function _handleReceivedMessage(\n uint32 sourceDomain,\n bytes32 sender,\n bytes memory messageBody\n ) internal returns (bool) {\n require(sourceDomain == peerDomainID, \"Unknown Source Domain\");\n\n // Extract address from bytes32 (CCTP stores addresses as right-padded bytes32)\n address senderAddress = address(uint160(uint256(sender)));\n require(senderAddress == peerStrategy, \"Unknown Sender\");\n\n _onMessageReceived(messageBody);\n\n return true;\n }\n\n /**\n * @dev Sends tokens to the peer strategy using CCTP Token Messenger\n * @param tokenAmount Amount of tokens to send\n * @param hookData Hook data\n */\n function _sendTokens(uint256 tokenAmount, bytes memory hookData)\n internal\n virtual\n {\n // CCTP has a maximum transfer amount of 10M USDC per tx\n require(tokenAmount <= MAX_TRANSFER_AMOUNT, \"Token amount too high\");\n\n // Approve only what needs to be transferred\n IERC20(usdcToken).safeApprove(address(cctpTokenMessenger), tokenAmount);\n\n // Compute the max fee to be paid.\n // Ref: https://developers.circle.com/cctp/evm-smart-contracts#getminfeeamount\n // The right way to compute fees would be to use CCTP's getMinFeeAmount function.\n // The issue is that the getMinFeeAmount is not present on v2.0 contracts, but is on\n // v2.1. Some of CCTP's deployed contracts are v2.0, some are v2.1.\n // We will only be using standard transfers and fee on those is 0 for now. If they\n // ever start implementing fee for standard transfers or if we decide to use fast\n // trasnfer, we can use feePremiumBps as a workaround.\n uint256 maxFee = feePremiumBps > 0\n ? (tokenAmount * feePremiumBps) / 10000\n : 0;\n\n // Send tokens to the peer strategy using CCTP Token Messenger\n cctpTokenMessenger.depositForBurnWithHook(\n tokenAmount,\n peerDomainID,\n bytes32(uint256(uint160(peerStrategy))),\n address(usdcToken),\n bytes32(uint256(uint160(peerStrategy))),\n maxFee,\n uint32(minFinalityThreshold),\n hookData\n );\n\n emit TokensBridged(\n peerDomainID,\n peerStrategy,\n usdcToken,\n tokenAmount,\n maxFee,\n uint32(minFinalityThreshold),\n hookData\n );\n }\n\n /**\n * @dev Sends a message to the peer strategy using CCTP Message Transmitter\n * @param message Payload of the message to send\n */\n function _sendMessage(bytes memory message) internal virtual {\n cctpMessageTransmitter.sendMessage(\n peerDomainID,\n bytes32(uint256(uint160(peerStrategy))),\n bytes32(uint256(uint160(peerStrategy))),\n uint32(minFinalityThreshold),\n message\n );\n\n emit MessageTransmitted(\n peerDomainID,\n peerStrategy,\n uint32(minFinalityThreshold),\n message\n );\n }\n\n /**\n * @dev Receives a message from the peer strategy on the other chain,\n * does some basic checks and relays it to the local MessageTransmitterV2.\n * If the message is a burn message, it will also handle the hook data\n * and call the _onTokenReceived function.\n * @param message Payload of the message to send\n * @param attestation Attestation of the message\n */\n function relay(bytes memory message, bytes memory attestation)\n external\n onlyOperator\n {\n (\n uint32 version,\n uint32 sourceDomainID,\n address sender,\n address recipient,\n bytes memory messageBody\n ) = message.decodeMessageHeader();\n\n // Ensure that it's a CCTP message\n require(\n version == CrossChainStrategyHelper.CCTP_MESSAGE_VERSION,\n \"Invalid CCTP message version\"\n );\n\n // Ensure that the source domain is the peer domain\n require(sourceDomainID == peerDomainID, \"Unknown Source Domain\");\n\n // Ensure message body version\n version = messageBody.extractUint32(BURN_MESSAGE_V2_VERSION_INDEX);\n\n // NOTE: There's a possibility that the CCTP Token Messenger might\n // send other types of messages in future, not just the burn message.\n // If it ever comes to that, this shouldn't cause us any problems\n // because it has to still go through the followign checks:\n // - version check\n // - message body length check\n // - sender and recipient (which should be in the same slots and same as address(this))\n // - hook data handling (which will revert even if all the above checks pass)\n bool isBurnMessageV1 = sender == address(cctpTokenMessenger);\n\n if (isBurnMessageV1) {\n // Handle burn message\n require(\n version == 1 &&\n messageBody.length >= BURN_MESSAGE_V2_HOOK_DATA_INDEX,\n \"Invalid burn message\"\n );\n\n // Ensure the burn token is USDC\n address burnToken = messageBody.extractAddress(\n BURN_MESSAGE_V2_BURN_TOKEN_INDEX\n );\n require(burnToken == peerUsdcToken, \"Invalid burn token\");\n\n // Address of caller of depositForBurn (or depositForBurnWithCaller) on source domain\n sender = messageBody.extractAddress(\n BURN_MESSAGE_V2_MESSAGE_SENDER_INDEX\n );\n\n recipient = messageBody.extractAddress(\n BURN_MESSAGE_V2_RECIPIENT_INDEX\n );\n } else {\n // We handle only Burn message or our custom messagee\n require(\n version == CrossChainStrategyHelper.ORIGIN_MESSAGE_VERSION,\n \"Unsupported message version\"\n );\n }\n\n // Ensure the recipient is this contract\n // Both sender and recipient should be deployed to same address on both chains.\n require(address(this) == recipient, \"Unexpected recipient address\");\n require(sender == peerStrategy, \"Incorrect sender/recipient address\");\n\n // Relay the message\n // This step also mints USDC and transfers it to the recipient wallet\n bool relaySuccess = cctpMessageTransmitter.receiveMessage(\n message,\n attestation\n );\n require(relaySuccess, \"Receive message failed\");\n\n if (isBurnMessageV1) {\n // Extract the hook data from the message body\n bytes memory hookData = messageBody.extractSlice(\n BURN_MESSAGE_V2_HOOK_DATA_INDEX,\n messageBody.length\n );\n\n // Extract the token amount from the message body\n uint256 tokenAmount = messageBody.extractUint256(\n BURN_MESSAGE_V2_AMOUNT_INDEX\n );\n\n // Extract the fee executed from the message body\n uint256 feeExecuted = messageBody.extractUint256(\n BURN_MESSAGE_V2_FEE_EXECUTED_INDEX\n );\n\n // Call the _onTokenReceived function\n _onTokenReceived(tokenAmount - feeExecuted, feeExecuted, hookData);\n }\n }\n\n /***************************************\n Message utils\n ****************************************/\n\n /***************************************\n Nonce Handling\n ****************************************/\n /**\n * @dev Checks if the last known transfer is pending.\n * Nonce starts at 1, so 0 is disregarded.\n * @return True if a transfer is pending, false otherwise\n */\n function isTransferPending() public view returns (bool) {\n return !nonceProcessed[lastTransferNonce];\n }\n\n /**\n * @dev Checks if a given nonce is processed.\n * Nonce starts at 1, so 0 is disregarded.\n * @param nonce Nonce to check\n * @return True if the nonce is processed, false otherwise\n */\n function isNonceProcessed(uint64 nonce) public view returns (bool) {\n return nonceProcessed[nonce];\n }\n\n /**\n * @dev Marks a given nonce as processed.\n * Can only mark nonce as processed once. New nonce should\n * always be greater than the last known nonce. Also updates\n * the last known nonce.\n * @param nonce Nonce to mark as processed\n */\n function _markNonceAsProcessed(uint64 nonce) internal {\n uint64 lastNonce = lastTransferNonce;\n\n // Can only mark latest nonce as processed\n // Master strategy when receiving a message from the remote strategy\n // will have lastNone == nonce, as the nonce is increase at the start\n // of deposit / withdrawal flow.\n // Remote strategy will have lastNonce < nonce, as a new nonce initiated\n // from master will be greater than the last one.\n require(nonce >= lastNonce, \"Nonce too low\");\n // Can only mark nonce as processed once\n require(!nonceProcessed[nonce], \"Nonce already processed\");\n\n nonceProcessed[nonce] = true;\n emit NonceProcessed(nonce);\n\n if (nonce != lastNonce) {\n // Update last known nonce\n lastTransferNonce = nonce;\n emit LastTransferNonceUpdated(nonce);\n }\n }\n\n /**\n * @dev Gets the next nonce to use.\n * Nonce starts at 1, so 0 is disregarded.\n * Reverts if last nonce hasn't been processed yet.\n * @return Next nonce\n */\n function _getNextNonce() internal returns (uint64) {\n uint64 nonce = lastTransferNonce;\n\n require(nonceProcessed[nonce], \"Pending token transfer\");\n\n nonce = nonce + 1;\n lastTransferNonce = nonce;\n emit LastTransferNonceUpdated(nonce);\n\n return nonce;\n }\n\n /***************************************\n Inheritence overrides\n ****************************************/\n\n /**\n * @dev Called when the USDC is received from the CCTP\n * @param tokenAmount The actual amount of USDC received (amount sent - fee executed)\n * @param feeExecuted The fee executed\n * @param payload The payload of the message (hook data)\n */\n function _onTokenReceived(\n uint256 tokenAmount,\n uint256 feeExecuted,\n bytes memory payload\n ) internal virtual;\n\n /**\n * @dev Called when the message is received\n * @param payload The payload of the message\n */\n function _onMessageReceived(bytes memory payload) internal virtual;\n}\n" + }, + "contracts/strategies/crosschain/CrossChainMasterStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Yearn V3 Master Strategy - the Mainnet part\n * @author Origin Protocol Inc\n *\n * @dev This strategy can only perform 1 deposit or withdrawal at a time. For that\n * reason it shouldn't be configured as an asset default strategy.\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { AbstractCCTPIntegrator } from \"./AbstractCCTPIntegrator.sol\";\nimport { CrossChainStrategyHelper } from \"./CrossChainStrategyHelper.sol\";\n\ncontract CrossChainMasterStrategy is\n AbstractCCTPIntegrator,\n InitializableAbstractStrategy\n{\n using SafeERC20 for IERC20;\n using CrossChainStrategyHelper for bytes;\n\n /**\n * @notice Remote strategy balance\n * @dev The remote balance is cached and might not reflect the actual\n * real-time balance of the remote strategy.\n */\n uint256 public remoteStrategyBalance;\n\n /// @notice Amount that's bridged due to a pending Deposit process\n /// but with no acknowledgement from the remote strategy yet\n uint256 public pendingAmount;\n\n uint256 internal constant MAX_BALANCE_CHECK_AGE = 1 days;\n\n event RemoteStrategyBalanceUpdated(uint256 balance);\n event WithdrawRequested(address indexed asset, uint256 amount);\n event WithdrawAllSkipped();\n event BalanceCheckIgnored(uint64 nonce, uint256 timestamp, bool isTooOld);\n\n /**\n * @param _stratConfig The platform and OToken vault addresses\n */\n constructor(\n BaseStrategyConfig memory _stratConfig,\n CCTPIntegrationConfig memory _cctpConfig\n )\n InitializableAbstractStrategy(_stratConfig)\n AbstractCCTPIntegrator(_cctpConfig)\n {\n require(\n _stratConfig.platformAddress == address(0),\n \"Invalid platform address\"\n );\n require(\n _stratConfig.vaultAddress != address(0),\n \"Invalid Vault address\"\n );\n }\n\n /**\n * @dev Initialize the strategy implementation\n * @param _operator Address of the operator\n * @param _minFinalityThreshold Minimum finality threshold\n * @param _feePremiumBps Fee premium in basis points\n */\n function initialize(\n address _operator,\n uint16 _minFinalityThreshold,\n uint16 _feePremiumBps\n ) external virtual onlyGovernor initializer {\n _initialize(_operator, _minFinalityThreshold, _feePremiumBps);\n\n address[] memory rewardTokens = new address[](0);\n address[] memory assets = new address[](0);\n address[] memory pTokens = new address[](0);\n\n InitializableAbstractStrategy._initialize(\n rewardTokens,\n assets,\n pTokens\n );\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function depositAll() external override onlyVault nonReentrant {\n uint256 balance = IERC20(usdcToken).balanceOf(address(this));\n // Deposit if balance is greater than 1 USDC\n if (balance >= MIN_TRANSFER_AMOUNT) {\n _deposit(usdcToken, balance);\n }\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_recipient == vaultAddress, \"Only Vault can withdraw\");\n _withdraw(_asset, _amount);\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n if (isTransferPending()) {\n // Do nothing if there is a pending transfer\n // Note: We never want withdrawAll to fail, so\n // emit an event to indicate that the withdrawal was skipped\n emit WithdrawAllSkipped();\n return;\n }\n\n // Withdraw everything in Remote strategy\n uint256 _remoteBalance = remoteStrategyBalance;\n if (_remoteBalance < MIN_TRANSFER_AMOUNT) {\n // Do nothing if there is less than 1 USDC in the Remote strategy\n return;\n }\n\n _withdraw(\n usdcToken,\n _remoteBalance > MAX_TRANSFER_AMOUNT\n ? MAX_TRANSFER_AMOUNT\n : _remoteBalance\n );\n }\n\n /**\n * @notice Check the balance of the strategy that includes\n * the balance of the asset on this contract,\n * the amount of the asset being bridged,\n * and the balance reported by the Remote strategy.\n * @param _asset Address of the asset to check\n * @return balance Total balance of the asset\n */\n function checkBalance(address _asset)\n public\n view\n override\n returns (uint256 balance)\n {\n require(_asset == usdcToken, \"Unsupported asset\");\n\n // USDC balance on this contract\n // + USDC being bridged\n // + USDC cached in the corresponding Remote part of this contract\n return\n IERC20(usdcToken).balanceOf(address(this)) +\n pendingAmount +\n remoteStrategyBalance;\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == usdcToken;\n }\n\n /// @inheritdoc InitializableAbstractStrategy\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {}\n\n /// @inheritdoc InitializableAbstractStrategy\n function _abstractSetPToken(address, address) internal override {}\n\n /// @inheritdoc InitializableAbstractStrategy\n function collectRewardTokens()\n external\n override\n onlyHarvesterOrStrategist\n nonReentrant\n {}\n\n /// @inheritdoc AbstractCCTPIntegrator\n function _onMessageReceived(bytes memory payload) internal override {\n if (\n payload.getMessageType() ==\n CrossChainStrategyHelper.BALANCE_CHECK_MESSAGE\n ) {\n // Received when Remote strategy checks the balance\n _processBalanceCheckMessage(payload);\n return;\n }\n\n revert(\"Unknown message type\");\n }\n\n /// @inheritdoc AbstractCCTPIntegrator\n function _onTokenReceived(\n uint256 tokenAmount,\n // solhint-disable-next-line no-unused-vars\n uint256 feeExecuted,\n bytes memory payload\n ) internal override {\n uint64 _nonce = lastTransferNonce;\n\n // Should be expecting an acknowledgement\n require(!isNonceProcessed(_nonce), \"Nonce already processed\");\n\n // Now relay to the regular flow\n // NOTE: Calling _onMessageReceived would mean that we are bypassing a\n // few checks that the regular flow does (like sourceDomainID check\n // and sender check in `handleReceiveFinalizedMessage`). However,\n // CCTPMessageRelayer relays the message first (which will go through\n // all the checks) and not update balance and then finally calls this\n // `_onTokenReceived` which will update the balance.\n // So, if any of the checks fail during the first no-balance-update flow,\n // this won't happen either, since the tx would revert.\n _onMessageReceived(payload);\n\n // Send any tokens in the contract to the Vault\n uint256 usdcBalance = IERC20(usdcToken).balanceOf(address(this));\n // Should always have enough tokens\n require(usdcBalance >= tokenAmount, \"Insufficient balance\");\n // Transfer all tokens to the Vault to not leave any dust\n IERC20(usdcToken).safeTransfer(vaultAddress, usdcBalance);\n\n // Emit withdrawal amount\n emit Withdrawal(usdcToken, usdcToken, usdcBalance);\n }\n\n /**\n * @dev Bridge and deposit asset into the remote strategy\n * @param _asset Address of the asset to deposit\n * @param depositAmount Amount of the asset to deposit\n */\n function _deposit(address _asset, uint256 depositAmount) internal virtual {\n require(_asset == usdcToken, \"Unsupported asset\");\n require(pendingAmount == 0, \"Unexpected pending amount\");\n // Deposit at least 1 USDC\n require(\n depositAmount >= MIN_TRANSFER_AMOUNT,\n \"Deposit amount too small\"\n );\n require(\n depositAmount <= MAX_TRANSFER_AMOUNT,\n \"Deposit amount too high\"\n );\n\n // Get the next nonce\n // Note: reverts if a transfer is pending\n uint64 nonce = _getNextNonce();\n\n // Set pending amount\n pendingAmount = depositAmount;\n\n // Build deposit message payload\n bytes memory message = CrossChainStrategyHelper.encodeDepositMessage(\n nonce,\n depositAmount\n );\n\n // Send deposit message to the remote strategy\n _sendTokens(depositAmount, message);\n\n // Emit deposit event\n emit Deposit(_asset, _asset, depositAmount);\n }\n\n /**\n * @dev Send a withdraw request to the remote strategy\n * @param _asset Address of the asset to withdraw\n * @param _amount Amount of the asset to withdraw\n */\n function _withdraw(address _asset, uint256 _amount) internal virtual {\n require(_asset == usdcToken, \"Unsupported asset\");\n // Withdraw at least 1 USDC\n require(_amount >= MIN_TRANSFER_AMOUNT, \"Withdraw amount too small\");\n require(\n _amount <= remoteStrategyBalance,\n \"Withdraw amount exceeds remote strategy balance\"\n );\n require(\n _amount <= MAX_TRANSFER_AMOUNT,\n \"Withdraw amount exceeds max transfer amount\"\n );\n\n // Get the next nonce\n // Note: reverts if a transfer is pending\n uint64 nonce = _getNextNonce();\n\n // Build and send withdrawal message with payload\n bytes memory message = CrossChainStrategyHelper.encodeWithdrawMessage(\n nonce,\n _amount\n );\n _sendMessage(message);\n\n // Emit WithdrawRequested event here,\n // Withdraw will be emitted in _onTokenReceived\n emit WithdrawRequested(usdcToken, _amount);\n }\n\n /**\n * @dev Process balance check:\n * - Confirms a deposit to the remote strategy\n * - Skips balance update if there's a pending withdrawal\n * - Updates the remote strategy balance\n * @param message The message containing the nonce and balance\n */\n function _processBalanceCheckMessage(bytes memory message)\n internal\n virtual\n {\n // Decode the message\n // When transferConfirmation is true, it means that the message is a result of a deposit or a withdrawal\n // process.\n (\n uint64 nonce,\n uint256 balance,\n bool transferConfirmation,\n uint256 timestamp\n ) = message.decodeBalanceCheckMessage();\n // Get the last cached nonce\n uint64 _lastCachedNonce = lastTransferNonce;\n\n if (nonce != _lastCachedNonce) {\n // If nonce is not the last cached nonce, it is an outdated message\n // Ignore it\n return;\n }\n\n // A received message nonce not yet processed indicates there is a\n // deposit or withdrawal in progress.\n bool transferInProgress = isTransferPending();\n\n if (transferInProgress) {\n if (transferConfirmation) {\n // Apply the effects of the deposit / withdrawal completion\n _markNonceAsProcessed(nonce);\n pendingAmount = 0;\n } else {\n // A balanceCheck arrived that is not part of the deposit / withdrawal process\n // that has been generated on the Remote contract after the deposit / withdrawal which is\n // still pending. This can happen when the CCTP bridge delivers the messages out of order.\n // Ignore it, since the pending deposit / withdrawal must first be cofirmed.\n emit BalanceCheckIgnored(nonce, timestamp, false);\n return;\n }\n } else {\n if (block.timestamp > timestamp + MAX_BALANCE_CHECK_AGE) {\n // Balance check is too old, ignore it\n emit BalanceCheckIgnored(nonce, timestamp, true);\n return;\n }\n }\n\n // At this point update the strategy balance the balanceCheck message is either:\n // - a confirmation of a deposit / withdrawal\n // - a message that updates balances when no deposit / withdrawal is in progress\n remoteStrategyBalance = balance;\n emit RemoteStrategyBalanceUpdated(balance);\n }\n}\n" + }, + "contracts/strategies/crosschain/CrossChainRemoteStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title CrossChainRemoteStrategy\n * @author Origin Protocol Inc\n *\n * @dev Part of the cross-chain strategy that lives on the remote chain.\n * Handles deposits and withdrawals from the master strategy on peer chain\n * and locally deposits the funds to a 4626 compatible vault.\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IERC4626 } from \"../../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IVaultV2 } from \"../../interfaces/morpho/IVaultV2.sol\";\nimport { Generalized4626Strategy } from \"../Generalized4626Strategy.sol\";\nimport { AbstractCCTPIntegrator } from \"./AbstractCCTPIntegrator.sol\";\nimport { CrossChainStrategyHelper } from \"./CrossChainStrategyHelper.sol\";\nimport { InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { Strategizable } from \"../../governance/Strategizable.sol\";\nimport { MorphoV2VaultUtils } from \"../MorphoV2VaultUtils.sol\";\n\ncontract CrossChainRemoteStrategy is\n AbstractCCTPIntegrator,\n Generalized4626Strategy,\n Strategizable\n{\n using SafeERC20 for IERC20;\n using CrossChainStrategyHelper for bytes;\n\n event DepositUnderlyingFailed(string reason);\n event WithdrawalFailed(uint256 amountRequested, uint256 amountAvailable);\n event WithdrawUnderlyingFailed(string reason);\n\n modifier onlyOperatorOrStrategistOrGovernor() {\n require(\n msg.sender == operator ||\n msg.sender == strategistAddr ||\n isGovernor(),\n \"Caller is not the Operator, Strategist or the Governor\"\n );\n _;\n }\n\n modifier onlyGovernorOrStrategist()\n override(InitializableAbstractStrategy, Strategizable) {\n require(\n msg.sender == strategistAddr || isGovernor(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n CCTPIntegrationConfig memory _cctpConfig\n )\n AbstractCCTPIntegrator(_cctpConfig)\n Generalized4626Strategy(_baseConfig, _cctpConfig.usdcToken)\n {\n require(usdcToken == address(assetToken), \"Token mismatch\");\n require(\n _baseConfig.platformAddress != address(0),\n \"Invalid platform address\"\n );\n // Vault address must always be address(0) for the remote strategy\n require(\n _baseConfig.vaultAddress == address(0),\n \"Invalid vault address\"\n );\n }\n\n /**\n * @dev Initialize the strategy implementation\n * @param _strategist Address of the strategist\n * @param _operator Address of the operator\n * @param _minFinalityThreshold Minimum finality threshold\n * @param _feePremiumBps Fee premium in basis points\n */\n function initialize(\n address _strategist,\n address _operator,\n uint16 _minFinalityThreshold,\n uint16 _feePremiumBps\n ) external virtual onlyGovernor initializer {\n _initialize(_operator, _minFinalityThreshold, _feePremiumBps);\n _setStrategistAddr(_strategist);\n\n address[] memory rewardTokens = new address[](0);\n address[] memory assets = new address[](1);\n address[] memory pTokens = new address[](1);\n\n assets[0] = address(usdcToken);\n pTokens[0] = address(platformAddress);\n\n InitializableAbstractStrategy._initialize(\n rewardTokens,\n assets,\n pTokens\n );\n }\n\n /// @inheritdoc Generalized4626Strategy\n function deposit(address _asset, uint256 _amount)\n external\n virtual\n override\n onlyGovernorOrStrategist\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /// @inheritdoc Generalized4626Strategy\n function depositAll()\n external\n virtual\n override\n onlyGovernorOrStrategist\n nonReentrant\n {\n _deposit(usdcToken, IERC20(usdcToken).balanceOf(address(this)));\n }\n\n /// @inheritdoc Generalized4626Strategy\n /// @dev Interface requires a recipient, but for compatibility it must be address(this).\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external virtual override onlyGovernorOrStrategist nonReentrant {\n _withdraw(_recipient, _asset, _amount);\n }\n\n /// @inheritdoc Generalized4626Strategy\n function withdrawAll()\n external\n virtual\n override\n onlyGovernorOrStrategist\n nonReentrant\n {\n IERC4626 platform = IERC4626(platformAddress);\n uint256 availableMorphoVault = MorphoV2VaultUtils.maxWithdrawableAssets(\n platformAddress,\n usdcToken\n );\n uint256 amountToWithdraw = Math.min(\n availableMorphoVault,\n platform.previewRedeem(platform.balanceOf(address(this)))\n );\n\n if (amountToWithdraw > 0) {\n _withdraw(address(this), usdcToken, amountToWithdraw);\n }\n }\n\n /// @inheritdoc AbstractCCTPIntegrator\n function _onMessageReceived(bytes memory payload) internal override {\n uint32 messageType = payload.getMessageType();\n if (messageType == CrossChainStrategyHelper.DEPOSIT_MESSAGE) {\n // Received when Master strategy sends tokens to the remote strategy\n // Do nothing because we receive acknowledgement with token transfer,\n // so _onTokenReceived will handle it\n } else if (messageType == CrossChainStrategyHelper.WITHDRAW_MESSAGE) {\n // Received when Master strategy requests a withdrawal\n _processWithdrawMessage(payload);\n } else {\n revert(\"Unknown message type\");\n }\n }\n\n /**\n * @dev Process deposit message from peer strategy\n * @param tokenAmount Amount of tokens received\n * @param feeExecuted Fee executed\n * @param payload Payload of the message\n */\n function _processDepositMessage(\n // solhint-disable-next-line no-unused-vars\n uint256 tokenAmount,\n // solhint-disable-next-line no-unused-vars\n uint256 feeExecuted,\n bytes memory payload\n ) internal virtual {\n (uint64 nonce, ) = payload.decodeDepositMessage();\n\n // Replay protection is part of the _markNonceAsProcessed function\n _markNonceAsProcessed(nonce);\n\n // Deposit everything we got, not just what was bridged\n uint256 balance = IERC20(usdcToken).balanceOf(address(this));\n\n // Underlying call to deposit funds can fail. It mustn't affect the overall\n // flow as confirmation message should still be sent.\n if (balance >= MIN_TRANSFER_AMOUNT) {\n _deposit(usdcToken, balance);\n }\n\n // Send balance check message to the peer strategy\n bytes memory message = CrossChainStrategyHelper\n .encodeBalanceCheckMessage(\n lastTransferNonce,\n checkBalance(usdcToken),\n true,\n block.timestamp\n );\n _sendMessage(message);\n }\n\n /**\n * @dev Deposit assets by converting them to shares\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal override {\n // By design, this function should not revert. Otherwise, it'd\n // not be able to process messages and might freeze the contracts\n // state. However these two require statements would never fail\n // in every function invoking this. The same kind of checks should\n // be enforced in all the calling functions for these two and any\n // other require statements added to this function.\n require(_amount > 0, \"Must deposit something\");\n require(_asset == address(usdcToken), \"Unexpected asset address\");\n\n // This call can fail, and the failure doesn't need to bubble up to the _processDepositMessage function\n // as the flow is not affected by the failure.\n\n try IERC4626(platformAddress).deposit(_amount, address(this)) {\n emit Deposit(_asset, address(shareToken), _amount);\n } catch Error(string memory reason) {\n emit DepositUnderlyingFailed(\n string(abi.encodePacked(\"Deposit failed: \", reason))\n );\n } catch (bytes memory lowLevelData) {\n emit DepositUnderlyingFailed(\n string(\n abi.encodePacked(\n \"Deposit failed: low-level call failed with data \",\n lowLevelData\n )\n )\n );\n }\n }\n\n /**\n * @dev Process withdrawal message from peer strategy\n * @param payload Payload of the message\n */\n function _processWithdrawMessage(bytes memory payload) internal virtual {\n (uint64 nonce, uint256 withdrawAmount) = payload\n .decodeWithdrawMessage();\n\n // Replay protection is part of the _markNonceAsProcessed function\n _markNonceAsProcessed(nonce);\n\n uint256 usdcBalance = IERC20(usdcToken).balanceOf(address(this));\n\n if (usdcBalance < withdrawAmount) {\n // Withdraw the missing funds from the remote strategy. This call can fail and\n // the failure doesn't bubble up to the _processWithdrawMessage function\n _withdraw(address(this), usdcToken, withdrawAmount - usdcBalance);\n\n // Update the possible increase in the balance on the contract.\n usdcBalance = IERC20(usdcToken).balanceOf(address(this));\n }\n\n // Check balance after withdrawal\n uint256 strategyBalance = checkBalance(usdcToken);\n\n // If there are some tokens to be sent AND the balance is sufficient\n // to satisfy the withdrawal request then send the funds to the peer strategy.\n // In case a direct withdraw(All) has previously been called\n // there is a possibility of USDC funds remaining on the contract.\n // A separate withdraw to extract or deposit to the Morpho vault needs to be\n // initiated from the peer Master strategy to utilise USDC funds.\n if (\n withdrawAmount >= MIN_TRANSFER_AMOUNT &&\n usdcBalance >= withdrawAmount\n ) {\n // The new balance on the contract needs to have USDC subtracted from it as\n // that will be withdrawn in the next step\n bytes memory message = CrossChainStrategyHelper\n .encodeBalanceCheckMessage(\n lastTransferNonce,\n strategyBalance - withdrawAmount,\n true,\n block.timestamp\n );\n _sendTokens(withdrawAmount, message);\n } else {\n // Contract either:\n // - only has small dust amount of USDC\n // - doesn't have sufficient funds to satisfy the withdrawal request\n // In both cases send the balance update message to the peer strategy.\n bytes memory message = CrossChainStrategyHelper\n .encodeBalanceCheckMessage(\n lastTransferNonce,\n strategyBalance,\n true,\n block.timestamp\n );\n _sendMessage(message);\n emit WithdrawalFailed(withdrawAmount, usdcBalance);\n }\n }\n\n /**\n * @dev Withdraw asset by burning shares\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal override {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient == address(this), \"Invalid recipient\");\n require(_asset == address(usdcToken), \"Unexpected asset address\");\n\n // This call can fail, and the failure doesn't need to bubble up to the _processWithdrawMessage function\n // as the flow is not affected by the failure.\n try\n // slither-disable-next-line unused-return\n IERC4626(platformAddress).withdraw(\n _amount,\n address(this),\n address(this)\n )\n {\n emit Withdrawal(_asset, address(shareToken), _amount);\n } catch Error(string memory reason) {\n emit WithdrawUnderlyingFailed(\n string(abi.encodePacked(\"Withdrawal failed: \", reason))\n );\n } catch (bytes memory lowLevelData) {\n emit WithdrawUnderlyingFailed(\n string(\n abi.encodePacked(\n \"Withdrawal failed: low-level call failed with data \",\n lowLevelData\n )\n )\n );\n }\n }\n\n /**\n * @dev Process token received message from peer strategy\n * @param tokenAmount Amount of tokens received\n * @param feeExecuted Fee executed\n * @param payload Payload of the message\n */\n function _onTokenReceived(\n uint256 tokenAmount,\n uint256 feeExecuted,\n bytes memory payload\n ) internal override {\n uint32 messageType = payload.getMessageType();\n\n require(\n messageType == CrossChainStrategyHelper.DEPOSIT_MESSAGE,\n \"Invalid message type\"\n );\n\n _processDepositMessage(tokenAmount, feeExecuted, payload);\n }\n\n /**\n * @dev Send balance update message to the peer strategy\n */\n function sendBalanceUpdate()\n external\n virtual\n onlyOperatorOrStrategistOrGovernor\n {\n uint256 balance = checkBalance(usdcToken);\n bytes memory message = CrossChainStrategyHelper\n .encodeBalanceCheckMessage(\n lastTransferNonce,\n balance,\n false,\n block.timestamp\n );\n _sendMessage(message);\n }\n\n /**\n * @notice Get the total asset value held in the platform and contract\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform and contract\n */\n function checkBalance(address _asset)\n public\n view\n override\n returns (uint256)\n {\n require(_asset == usdcToken, \"Unexpected asset address\");\n /**\n * Balance of USDC on the contract is counted towards the total balance, since a deposit\n * to the Morpho V2 might fail and the USDC might remain on this contract as a result of a\n * bridged transfer.\n */\n uint256 balanceOnContract = IERC20(usdcToken).balanceOf(address(this));\n\n IERC4626 platform = IERC4626(platformAddress);\n return\n platform.previewRedeem(platform.balanceOf(address(this))) +\n balanceOnContract;\n }\n}\n" + }, + "contracts/strategies/crosschain/CrossChainStrategyHelper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title CrossChainStrategyHelper\n * @author Origin Protocol Inc\n * @dev This library is used to encode and decode the messages for the cross-chain strategy.\n * It is used to ensure that the messages are valid and to get the message version and type.\n */\n\nimport { BytesHelper } from \"../../utils/BytesHelper.sol\";\n\nlibrary CrossChainStrategyHelper {\n using BytesHelper for bytes;\n\n uint32 public constant DEPOSIT_MESSAGE = 1;\n uint32 public constant WITHDRAW_MESSAGE = 2;\n uint32 public constant BALANCE_CHECK_MESSAGE = 3;\n\n uint32 public constant CCTP_MESSAGE_VERSION = 1;\n uint32 public constant ORIGIN_MESSAGE_VERSION = 1010;\n\n // CCTP Message Header fields\n // Ref: https://developers.circle.com/cctp/technical-guide#message-header\n uint8 private constant VERSION_INDEX = 0;\n uint8 private constant SOURCE_DOMAIN_INDEX = 4;\n uint8 private constant SENDER_INDEX = 44;\n uint8 private constant RECIPIENT_INDEX = 76;\n uint8 private constant MESSAGE_BODY_INDEX = 148;\n\n /**\n * @dev Get the message version from the message.\n * It should always be 4 bytes long,\n * starting from the 0th index.\n * @param message The message to get the version from\n * @return The message version\n */\n function getMessageVersion(bytes memory message)\n internal\n pure\n returns (uint32)\n {\n // uint32 bytes 0 to 4 is Origin message version\n // uint32 bytes 4 to 8 is Message type\n return message.extractUint32(0);\n }\n\n /**\n * @dev Get the message type from the message.\n * It should always be 4 bytes long,\n * starting from the 4th index.\n * @param message The message to get the type from\n * @return The message type\n */\n function getMessageType(bytes memory message)\n internal\n pure\n returns (uint32)\n {\n // uint32 bytes 0 to 4 is Origin message version\n // uint32 bytes 4 to 8 is Message type\n return message.extractUint32(4);\n }\n\n /**\n * @dev Verify the message version and type.\n * The message version should be the same as the Origin message version,\n * and the message type should be the same as the expected message type.\n * @param _message The message to verify\n * @param _type The expected message type\n */\n function verifyMessageVersionAndType(bytes memory _message, uint32 _type)\n internal\n pure\n {\n require(\n getMessageVersion(_message) == ORIGIN_MESSAGE_VERSION,\n \"Invalid Origin Message Version\"\n );\n require(getMessageType(_message) == _type, \"Invalid Message type\");\n }\n\n /**\n * @dev Get the message payload from the message.\n * The payload starts at the 8th byte.\n * @param message The message to get the payload from\n * @return The message payload\n */\n function getMessagePayload(bytes memory message)\n internal\n pure\n returns (bytes memory)\n {\n // uint32 bytes 0 to 4 is Origin message version\n // uint32 bytes 4 to 8 is Message type\n // Payload starts at byte 8\n return message.extractSlice(8, message.length);\n }\n\n /**\n * @dev Encode the deposit message.\n * The message version and type are always encoded in the message.\n * @param nonce The nonce of the deposit\n * @param depositAmount The amount of the deposit\n * @return The encoded deposit message\n */\n function encodeDepositMessage(uint64 nonce, uint256 depositAmount)\n internal\n pure\n returns (bytes memory)\n {\n return\n abi.encodePacked(\n ORIGIN_MESSAGE_VERSION,\n DEPOSIT_MESSAGE,\n abi.encode(nonce, depositAmount)\n );\n }\n\n /**\n * @dev Decode the deposit message.\n * The message version and type are verified in the message.\n * @param message The message to decode\n * @return The nonce and the amount of the deposit\n */\n function decodeDepositMessage(bytes memory message)\n internal\n pure\n returns (uint64, uint256)\n {\n verifyMessageVersionAndType(message, DEPOSIT_MESSAGE);\n\n (uint64 nonce, uint256 depositAmount) = abi.decode(\n getMessagePayload(message),\n (uint64, uint256)\n );\n return (nonce, depositAmount);\n }\n\n /**\n * @dev Encode the withdrawal message.\n * The message version and type are always encoded in the message.\n * @param nonce The nonce of the withdrawal\n * @param withdrawAmount The amount of the withdrawal\n * @return The encoded withdrawal message\n */\n function encodeWithdrawMessage(uint64 nonce, uint256 withdrawAmount)\n internal\n pure\n returns (bytes memory)\n {\n return\n abi.encodePacked(\n ORIGIN_MESSAGE_VERSION,\n WITHDRAW_MESSAGE,\n abi.encode(nonce, withdrawAmount)\n );\n }\n\n /**\n * @dev Decode the withdrawal message.\n * The message version and type are verified in the message.\n * @param message The message to decode\n * @return The nonce and the amount of the withdrawal\n */\n function decodeWithdrawMessage(bytes memory message)\n internal\n pure\n returns (uint64, uint256)\n {\n verifyMessageVersionAndType(message, WITHDRAW_MESSAGE);\n\n (uint64 nonce, uint256 withdrawAmount) = abi.decode(\n getMessagePayload(message),\n (uint64, uint256)\n );\n return (nonce, withdrawAmount);\n }\n\n /**\n * @dev Encode the balance check message.\n * The message version and type are always encoded in the message.\n * @param nonce The nonce of the balance check\n * @param balance The balance to check\n * @param transferConfirmation Indicates if the message is a transfer confirmation. This is true\n * when the message is a result of a deposit or a withdrawal.\n * @return The encoded balance check message\n */\n function encodeBalanceCheckMessage(\n uint64 nonce,\n uint256 balance,\n bool transferConfirmation,\n uint256 timestamp\n ) internal pure returns (bytes memory) {\n return\n abi.encodePacked(\n ORIGIN_MESSAGE_VERSION,\n BALANCE_CHECK_MESSAGE,\n abi.encode(nonce, balance, transferConfirmation, timestamp)\n );\n }\n\n /**\n * @dev Decode the balance check message.\n * The message version and type are verified in the message.\n * @param message The message to decode\n * @return The nonce, the balance and indicates if the message is a transfer confirmation\n */\n function decodeBalanceCheckMessage(bytes memory message)\n internal\n pure\n returns (\n uint64,\n uint256,\n bool,\n uint256\n )\n {\n verifyMessageVersionAndType(message, BALANCE_CHECK_MESSAGE);\n\n (\n uint64 nonce,\n uint256 balance,\n bool transferConfirmation,\n uint256 timestamp\n ) = abi.decode(\n getMessagePayload(message),\n (uint64, uint256, bool, uint256)\n );\n return (nonce, balance, transferConfirmation, timestamp);\n }\n\n /**\n * @dev Decode the CCTP message header\n * @param message Message to decode\n * @return version Version of the message\n * @return sourceDomainID Source domain ID\n * @return sender Sender of the message\n * @return recipient Recipient of the message\n * @return messageBody Message body\n */\n function decodeMessageHeader(bytes memory message)\n internal\n pure\n returns (\n uint32 version,\n uint32 sourceDomainID,\n address sender,\n address recipient,\n bytes memory messageBody\n )\n {\n version = message.extractUint32(VERSION_INDEX);\n sourceDomainID = message.extractUint32(SOURCE_DOMAIN_INDEX);\n // Address of MessageTransmitterV2 caller on source domain\n sender = message.extractAddress(SENDER_INDEX);\n // Address to handle message body on destination domain\n recipient = message.extractAddress(RECIPIENT_INDEX);\n messageBody = message.extractSlice(MESSAGE_BODY_INDEX, message.length);\n }\n}\n" + }, + "contracts/strategies/CurveAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Curve Automated Market Maker (AMO) Strategy\n * @notice AMO strategy for a Curve pool using an OToken.\n * @author Origin Protocol Inc\n */\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { ICurveStableSwapNG } from \"../interfaces/ICurveStableSwapNG.sol\";\nimport { ICurveLiquidityGaugeV6 } from \"../interfaces/ICurveLiquidityGaugeV6.sol\";\nimport { IBasicToken } from \"../interfaces/IBasicToken.sol\";\nimport { ICurveMinter } from \"../interfaces/ICurveMinter.sol\";\n\ncontract CurveAMOStrategy is InitializableAbstractStrategy {\n using SafeCast for uint256;\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n /**\n * @dev a threshold under which the contract no longer allows for the protocol to manually rebalance.\n * Guarding against a strategist / guardian being taken over and with multiple transactions\n * draining the protocol funds.\n */\n uint256 public constant SOLVENCY_THRESHOLD = 0.998 ether;\n\n // New immutable variables that must be set in the constructor\n /**\n * @notice Address of the hard asset (weth, usdt, usdc).\n */\n IERC20 public immutable hardAsset;\n\n /**\n * @notice Address of the OTOKEN token contract.\n */\n IERC20 public immutable oToken;\n\n /**\n * @notice Address of the LP (Liquidity Provider) token contract.\n */\n IERC20 public immutable lpToken;\n\n /**\n * @notice Address of the Curve StableSwap NG pool contract.\n */\n ICurveStableSwapNG public immutable curvePool;\n\n /**\n * @notice Address of the Curve X-Chain Liquidity Gauge contract.\n */\n ICurveLiquidityGaugeV6 public immutable gauge;\n\n /**\n * @notice Address of the Curve Minter contract.\n */\n ICurveMinter public immutable minter;\n\n /**\n * @notice Index of the OTOKEN and hardAsset in the Curve pool.\n */\n uint128 public immutable otokenCoinIndex;\n uint128 public immutable hardAssetCoinIndex;\n\n /**\n * @notice Decimals of the OTOKEN and hardAsset.\n */\n uint8 public immutable decimalsOToken;\n uint8 public immutable decimalsHardAsset;\n\n /**\n * @notice Maximum slippage allowed for adding/removing liquidity from the Curve pool.\n */\n uint256 public maxSlippage;\n\n event MaxSlippageUpdated(uint256 newMaxSlippage);\n\n /**\n * @dev Verifies that the caller is the Strategist.\n */\n modifier onlyStrategist() {\n require(\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n _;\n }\n\n /**\n * @dev Checks the Curve pool's balances have improved and the balances\n * have not tipped to the other side.\n * This modifier is only applied to functions that do a single sided add or remove.\n * The standard deposit function adds to both sides of the pool in a way that\n * the pool's balance is not worsened.\n * Withdrawals are proportional so doesn't change the pools asset balance.\n */\n modifier improvePoolBalance() {\n // Get the hard asset and OToken balances in the Curve pool\n uint256[] memory balancesBefore = curvePool.get_balances();\n // diff = hardAsset balance - OTOKEN balance\n int256 diffBefore = (\n balancesBefore[hardAssetCoinIndex].scaleBy(\n decimalsOToken,\n decimalsHardAsset\n )\n ).toInt256() - balancesBefore[otokenCoinIndex].toInt256();\n\n _;\n\n // Get the hard asset and OToken balances in the Curve pool\n uint256[] memory balancesAfter = curvePool.get_balances();\n // diff = hardAsset balance - OTOKEN balance\n int256 diffAfter = (\n balancesAfter[hardAssetCoinIndex].scaleBy(\n decimalsOToken,\n decimalsHardAsset\n )\n ).toInt256() - balancesAfter[otokenCoinIndex].toInt256();\n\n if (diffBefore == 0) {\n require(diffAfter == 0, \"Position balance is worsened\");\n } else if (diffBefore < 0) {\n // If the pool was originally imbalanced in favor of OTOKEN, then\n // we want to check that the pool is now more balanced\n require(diffAfter <= 0, \"OTokens overshot peg\");\n require(diffBefore < diffAfter, \"OTokens balance worse\");\n } else if (diffBefore > 0) {\n // If the pool was originally imbalanced in favor of hardAsset, then\n // we want to check that the pool is now more balanced\n require(diffAfter >= 0, \"Assets overshot peg\");\n require(diffAfter < diffBefore, \"Assets balance worse\");\n }\n }\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _otoken,\n address _hardAsset,\n address _gauge,\n address _minter\n ) InitializableAbstractStrategy(_baseConfig) {\n lpToken = IERC20(_baseConfig.platformAddress);\n curvePool = ICurveStableSwapNG(_baseConfig.platformAddress);\n minter = ICurveMinter(_minter);\n\n oToken = IERC20(_otoken);\n hardAsset = IERC20(_hardAsset);\n gauge = ICurveLiquidityGaugeV6(_gauge);\n decimalsHardAsset = IBasicToken(_hardAsset).decimals();\n decimalsOToken = IBasicToken(_otoken).decimals();\n\n (hardAssetCoinIndex, otokenCoinIndex) = curvePool.coins(0) == _hardAsset\n ? (0, 1)\n : (1, 0);\n require(\n curvePool.coins(otokenCoinIndex) == _otoken &&\n curvePool.coins(hardAssetCoinIndex) == _hardAsset,\n \"Invalid coin indexes\"\n );\n require(gauge.lp_token() == address(curvePool), \"Invalid pool\");\n }\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Curve strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Address of CRV\n * @param _maxSlippage Maximum slippage allowed for adding/removing liquidity from the Curve pool.\n */\n function initialize(\n address[] calldata _rewardTokenAddresses, // CRV\n uint256 _maxSlippage\n ) external onlyGovernor initializer {\n address[] memory pTokens = new address[](1);\n pTokens[0] = address(curvePool);\n\n address[] memory _assets = new address[](1);\n _assets[0] = address(hardAsset);\n\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n pTokens\n );\n\n _approveBase();\n _setMaxSlippage(_maxSlippage);\n }\n\n /***************************************\n Deposit\n ****************************************/\n\n /**\n * @notice Deposit hard asset into the Curve pool\n * @param _hardAsset Address of hard asset contract.\n * @param _amount Amount of hard asset to deposit.\n */\n function deposit(address _hardAsset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_hardAsset, _amount);\n }\n\n function _deposit(address _hardAsset, uint256 _hardAssetAmount) internal {\n require(_hardAssetAmount > 0, \"Must deposit something\");\n require(_hardAsset == address(hardAsset), \"Unsupported asset\");\n\n emit Deposit(_hardAsset, address(lpToken), _hardAssetAmount);\n uint256 scaledHardAssetAmount = _hardAssetAmount.scaleBy(\n decimalsOToken,\n decimalsHardAsset\n );\n\n // Get the asset and OToken balances in the Curve pool\n uint256[] memory balances = curvePool.get_balances();\n // safe to cast since min value is at least 0\n uint256 otokenToAdd = uint256(\n _max(\n 0,\n (\n balances[hardAssetCoinIndex].scaleBy(\n decimalsOToken,\n decimalsHardAsset\n )\n ).toInt256() +\n scaledHardAssetAmount.toInt256() -\n balances[otokenCoinIndex].toInt256()\n )\n );\n\n /* Add so much OTOKEN so that the pool ends up being balanced. And at minimum\n * add as much OTOKEN as hard asset and at maximum twice as much OTOKEN.\n */\n otokenToAdd = Math.max(otokenToAdd, scaledHardAssetAmount);\n otokenToAdd = Math.min(otokenToAdd, scaledHardAssetAmount * 2);\n\n /* Mint OTOKEN with a strategy that attempts to contribute to stability of OTOKEN/hardAsset pool. Try\n * to mint so much OTOKEN that after deployment of liquidity pool ends up being balanced.\n *\n * To manage unpredictability minimal OTOKEN minted will always be at least equal or greater\n * to hardAsset amount deployed. And never larger than twice the hardAsset amount deployed even if\n * it would have a further beneficial effect on pool stability.\n */\n IVault(vaultAddress).mintForStrategy(otokenToAdd);\n\n emit Deposit(address(oToken), address(lpToken), otokenToAdd);\n\n uint256[] memory _amounts = new uint256[](2);\n _amounts[hardAssetCoinIndex] = _hardAssetAmount;\n _amounts[otokenCoinIndex] = otokenToAdd;\n\n uint256 valueInLpTokens = (scaledHardAssetAmount + otokenToAdd)\n .divPrecisely(curvePool.get_virtual_price());\n uint256 minMintAmount = valueInLpTokens.mulTruncate(\n uint256(1e18) - maxSlippage\n );\n\n // Do the deposit to the Curve pool\n uint256 lpDeposited = curvePool.add_liquidity(_amounts, minMintAmount);\n require(lpDeposited >= minMintAmount, \"Min LP amount error\");\n\n // Deposit the Curve pool's LP tokens into the Curve gauge\n gauge.deposit(lpDeposited);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n }\n\n /**\n * @notice Deposit the strategy's entire balance of hardAsset into the Curve pool\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 balance = hardAsset.balanceOf(address(this));\n if (balance > 0) {\n _deposit(address(hardAsset), balance);\n }\n }\n\n /***************************************\n Withdraw\n ****************************************/\n\n /**\n * @notice Withdraw hardAsset and OTOKEN from the Curve pool, burn the OTOKEN,\n * transfer hardAsset to the recipient.\n * @param _recipient Address to receive withdrawn asset which is normally the Vault.\n * @param _hardAsset Address of the hardAsset contract.\n * @param _amount Amount of hardAsset to withdraw.\n */\n function withdraw(\n address _recipient,\n address _hardAsset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(\n _hardAsset == address(hardAsset),\n \"Can only withdraw hard asset\"\n );\n\n emit Withdrawal(_hardAsset, address(lpToken), _amount);\n\n uint256 requiredLpTokens = calcTokenToBurn(\n _amount.scaleBy(decimalsOToken, decimalsHardAsset)\n );\n\n _lpWithdraw(requiredLpTokens);\n\n /* math in requiredLpTokens should correctly calculate the amount of LP to remove\n * in that the strategy receives enough hardAsset on balanced removal\n */\n uint256[] memory _minWithdrawalAmounts = new uint256[](2);\n _minWithdrawalAmounts[hardAssetCoinIndex] = _amount;\n // slither-disable-next-line unused-return\n curvePool.remove_liquidity(requiredLpTokens, _minWithdrawalAmounts);\n\n // Burn all the removed OTOKEN and any that was left in the strategy\n uint256 otokenToBurn = oToken.balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(otokenToBurn);\n\n emit Withdrawal(address(oToken), address(lpToken), otokenToBurn);\n\n // Transfer hardAsset to the recipient\n hardAsset.safeTransfer(_recipient, _amount);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n }\n\n function calcTokenToBurn(uint256 _hardAssetAmount)\n internal\n view\n returns (uint256 lpToBurn)\n {\n /* The rate between coins in the pool determines the rate at which pool returns\n * tokens when doing balanced removal (remove_liquidity call). And by knowing how much hardAsset\n * we want we can determine how much of OTOKEN we receive by removing liquidity.\n *\n * Because we are doing balanced removal we should be making profit when removing liquidity in a\n * pool tilted to either side.\n *\n * Important: A downside is that the Strategist / Governor needs to be\n * cognisant of not removing too much liquidity. And while the proposal to remove liquidity\n * is being voted on the pool tilt might change so much that the proposal that has been valid while\n * created is no longer valid.\n */\n\n uint256 poolHardAssetBalance = curvePool\n .balances(hardAssetCoinIndex)\n .scaleBy(decimalsOToken, decimalsHardAsset);\n /* K is multiplied by 1e36 which is used for higher precision calculation of required\n * pool LP tokens. Without it the end value can have rounding errors up to precision of\n * 10 digits. This way we move the decimal point by 36 places when doing the calculation\n * and again by 36 places when we are done with it.\n */\n uint256 k = (1e36 * lpToken.totalSupply()) / poolHardAssetBalance;\n // prettier-ignore\n // slither-disable-next-line divide-before-multiply\n uint256 diff = (_hardAssetAmount + 1) * k;\n lpToBurn = diff / 1e36;\n }\n\n /**\n * @notice Remove all hardAsset and OTOKEN from the Curve pool, burn the OTOKEN,\n * transfer hardAsset to the Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 gaugeTokens = gauge.balanceOf(address(this));\n _lpWithdraw(gaugeTokens);\n\n // Withdraws are proportional to assets held by 3Pool\n uint256[] memory minWithdrawAmounts = new uint256[](2);\n\n // Check balance of LP tokens in the strategy, if 0 return\n uint256 lpBalance = lpToken.balanceOf(address(this));\n\n // Remove liquidity\n // slither-disable-next-line unused-return\n if (lpBalance > 0) {\n curvePool.remove_liquidity(lpBalance, minWithdrawAmounts);\n }\n\n // Burn all OTOKEN\n uint256 otokenToBurn = oToken.balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(otokenToBurn);\n\n // Get the strategy contract's hardAsset balance.\n // This includes all that was removed from the Curve pool and\n // any hardAsset that was sitting in the strategy contract before the removal.\n uint256 hardAssetBalance = hardAsset.balanceOf(address(this));\n hardAsset.safeTransfer(vaultAddress, hardAssetBalance);\n\n if (hardAssetBalance > 0)\n emit Withdrawal(\n address(hardAsset),\n address(lpToken),\n hardAssetBalance\n );\n if (otokenToBurn > 0)\n emit Withdrawal(address(oToken), address(lpToken), otokenToBurn);\n }\n\n /***************************************\n Curve pool Rebalancing\n ****************************************/\n\n /**\n * @notice Mint OTokens and one-sided add to the Curve pool.\n * This is used when the Curve pool does not have enough OTokens and too many hardAsset.\n * The OToken/Asset, eg OTOKEN/hardAsset, price with increase.\n * The amount of assets in the vault is unchanged.\n * The total supply of OTokens is increased.\n * The asset value of the strategy and vault is increased.\n * @param _oTokens The amount of OTokens to be minted and added to the pool.\n */\n function mintAndAddOTokens(uint256 _oTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n IVault(vaultAddress).mintForStrategy(_oTokens);\n\n uint256[] memory amounts = new uint256[](2);\n amounts[otokenCoinIndex] = _oTokens;\n\n // Convert OTOKEN to Curve pool LP tokens\n uint256 valueInLpTokens = (_oTokens).divPrecisely(\n curvePool.get_virtual_price()\n );\n // Apply slippage to LP tokens\n uint256 minMintAmount = valueInLpTokens.mulTruncate(\n uint256(1e18) - maxSlippage\n );\n\n // Add the minted OTokens to the Curve pool\n uint256 lpDeposited = curvePool.add_liquidity(amounts, minMintAmount);\n require(lpDeposited >= minMintAmount, \"Min LP amount error\");\n\n // Deposit the Curve pool LP tokens to the Curve gauge\n gauge.deposit(lpDeposited);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Deposit(address(oToken), address(lpToken), _oTokens);\n }\n\n /**\n * @notice One-sided remove of OTokens from the Curve pool which are then burned.\n * This is used when the Curve pool has too many OTokens and not enough hardAsset.\n * The amount of assets in the vault is unchanged.\n * The total supply of OTokens is reduced.\n * The asset value of the strategy and vault is reduced.\n * @param _lpTokens The amount of Curve pool LP tokens to be burned for OTokens.\n */\n function removeAndBurnOTokens(uint256 _lpTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n // Withdraw Curve pool LP tokens from gauge and remove OTokens from the Curve pool\n uint256 otokenToBurn = _withdrawAndRemoveFromPool(\n _lpTokens,\n otokenCoinIndex\n );\n\n // The vault burns the OTokens from this strategy\n IVault(vaultAddress).burnForStrategy(otokenToBurn);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Withdrawal(address(oToken), address(lpToken), otokenToBurn);\n }\n\n /**\n * @notice One-sided remove of hardAsset from the Curve pool and transfer to the vault.\n * This is used when the Curve pool does not have enough OTokens and too many hardAsset.\n * The OToken/Asset, eg OTOKEN/hardAsset, price with decrease.\n * The amount of assets in the vault increases.\n * The total supply of OTokens does not change.\n * The asset value of the strategy reduces.\n * The asset value of the vault should be close to the same.\n * @param _lpTokens The amount of Curve pool LP tokens to be burned for hardAsset.\n * @dev Curve pool LP tokens is used rather than hardAsset assets as Curve does not\n * have a way to accurately calculate the amount of LP tokens for a required\n * amount of hardAsset. Curve's `calc_token_amount` function does not include fees.\n * A 3rd party library can be used that takes into account the fees, but this\n * is a gas intensive process. It's easier for the trusted strategist to\n * calculate the amount of Curve pool LP tokens required off-chain.\n */\n function removeOnlyAssets(uint256 _lpTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n // Withdraw Curve pool LP tokens from Curve gauge and remove hardAsset from the Curve pool\n uint256 hardAssetAmount = _withdrawAndRemoveFromPool(\n _lpTokens,\n hardAssetCoinIndex\n );\n\n // Transfer hardAsset to the vault\n hardAsset.safeTransfer(vaultAddress, hardAssetAmount);\n\n // Ensure solvency of the vault\n _solvencyAssert();\n\n emit Withdrawal(address(hardAsset), address(lpToken), hardAssetAmount);\n }\n\n /**\n * @dev Remove Curve pool LP tokens from the gauge and\n * do a one-sided remove of hardAsset or OTOKEN from the Curve pool.\n * @param _lpTokens The amount of Curve pool LP tokens to be removed from the gauge\n * @param coinIndex The index of the coin to be removed from the Curve pool. 0 = hardAsset, 1 = OTOKEN.\n * @return coinsRemoved The amount of hardAsset or OTOKEN removed from the Curve pool.\n */\n function _withdrawAndRemoveFromPool(uint256 _lpTokens, uint128 coinIndex)\n internal\n returns (uint256 coinsRemoved)\n {\n // Withdraw Curve pool LP tokens from Curve gauge\n _lpWithdraw(_lpTokens);\n\n // Convert Curve pool LP tokens to hardAsset value\n uint256 valueInEth = _lpTokens.mulTruncate(\n curvePool.get_virtual_price()\n );\n\n if (coinIndex == hardAssetCoinIndex) {\n valueInEth = valueInEth.scaleBy(decimalsHardAsset, decimalsOToken);\n }\n\n // Apply slippage to hardAsset value\n uint256 minAmount = valueInEth.mulTruncate(uint256(1e18) - maxSlippage);\n\n // Remove just the hardAsset from the Curve pool\n coinsRemoved = curvePool.remove_liquidity_one_coin(\n _lpTokens,\n int128(coinIndex),\n minAmount,\n address(this)\n );\n }\n\n /**\n * Checks that the protocol is solvent, protecting from a rogue Strategist / Guardian that can\n * keep rebalancing the pool in both directions making the protocol lose a tiny amount of\n * funds each time.\n *\n * Protocol must be at least SOLVENCY_THRESHOLD (99,8 %) backed in order for the rebalances to\n * function.\n */\n function _solvencyAssert() internal view {\n uint256 _totalVaultValue = IVault(vaultAddress).totalValue();\n uint256 _totalOtokenSupply = oToken.totalSupply();\n\n if (\n _totalVaultValue.divPrecisely(_totalOtokenSupply) <\n SOLVENCY_THRESHOLD\n ) {\n revert(\"Protocol insolvent\");\n }\n }\n\n /***************************************\n Assets and Rewards\n ****************************************/\n\n /**\n * @notice Collect accumulated CRV (and other) rewards and send to the Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvesterOrStrategist\n nonReentrant\n {\n // Collect CRV rewards from inflation\n minter.mint(address(gauge));\n\n // Collect extra gauge rewards (outside of CRV)\n gauge.claim_rewards();\n\n _collectRewardTokens();\n }\n\n function _lpWithdraw(uint256 _lpAmount) internal {\n require(\n gauge.balanceOf(address(this)) >= _lpAmount,\n \"Insufficient LP tokens\"\n );\n // withdraw lp tokens from the gauge without claiming rewards\n gauge.withdraw(_lpAmount);\n }\n\n /**\n * @notice Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == address(hardAsset), \"Unsupported asset\");\n\n // hardAsset balance needed here for the balance check that happens from vault during depositing.\n balance = hardAsset.balanceOf(address(this));\n uint256 lpTokens = gauge.balanceOf(address(this));\n if (lpTokens > 0) {\n balance += ((lpTokens * curvePool.get_virtual_price()) / 1e18)\n .scaleBy(decimalsHardAsset, decimalsOToken);\n }\n }\n\n /**\n * @notice Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == address(hardAsset);\n }\n\n /***************************************\n Approvals\n ****************************************/\n\n /**\n * @notice Sets the maximum slippage allowed for any swap/liquidity operation\n * @param _maxSlippage Maximum slippage allowed, 1e18 = 100%.\n */\n function setMaxSlippage(uint256 _maxSlippage) external onlyGovernor {\n _setMaxSlippage(_maxSlippage);\n }\n\n function _setMaxSlippage(uint256 _maxSlippage) internal {\n require(_maxSlippage <= 5e16, \"Slippage must be less than 100%\");\n maxSlippage = _maxSlippage;\n emit MaxSlippageUpdated(_maxSlippage);\n }\n\n /**\n * @notice Approve the spending of all assets by their corresponding pool tokens,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n _approveBase();\n }\n\n /**\n * @dev Since we are unwrapping WETH before depositing it to Curve\n * there is no need to set an approval for WETH on the Curve\n * pool\n * @param _asset Address of the asset\n * @param _pToken Address of the Curve LP token\n */\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {}\n\n function _approveBase() internal {\n // Approve Curve pool for OTOKEN (required for adding liquidity)\n // slither-disable-next-line unused-return\n oToken.approve(platformAddress, type(uint256).max);\n\n // Approve Curve pool for hardAsset (required for adding liquidity)\n // slither-disable-next-line unused-return\n hardAsset.safeApprove(platformAddress, type(uint256).max);\n\n // Approve Curve gauge contract to transfer Curve pool LP tokens\n // This is needed for deposits if Curve pool LP tokens into the Curve gauge.\n // slither-disable-next-line unused-return\n lpToken.approve(address(gauge), type(uint256).max);\n }\n\n /**\n * @dev Returns the largest of two numbers int256 version\n */\n function _max(int256 a, int256 b) internal pure returns (int256) {\n return a >= b ? a : b;\n }\n}\n" + }, + "contracts/strategies/Generalized4626Strategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Generalized 4626 Strategy\n * @notice Investment strategy for ERC-4626 Tokenized Vaults\n * @dev This strategy should not be used for the Morpho V2 Vaults as those are not\n * completley ERC-4626 compliant - they don't implement the maxWithdraw() and\n * maxRedeem() functions and rather return 0 when any of them is called.\n * @author Origin Protocol Inc\n */\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { IDistributor } from \"../interfaces/IMerkl.sol\";\n\ncontract Generalized4626Strategy is InitializableAbstractStrategy {\n /// @notice The address of the Merkle Distributor contract.\n IDistributor public constant merkleDistributor =\n IDistributor(0x3Ef3D8bA38EBe18DB133cEc108f4D14CE00Dd9Ae);\n\n /// @dev Replaced with an immutable variable\n // slither-disable-next-line constable-states\n address private _deprecate_shareToken;\n /// @dev Replaced with an immutable variable\n // slither-disable-next-line constable-states\n address private _deprecate_assetToken;\n\n IERC20 public immutable shareToken;\n IERC20 public immutable assetToken;\n\n // For future use\n uint256[50] private __gap;\n\n event ClaimedRewards(address indexed token, uint256 amount);\n\n /**\n * @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI,\n * and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\n * @param _assetToken Address of the ERC-4626 asset token. eg frxETH or DAI\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _assetToken)\n InitializableAbstractStrategy(_baseConfig)\n {\n shareToken = IERC20(_baseConfig.platformAddress);\n assetToken = IERC20(_assetToken);\n }\n\n function initialize() external virtual onlyGovernor initializer {\n address[] memory rewardTokens = new address[](0);\n address[] memory assets = new address[](1);\n address[] memory pTokens = new address[](1);\n\n assets[0] = address(assetToken);\n pTokens[0] = address(platformAddress);\n\n InitializableAbstractStrategy._initialize(\n rewardTokens,\n assets,\n pTokens\n );\n }\n\n /**\n * @dev Deposit assets by converting them to shares\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n virtual\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /**\n * @dev Deposit assets by converting them to shares\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal virtual {\n require(_amount > 0, \"Must deposit something\");\n require(_asset == address(assetToken), \"Unexpected asset address\");\n\n // slither-disable-next-line unused-return\n IERC4626(platformAddress).deposit(_amount, address(this));\n emit Deposit(_asset, address(shareToken), _amount);\n }\n\n /**\n * @dev Deposit the entire balance of assetToken to gain shareToken\n */\n function depositAll() external virtual override onlyVault nonReentrant {\n uint256 balance = assetToken.balanceOf(address(this));\n if (balance > 0) {\n _deposit(address(assetToken), balance);\n }\n }\n\n /**\n * @dev Withdraw asset by burning shares\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external virtual override onlyVault nonReentrant {\n _withdraw(_recipient, _asset, _amount);\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal virtual {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n require(_asset == address(assetToken), \"Unexpected asset address\");\n\n // slither-disable-next-line unused-return\n IERC4626(platformAddress).withdraw(_amount, _recipient, address(this));\n emit Withdrawal(_asset, address(shareToken), _amount);\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset / share tokens\n */\n function _abstractSetPToken(address, address) internal virtual override {\n _approveBase();\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll()\n external\n virtual\n override\n onlyVaultOrGovernor\n nonReentrant\n {\n // @dev Don't use for Morpho V2 Vaults as below line will return 0\n uint256 sharesToRedeem = IERC4626(platformAddress).maxRedeem(\n address(this)\n );\n\n uint256 assetAmount = 0;\n if (sharesToRedeem > 0) {\n assetAmount = IERC4626(platformAddress).redeem(\n sharesToRedeem,\n vaultAddress,\n address(this)\n );\n emit Withdrawal(\n address(assetToken),\n address(shareToken),\n assetAmount\n );\n }\n }\n\n /**\n * @notice Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n public\n view\n virtual\n override\n returns (uint256 balance)\n {\n require(_asset == address(assetToken), \"Unexpected asset address\");\n /* We are intentionally not counting the amount of assetToken parked on the\n * contract toward the checkBalance. The deposit and withdraw functions\n * should not result in assetToken being unused and owned by this strategy\n * contract.\n */\n IERC4626 platform = IERC4626(platformAddress);\n return platform.previewRedeem(platform.balanceOf(address(this)));\n }\n\n /**\n * @notice Governor approves the ERC-4626 Tokenized Vault to spend the asset.\n */\n function safeApproveAllTokens() external override onlyGovernor {\n _approveBase();\n }\n\n function _approveBase() internal virtual {\n // Approval the asset to be transferred to the ERC-4626 Tokenized Vault.\n // Used by the ERC-4626 deposit() and mint() functions\n // slither-disable-next-line unused-return\n assetToken.approve(platformAddress, type(uint256).max);\n }\n\n /**\n * @dev Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset)\n public\n view\n virtual\n override\n returns (bool)\n {\n return _asset == address(assetToken);\n }\n\n /**\n * @notice is not supported for this strategy as the asset and\n * ERC-4626 Tokenized Vault are set at deploy time.\n * @dev If the ERC-4626 Tokenized Vault needed to be changed, a new\n * contract would need to be deployed and the proxy updated.\n */\n function setPTokenAddress(address, address) external override onlyGovernor {\n revert(\"unsupported function\");\n }\n\n /**\n * @notice is not supported for this strategy as the asset and\n * ERC-4626 Tokenized Vault are set at deploy time.\n * @dev If the ERC-4626 Tokenized Vault needed to be changed, a new\n * contract would need to be deployed and the proxy updated.\n */\n function removePToken(uint256) external override onlyGovernor {\n revert(\"unsupported function\");\n }\n\n /// @notice Claim tokens from the Merkle Distributor\n /// @param token The address of the token to claim.\n /// @param amount The amount of tokens to claim.\n /// @param proof The Merkle proof to validate the claim.\n function merkleClaim(\n address token,\n uint256 amount,\n bytes32[] calldata proof\n ) external {\n address[] memory users = new address[](1);\n users[0] = address(this);\n\n address[] memory tokens = new address[](1);\n tokens[0] = token;\n\n uint256[] memory amounts = new uint256[](1);\n amounts[0] = amount;\n\n bytes32[][] memory proofs = new bytes32[][](1);\n proofs[0] = proof;\n\n merkleDistributor.claim(users, tokens, amounts, proofs);\n\n emit ClaimedRewards(token, amount);\n }\n}\n" + }, + "contracts/strategies/hydrex/OETHbHydrexAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OETHb Hydrex Algorithmic Market Maker (AMO) Strategy\n * @notice AMO strategy for the Hydrex superOETHb/WETH stable pool on Base\n * @author Origin Protocol Inc\n */\nimport { StableSwapAMMStrategy } from \"../algebra/StableSwapAMMStrategy.sol\";\nimport { IHydrexGauge } from \"../../interfaces/hydrex/IHydrexGauge.sol\";\n\ncontract OETHbHydrexAMOStrategy is StableSwapAMMStrategy {\n /**\n * @param _baseConfig The `platformAddress` is the address of the Hydrex superOETHb/WETH pool.\n * The `vaultAddress` is the address of the OETHBase Vault.\n * @param _gauge Address of the Hydrex gauge for the pool. Hydrex GaugeV2\n * (>= v2.5) renamed `TOKEN()` to `stakeToken()`, which is what we\n * resolve here and forward to the parent.\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _gauge)\n StableSwapAMMStrategy(\n _baseConfig,\n _gauge,\n IHydrexGauge(_gauge).stakeToken()\n )\n {}\n}\n" + }, + "contracts/strategies/ICurvePool.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface ICurvePool {\n function get_virtual_price() external view returns (uint256);\n\n function add_liquidity(uint256[3] calldata _amounts, uint256 _min) external;\n\n function balances(uint256) external view returns (uint256);\n\n function calc_token_amount(uint256[3] calldata _amounts, bool _deposit)\n external\n returns (uint256);\n\n function fee() external view returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _amount,\n int128 _index,\n uint256 _minAmount\n ) external;\n\n function remove_liquidity(\n uint256 _amount,\n uint256[3] calldata _minWithdrawAmounts\n ) external;\n\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n external\n view\n returns (uint256);\n\n function exchange(\n uint256 i,\n uint256 j,\n uint256 dx,\n uint256 min_dy\n ) external returns (uint256);\n\n function coins(uint256 _index) external view returns (address);\n\n function remove_liquidity_imbalance(\n uint256[3] calldata _amounts,\n uint256 maxBurnAmount\n ) external;\n}\n" + }, + "contracts/strategies/MorphoV2Strategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Generalized 4626 Strategy when the underlying platform is Morpho V2\n * @notice Investment strategy for ERC-4626 Tokenized Vaults for the Morpho V2 platform.\n * @author Origin Protocol Inc\n */\nimport { Generalized4626Strategy } from \"./Generalized4626Strategy.sol\";\nimport { MorphoV2VaultUtils } from \"./MorphoV2VaultUtils.sol\";\nimport { IVaultV2 } from \"../interfaces/morpho/IVaultV2.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\ncontract MorphoV2Strategy is Generalized4626Strategy {\n /**\n * @param _baseConfig Base strategy config with Morpho V2 Vault and\n * vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\n * @param _assetToken Address of the ERC-4626 asset token. e.g. USDC\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _assetToken)\n Generalized4626Strategy(_baseConfig, _assetToken)\n {}\n\n /**\n * @notice Remove all the liquidity that is available in the Morpho V2 vault.\n * Which might not be all of the liquidity owned by the strategy.\n * @dev Remove all the liquidity that is available in the Morpho V2 vault\n * The particular behaviour of the Morpho V2 vault is that it can hold\n * multiple Morpho V1 vaults as adapters but only one liquidity adapter.\n * The immediate available funds on the Morpho V2 vault are therfore any\n * liquid assets residing on the Vault V2 contract and the maxWithdraw\n * amount that the Morpho V1 contract can supply.\n */\n function withdrawAll()\n external\n virtual\n override\n onlyVaultOrGovernor\n nonReentrant\n {\n uint256 availableMorphoVault = _maxWithdraw();\n uint256 balanceToWithdraw = Math.min(\n availableMorphoVault,\n checkBalance(address(assetToken))\n );\n\n if (balanceToWithdraw > 0) {\n // slither-disable-next-line unused-return\n IVaultV2(platformAddress).withdraw(\n balanceToWithdraw,\n vaultAddress,\n address(this)\n );\n }\n\n emit Withdrawal(\n address(assetToken),\n address(shareToken),\n balanceToWithdraw\n );\n }\n\n function maxWithdraw() external view returns (uint256) {\n return _maxWithdraw();\n }\n\n function _maxWithdraw()\n internal\n view\n returns (uint256 availableAssetLiquidity)\n {\n availableAssetLiquidity = MorphoV2VaultUtils.maxWithdrawableAssets(\n platformAddress,\n address(assetToken)\n );\n }\n}\n" + }, + "contracts/strategies/MorphoV2VaultUtils.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IVaultV2 } from \"../interfaces/morpho/IVaultV2.sol\";\nimport { IMorphoV2Adapter } from \"../interfaces/morpho/IMorphoV2Adapter.sol\";\n\nlibrary MorphoV2VaultUtils {\n error IncompatibleAdapter(address adapter);\n\n /**\n * @notice Return maximum amount that can be safely withdrawn from a Morpho V2 vault.\n * @dev Available liquidity is:\n * 1) asset balance parked on Morpho V2 vault contract\n * 2) additional liquidity from the active adapter if it resolves to a Morpho V1 vault\n * and, when provided, matches the expected adapter\n */\n function maxWithdrawableAssets(address platformAddress, address assetToken)\n internal\n view\n returns (uint256 availableAssetLiquidity)\n {\n availableAssetLiquidity = IERC20(assetToken).balanceOf(platformAddress);\n\n address liquidityAdapter = IVaultV2(platformAddress).liquidityAdapter();\n // this is a sufficient check to ensure the adapter is Morpho V1\n try IMorphoV2Adapter(liquidityAdapter).morphoVaultV1() returns (\n address underlyingVault\n ) {\n availableAssetLiquidity += IERC4626(underlyingVault).maxWithdraw(\n liquidityAdapter\n );\n } catch {\n revert IncompatibleAdapter(liquidityAdapter);\n }\n }\n}\n" + }, + "contracts/strategies/NativeStaking/CompoundingStakingSSVStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { CompoundingValidatorManager } from \"./CompoundingValidatorManager.sol\";\n\n/// @title Compounding Staking SSV Strategy\n/// @notice Strategy to deploy funds into DVT validators powered by the SSV Network\n/// @author Origin Protocol Inc\ncontract CompoundingStakingSSVStrategy is\n CompoundingValidatorManager,\n InitializableAbstractStrategy\n{\n // For future use\n uint256[50] private __gap;\n\n /// @param _baseConfig Base strategy config with\n /// `platformAddress` not used so empty address\n /// `vaultAddress` the address of the OETH Vault contract\n /// @param _wethAddress Address of the WETH Token contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _beaconProofs Address of the Beacon Proofs contract that verifies beacon chain data\n /// @param _beaconGenesisTimestamp The timestamp of the Beacon chain's genesis.\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _wethAddress,\n address _ssvNetwork,\n address _beaconChainDepositContract,\n address _beaconProofs,\n uint64 _beaconGenesisTimestamp\n )\n InitializableAbstractStrategy(_baseConfig)\n CompoundingValidatorManager(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork,\n _beaconProofs,\n _beaconGenesisTimestamp\n )\n {\n // Make sure nobody owns the implementation contract\n _setGovernor(address(0));\n }\n\n /// @notice Set up initial internal state including\n /// 1. approving the SSVNetwork to transfer SSV tokens from this strategy contract\n /// @param _rewardTokenAddresses Not used so empty array\n /// @param _assets Not used so empty array\n /// @param _pTokens Not used so empty array\n function initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n }\n\n /// @notice Unlike other strategies, this does not deposit assets into the underlying platform.\n /// It just checks the asset is WETH and emits the Deposit event.\n /// To deposit WETH into validators, `registerSsvValidator` and `stakeEth` must be used.\n /// @param _asset Address of the WETH token.\n /// @param _amount Amount of WETH that was transferred to the strategy by the vault.\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n require(_asset == WETH, \"Unsupported asset\");\n require(_amount > 0, \"Must deposit something\");\n\n // Account for the new WETH\n depositedWethAccountedFor += _amount;\n\n emit Deposit(_asset, address(0), _amount);\n }\n\n /// @notice Unlike other strategies, this does not deposit assets into the underlying platform.\n /// It just emits the Deposit event.\n /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used.\n function depositAll() external override onlyVault nonReentrant {\n uint256 wethBalance = IERC20(WETH).balanceOf(address(this));\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\n\n if (newWeth > 0) {\n // Account for the new WETH\n depositedWethAccountedFor = wethBalance;\n\n emit Deposit(WETH, address(0), newWeth);\n }\n }\n\n /// @notice Withdraw ETH and WETH from this strategy contract.\n /// @param _recipient Address to receive withdrawn assets.\n /// @param _asset Address of the WETH token.\n /// @param _amount Amount of WETH to withdraw.\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override nonReentrant {\n require(_asset == WETH, \"Unsupported asset\");\n require(\n msg.sender == vaultAddress || msg.sender == validatorRegistrator,\n \"Caller not Vault or Registrator\"\n );\n\n _withdraw(_recipient, _amount, address(this).balance);\n }\n\n function _withdraw(\n address _recipient,\n uint256 _withdrawAmount,\n uint256 _ethBalance\n ) internal {\n require(_withdrawAmount > 0, \"Must withdraw something\");\n require(_recipient == vaultAddress, \"Recipient not Vault\");\n\n // Convert any ETH from validator partial withdrawals, exits\n // or execution rewards to WETH and do the necessary accounting.\n if (_ethBalance > 0) _convertEthToWeth(_ethBalance);\n\n // Transfer WETH to the recipient and do the necessary accounting.\n _transferWeth(_withdrawAmount, _recipient);\n\n emit Withdrawal(WETH, address(0), _withdrawAmount);\n }\n\n /// @notice Transfer all WETH deposits, ETH from validator withdrawals and ETH from\n /// execution rewards in this strategy to the vault.\n /// This does not withdraw from the validators. That has to be done separately with the\n /// `validatorWithdrawal` operation.\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 ethBalance = address(this).balance;\n uint256 withdrawAmount = IERC20(WETH).balanceOf(address(this)) +\n ethBalance;\n\n if (withdrawAmount > 0) {\n _withdraw(vaultAddress, withdrawAmount, ethBalance);\n }\n }\n\n /// @notice Accounts for all the assets managed by this strategy which includes:\n /// 1. The current WETH in this strategy contract\n /// 2. The last verified ETH balance, total deposits and total validator balances\n /// @param _asset Address of WETH asset.\n /// @return balance Total value in ETH\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == WETH, \"Unsupported asset\");\n\n // Load the last verified balance from the storage\n // and add to the latest WETH balance of this strategy.\n balance =\n lastVerifiedEthBalance +\n IWETH9(WETH).balanceOf(address(this));\n }\n\n /// @notice Returns bool indicating whether asset is supported by the strategy.\n /// @param _asset The address of the WETH token.\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == WETH;\n }\n\n /// @notice Does nothing but needed as this function is abstract on InitializableAbstractStrategy\n /// @dev Use to be used to approve SSV tokens but that is no longer used by the SSV Network.\n function safeApproveAllTokens() public override {}\n\n /**\n * @notice We can accept ETH directly to this contract from anyone as it does not impact our accounting\n * like it did in the legacy NativeStakingStrategy.\n * The new ETH will be accounted for in `checkBalance` after the next snapBalances and verifyBalances txs.\n */\n receive() external payable {}\n\n /***************************************\n Internal functions\n ****************************************/\n\n /// @notice is not supported for this strategy as there is no platform token.\n function setPTokenAddress(address, address) external pure override {\n revert(\"Unsupported function\");\n }\n\n /// @notice is not supported for this strategy as there is no platform token.\n function removePToken(uint256) external pure override {\n revert(\"Unsupported function\");\n }\n\n /// @dev This strategy does not use a platform token like the old Aave and Compound strategies.\n function _abstractSetPToken(address _asset, address) internal override {}\n\n /// @dev Consensus rewards are compounded to the validator's balance instead of being\n /// swept to this strategy contract.\n /// Execution rewards from MEV and tx priority accumulate as ETH in this strategy contract.\n /// Withdrawals from validators also accumulate as ETH in this strategy contract.\n /// It's too complex to separate the rewards from withdrawals so this function is not implemented.\n /// Besides, ETH rewards are not sent to the Dripper any more. The Vault can now regulate\n /// the increase in assets.\n function _collectRewardTokens() internal pure override {\n revert(\"Unsupported function\");\n }\n}\n" + }, + "contracts/strategies/NativeStaking/CompoundingValidatorManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { Governable } from \"../../governance/Governable.sol\";\nimport { IDepositContract } from \"../../interfaces/IDepositContract.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { ISSVNetwork, Cluster } from \"../../interfaces/ISSVNetwork.sol\";\nimport { BeaconRoots } from \"../../beacon/BeaconRoots.sol\";\nimport { PartialWithdrawal } from \"../../beacon/PartialWithdrawal.sol\";\nimport { IBeaconProofs } from \"../../interfaces/IBeaconProofs.sol\";\n\n/**\n * @title Validator lifecycle management contract\n * @notice This contract implements all the required functionality to\n * register, deposit, withdraw, exit and remove validators.\n * @author Origin Protocol Inc\n */\nabstract contract CompoundingValidatorManager is Governable, Pausable {\n using SafeERC20 for IERC20;\n\n /// @dev The amount of ETH in wei that is required for a deposit to a new validator.\n uint256 internal constant DEPOSIT_AMOUNT_WEI = 1 ether;\n /// @dev Validator balances over this amount will eventually become active on the beacon chain.\n /// Due to hysteresis, if the effective balance is 31 ETH, the actual balance\n /// must rise to 32.25 ETH to trigger an effective balance update to 32 ETH.\n /// https://eth2book.info/capella/part2/incentives/balances/#hysteresis\n uint256 internal constant MIN_ACTIVATION_BALANCE_GWEI = 32.25 ether / 1e9;\n /// @dev The maximum number of deposits that are waiting to be verified as processed on the beacon chain.\n uint256 internal constant MAX_DEPOSITS = 32;\n /// @dev The maximum number of validators that can be verified.\n uint256 internal constant MAX_VERIFIED_VALIDATORS = 48;\n /// @dev The default withdrawable epoch value on the Beacon chain.\n /// A value in the far future means the validator is not exiting.\n uint64 internal constant FAR_FUTURE_EPOCH = type(uint64).max;\n /// @dev The number of seconds between each beacon chain slot.\n uint64 internal constant SLOT_DURATION = 12;\n /// @dev The number of slots in each beacon chain epoch.\n uint64 internal constant SLOTS_PER_EPOCH = 32;\n /// @dev Minimum time in seconds to allow snapped balances to be verified.\n /// Set to 35 slots which is 3 slots more than 1 epoch (32 slots). Deposits get processed\n /// once per epoch. This larger than 1 epoch delay should achieve that `snapBalances` sometimes\n /// get called in the middle (or towards the end) of the epoch. Giving the off-chain script\n /// sufficient time after the end of the epoch to prepare the proofs and call `verifyBalances`.\n /// This is considering a malicious actor would keep calling `snapBalances` as frequent as possible\n /// to disturb our operations.\n uint64 public constant SNAP_BALANCES_DELAY = 35 * SLOT_DURATION;\n\n /// @notice The address of the Wrapped ETH (WETH) token contract\n address internal immutable WETH;\n /// @notice The address of the beacon chain deposit contract\n address internal immutable BEACON_CHAIN_DEPOSIT_CONTRACT;\n /// @notice The address of the SSV Network contract used to interface with\n address internal immutable SSV_NETWORK;\n /// @notice Address of the OETH Vault proxy contract\n address internal immutable VAULT_ADDRESS;\n /// @notice Address of the Beacon Proofs contract that verifies beacon chain data\n address public immutable BEACON_PROOFS;\n /// @notice The timestamp of the Beacon chain genesis.\n /// @dev this is different on Testnets like Hoodi so is set at deployment time.\n uint64 internal immutable BEACON_GENESIS_TIMESTAMP;\n\n /// @notice Address of the registrator - allowed to register, withdraw, exit and remove validators\n address public validatorRegistrator;\n\n /// @notice Deposit data for new compounding validators.\n /// @dev A `VERIFIED` deposit can mean 3 separate things:\n /// - a deposit has been processed by the beacon chain and shall be included in the\n /// balance of the next verifyBalances call\n /// - a deposit has been done to a slashed validator and has probably been recovered\n /// back to this strategy. Probably because we can not know for certain. This contract\n /// only detects when the validator has passed its withdrawal epoch. It is close to impossible\n /// to prove with Merkle Proofs that the postponed deposit this contract is responsible for\n /// creating is not present anymore in BeaconChain.state.pending_deposits. This in effect\n /// means that there might be a period where this contract thinks the deposit has been already\n /// returned as ETH balance before it happens. This will result in some days (or weeks)\n /// -> depending on the size of deposit queue of showing a deficit when calling `checkBalance`.\n /// As this only offsets the yield and doesn't cause a critical double-counting we are not addressing\n /// this issue.\n /// - A deposit has been done to the validator, but our deposit has been front run by a malicious\n /// actor. Funds in the deposit this contract makes are not recoverable.\n enum DepositStatus {\n UNKNOWN, // default value\n PENDING, // deposit is pending and waiting to be verified\n VERIFIED // deposit has been verified\n }\n\n /// @param pubKeyHash Hash of validator's public key using the Beacon Chain's format\n /// @param amountGwei Amount of ETH in gwei that has been deposited to the beacon chain deposit contract\n /// @param slot The beacon chain slot number when the deposit has been made\n /// @param depositIndex The index of the deposit in the list of active deposits\n /// @param status The status of the deposit, either UNKNOWN, PENDING or VERIFIED\n struct DepositData {\n bytes32 pubKeyHash;\n uint64 amountGwei;\n uint64 slot;\n uint32 depositIndex;\n DepositStatus status;\n }\n /// @notice Restricts to only one deposit to an unverified validator at a time.\n /// This is to limit front-running attacks of deposits to the beacon chain contract.\n ///\n /// @dev The value is set to true when a deposit to a new validator has been done that has\n /// not yet be verified.\n bool public firstDeposit;\n /// @notice Mapping of the pending deposit roots to the deposit data\n mapping(bytes32 => DepositData) public deposits;\n /// @notice List of strategy deposit IDs to a validator.\n /// The ID is the merkle root of the pending deposit data which is unique for each validator, amount and block.\n /// Duplicate pending deposit roots are prevented so can be used as an identifier to each strategy deposit.\n /// The list can be for deposits waiting to be verified as processed on the beacon chain,\n /// or deposits that have been verified to an exiting validator and is now waiting for the\n /// validator's balance to be swept.\n /// The list may not be ordered by time of deposit.\n /// Removed deposits will move the last deposit to the removed index.\n bytes32[] public depositList;\n\n enum ValidatorState {\n NON_REGISTERED, // validator is not registered on the SSV network\n REGISTERED, // validator is registered on the SSV network\n STAKED, // validator has funds staked\n VERIFIED, // validator has been verified to exist on the beacon chain\n ACTIVE, // The validator balance is at least 32 ETH. The validator may not yet be active on the beacon chain.\n EXITING, // The validator has been requested to exit\n EXITED, // The validator has been verified to have a zero balance\n REMOVED, // validator has funds withdrawn to this strategy contract and is removed from the SSV\n INVALID // The validator has been front-run and the withdrawal address is not this strategy\n }\n\n // Validator data\n struct ValidatorData {\n ValidatorState state; // The state of the validator known to this contract\n uint40 index; // The index of the validator on the beacon chain\n }\n /// @notice List of validator public key hashes that have been verified to exist on the beacon chain.\n /// These have had a deposit processed and the validator's balance increased.\n /// Validators will be removed from this list when its verified they have a zero balance.\n bytes32[] public verifiedValidators;\n /// @notice Mapping of the hash of the validator's public key to the validator state and index.\n /// Uses the Beacon chain hashing for BLSPubkey which is sha256(abi.encodePacked(validator.pubkey, bytes16(0)))\n mapping(bytes32 => ValidatorData) public validator;\n\n /// @param blockRoot Beacon chain block root of the snapshot\n /// @param timestamp Timestamp of the snapshot\n /// @param ethBalance The balance of ETH in the strategy contract at the snapshot\n struct Balances {\n bytes32 blockRoot;\n uint64 timestamp;\n uint128 ethBalance;\n }\n /// @notice Mapping of the block root to the balances at that slot\n Balances public snappedBalance;\n /// @notice The last verified ETH balance of the strategy\n uint256 public lastVerifiedEthBalance;\n\n /// @dev This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately\n /// deposit it to an underlying platform. Rather a special privilege account stakes it to the validators.\n /// For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been\n /// deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track\n /// of WETH that has already been accounted for.\n /// This value represents the amount of WETH balance of this contract that has already been accounted for by the\n /// deposit events.\n /// It is important to note that this variable is not concerned with WETH that is a result of full/partial\n /// withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to\n /// be staked.\n uint256 public depositedWethAccountedFor;\n\n // For future use\n uint256[41] private __gap;\n\n event RegistratorChanged(address indexed newAddress);\n event FirstDepositReset();\n event SSVValidatorRegistered(\n bytes32 indexed pubKeyHash,\n uint64[] operatorIds\n );\n event SSVValidatorRemoved(bytes32 indexed pubKeyHash, uint64[] operatorIds);\n event ETHStaked(\n bytes32 indexed pubKeyHash,\n bytes32 indexed pendingDepositRoot,\n bytes pubKey,\n uint256 amountWei\n );\n event ValidatorVerified(\n bytes32 indexed pubKeyHash,\n uint40 indexed validatorIndex\n );\n event ValidatorInvalid(bytes32 indexed pubKeyHash);\n event DepositVerified(\n bytes32 indexed pendingDepositRoot,\n uint256 amountWei\n );\n event ValidatorWithdraw(bytes32 indexed pubKeyHash, uint256 amountWei);\n event BalancesSnapped(bytes32 indexed blockRoot, uint256 ethBalance);\n event BalancesVerified(\n uint64 indexed timestamp,\n uint256 totalDepositsWei,\n uint256 totalValidatorBalance,\n uint256 ethBalance\n );\n\n /// @dev Throws if called by any account other than the Registrator\n modifier onlyRegistrator() {\n _onlyRegistrator();\n _;\n }\n\n /// @dev internal function used to reduce contract size\n function _onlyRegistrator() internal view {\n require(msg.sender == validatorRegistrator, \"Not Registrator\");\n }\n\n /// @dev Throws if called by any account other than the Registrator or Governor\n modifier onlyRegistratorOrGovernor() {\n require(\n msg.sender == validatorRegistrator || isGovernor(),\n \"Not Registrator or Governor\"\n );\n _;\n }\n\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _vaultAddress Address of the Vault\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _beaconProofs Address of the Beacon Proofs contract that verifies beacon chain data\n /// @param _beaconGenesisTimestamp The timestamp of the Beacon chain's genesis.\n constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork,\n address _beaconProofs,\n uint64 _beaconGenesisTimestamp\n ) {\n WETH = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK = _ssvNetwork;\n VAULT_ADDRESS = _vaultAddress;\n BEACON_PROOFS = _beaconProofs;\n BEACON_GENESIS_TIMESTAMP = _beaconGenesisTimestamp;\n\n require(\n block.timestamp > _beaconGenesisTimestamp,\n \"Invalid genesis timestamp\"\n );\n }\n\n /**\n *\n * Admin Functions\n *\n */\n\n /// @notice Set the address of the registrator which can register, exit and remove validators\n function setRegistrator(address _address) external onlyGovernor {\n validatorRegistrator = _address;\n emit RegistratorChanged(_address);\n }\n\n /// @notice Reset the `firstDeposit` flag to false so deposits to unverified validators can be made again.\n function resetFirstDeposit() external onlyGovernor {\n require(firstDeposit, \"No first deposit\");\n\n firstDeposit = false;\n\n emit FirstDepositReset();\n }\n\n function pause() external onlyRegistratorOrGovernor {\n _pause();\n }\n\n function unPause() external onlyGovernor {\n _unpause();\n }\n\n /**\n *\n * Validator Management\n *\n */\n\n /// @notice Registers a single validator in a SSV Cluster.\n /// Only the Registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param sharesData The shares data for the validator\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n // slither-disable-start reentrancy-no-eth\n function registerSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n bytes calldata sharesData,\n Cluster calldata cluster\n ) external payable onlyRegistrator whenNotPaused {\n // Hash the public key using the Beacon Chain's format\n bytes32 pubKeyHash = _hashPubKey(publicKey);\n // Check each public key has not already been used\n require(\n validator[pubKeyHash].state == ValidatorState.NON_REGISTERED,\n \"Validator already registered\"\n );\n\n // Store the validator state as registered\n validator[pubKeyHash].state = ValidatorState.REGISTERED;\n\n ISSVNetwork(SSV_NETWORK).registerValidator{ value: msg.value }(\n publicKey,\n operatorIds,\n sharesData,\n cluster\n );\n\n emit SSVValidatorRegistered(pubKeyHash, operatorIds);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n struct ValidatorStakeData {\n bytes pubkey;\n bytes signature;\n bytes32 depositDataRoot;\n }\n\n /// @notice Stakes WETH in this strategy to a compounding validator.\n /// The first deposit to a new validator, the amount must be 1 ETH.\n /// Another deposit of at least 31 ETH is required for the validator to be activated.\n /// This second deposit has to be done after the validator has been verified.\n /// Does not convert any ETH sitting in this strategy to WETH.\n /// There can not be two deposits to the same validator in the same block for the same amount.\n /// Function is pausable so in case a run-away Registrator can be prevented from continuing\n /// to deposit funds to slashed or undesired validators.\n /// @param validatorStakeData validator data needed to stake.\n /// The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot.\n /// Only the registrator can call this function.\n /// @param depositAmountGwei The amount of WETH to stake to the validator in Gwei.\n // slither-disable-start reentrancy-eth,reentrancy-no-eth\n function stakeEth(\n ValidatorStakeData calldata validatorStakeData,\n uint64 depositAmountGwei\n ) external onlyRegistrator whenNotPaused {\n uint256 depositAmountWei = uint256(depositAmountGwei) * 1 gwei;\n // Check there is enough WETH from the deposits sitting in this strategy contract\n // There could be ETH from withdrawals but we'll ignore that. If it's really needed\n // the ETH can be withdrawn and then deposited back to the strategy.\n require(\n depositAmountWei <= IWETH9(WETH).balanceOf(address(this)),\n \"Insufficient WETH\"\n );\n require(depositList.length < MAX_DEPOSITS, \"Max deposits\");\n\n // Convert required ETH from WETH and do the necessary accounting\n _convertWethToEth(depositAmountWei);\n\n // Hash the public key using the Beacon Chain's hashing for BLSPubkey\n bytes32 pubKeyHash = _hashPubKey(validatorStakeData.pubkey);\n ValidatorState currentState = validator[pubKeyHash].state;\n // Can only stake to a validator that has been registered, verified or active.\n // Can not stake to a validator that has been staked but not yet verified.\n require(\n (currentState == ValidatorState.REGISTERED ||\n currentState == ValidatorState.VERIFIED ||\n currentState == ValidatorState.ACTIVE),\n \"Not registered or verified\"\n );\n require(depositAmountWei >= 1 ether, \"Deposit too small\");\n if (currentState == ValidatorState.REGISTERED) {\n // Can only have one pending deposit to an unverified validator at a time.\n // This is to limit front-running deposit attacks to a single deposit.\n // The exiting deposit needs to be verified before another deposit can be made.\n // If there was a front-running attack, the validator needs to be verified as invalid\n // and the Governor calls `resetFirstDeposit` to set `firstDeposit` to false.\n require(!firstDeposit, \"Existing first deposit\");\n // Limits the amount of ETH that can be at risk from a front-running deposit attack.\n require(\n depositAmountWei == DEPOSIT_AMOUNT_WEI,\n \"Invalid first deposit amount\"\n );\n // Limits the number of validator balance proofs to verifyBalances\n require(\n verifiedValidators.length + 1 <= MAX_VERIFIED_VALIDATORS,\n \"Max validators\"\n );\n\n // Flag a deposit to an unverified validator so no other deposits can be made\n // to an unverified validator.\n firstDeposit = true;\n validator[pubKeyHash].state = ValidatorState.STAKED;\n }\n\n /* 0x02 to indicate that withdrawal credentials are for a compounding validator\n * that was introduced with the Pectra upgrade.\n * bytes11(0) to fill up the required zeros\n * remaining bytes20 are for the address\n */\n bytes memory withdrawalCredentials = abi.encodePacked(\n bytes1(0x02),\n bytes11(0),\n address(this)\n );\n\n /// After the Pectra upgrade the validators have a new restriction when proposing\n /// blocks. The timestamps are at strict intervals of 12 seconds from the genesis block\n /// forward. Each slot is created at strict 12 second intervals and those slots can\n /// either have blocks attached to them or not. This way using the block.timestamp\n /// the slot number can easily be calculated.\n uint64 depositSlot = (SafeCast.toUint64(block.timestamp) -\n BEACON_GENESIS_TIMESTAMP) / SLOT_DURATION;\n\n // Calculate the merkle root of the beacon chain pending deposit data.\n // This is used as the unique ID of the deposit.\n bytes32 pendingDepositRoot = IBeaconProofs(BEACON_PROOFS)\n .merkleizePendingDeposit(\n pubKeyHash,\n withdrawalCredentials,\n depositAmountGwei,\n validatorStakeData.signature,\n depositSlot\n );\n require(\n deposits[pendingDepositRoot].status == DepositStatus.UNKNOWN,\n \"Duplicate deposit\"\n );\n\n // Store the deposit data for verifyDeposit and verifyBalances\n deposits[pendingDepositRoot] = DepositData({\n pubKeyHash: pubKeyHash,\n amountGwei: depositAmountGwei,\n slot: depositSlot,\n depositIndex: SafeCast.toUint32(depositList.length),\n status: DepositStatus.PENDING\n });\n depositList.push(pendingDepositRoot);\n\n // Deposit to the Beacon Chain deposit contract.\n // This will create a deposit in the beacon chain's pending deposit queue.\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\n value: depositAmountWei\n }(\n validatorStakeData.pubkey,\n withdrawalCredentials,\n validatorStakeData.signature,\n validatorStakeData.depositDataRoot\n );\n\n emit ETHStaked(\n pubKeyHash,\n pendingDepositRoot,\n validatorStakeData.pubkey,\n depositAmountWei\n );\n }\n\n // slither-disable-end reentrancy-eth,reentrancy-no-eth\n\n /// @notice Request a full or partial withdrawal from a validator.\n /// A zero amount will trigger a full withdrawal.\n /// If the remaining balance is < 32 ETH then only the amount in excess of 32 ETH will be withdrawn.\n /// Only the Registrator can call this function.\n /// 1 wei of value should be sent with the tx to pay for the withdrawal request fee.\n /// If no value sent, 1 wei will be taken from the strategy's ETH balance if it has any.\n /// If no ETH balance, the tx will revert.\n /// @param publicKey The public key of the validator\n /// @param amountGwei The amount of ETH to be withdrawn from the validator in Gwei.\n /// A zero amount will trigger a full withdrawal.\n // slither-disable-start reentrancy-no-eth\n function validatorWithdrawal(bytes calldata publicKey, uint64 amountGwei)\n external\n payable\n onlyRegistrator\n {\n // Hash the public key using the Beacon Chain's format\n bytes32 pubKeyHash = _hashPubKey(publicKey);\n ValidatorData memory validatorDataMem = validator[pubKeyHash];\n // Validator full withdrawal could be denied due to multiple reasons:\n // - the validator has not been activated or active long enough\n // (current_epoch < activation_epoch + SHARD_COMMITTEE_PERIOD)\n // - the validator has pending balance to withdraw from a previous partial withdrawal request\n //\n // Meaning that the on-chain to beacon chain full withdrawal request could fail. Instead\n // of adding complexity of verifying if a validator is eligible for a full exit, we allow\n // multiple full withdrawal requests per validator.\n require(\n validatorDataMem.state == ValidatorState.ACTIVE ||\n validatorDataMem.state == ValidatorState.EXITING,\n \"Validator not active/exiting\"\n );\n\n // If a full withdrawal (validator exit)\n if (amountGwei == 0) {\n // For each staking strategy's deposits\n uint256 depositsCount = depositList.length;\n for (uint256 i = 0; i < depositsCount; ++i) {\n bytes32 pendingDepositRoot = depositList[i];\n // Check there is no pending deposits to the exiting validator\n require(\n pubKeyHash != deposits[pendingDepositRoot].pubKeyHash,\n \"Pending deposit\"\n );\n }\n\n // Store the validator state as exiting so no more deposits can be made to it.\n // This may already be EXITING if the previous exit request failed. eg the validator\n // was not active long enough.\n validator[pubKeyHash].state = ValidatorState.EXITING;\n }\n\n // Do not remove from the list of verified validators.\n // This is done in the verifyBalances function once the validator's balance has been verified to be zero.\n // The validator state will be set to EXITED in the verifyBalances function.\n\n PartialWithdrawal.request(publicKey, amountGwei);\n\n emit ValidatorWithdraw(pubKeyHash, uint256(amountGwei) * 1 gwei);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Remove the validator from the SSV Cluster after:\n /// - the validator has been exited from `validatorWithdrawal` or slashed\n /// - the validator has incorrectly registered and can not be staked to\n /// - the initial deposit was front-run and the withdrawal address is not this strategy's address.\n /// Make sure `validatorWithdrawal` is called with a zero amount and the validator has exited the Beacon chain.\n /// If removed before the validator has exited the beacon chain will result in the validator being slashed.\n /// Only the registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n // slither-disable-start reentrancy-no-eth\n function removeSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator {\n // Hash the public key using the Beacon Chain's format\n bytes32 pubKeyHash = _hashPubKey(publicKey);\n ValidatorState currentState = validator[pubKeyHash].state;\n // Can remove SSV validators that were incorrectly registered and can not be deposited to.\n require(\n currentState == ValidatorState.REGISTERED ||\n currentState == ValidatorState.EXITED ||\n currentState == ValidatorState.INVALID,\n \"Validator not regd or exited\"\n );\n\n validator[pubKeyHash].state = ValidatorState.REMOVED;\n\n ISSVNetwork(SSV_NETWORK).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n\n emit SSVValidatorRemoved(pubKeyHash, operatorIds);\n }\n\n /**\n *\n * SSV Management\n *\n */\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Migrate the SSV cluster to use ETH for payment instead of SSV tokens.\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n function migrateClusterToETH(\n uint64[] memory operatorIds,\n Cluster memory cluster\n ) external payable onlyGovernor {\n ISSVNetwork(SSV_NETWORK).migrateClusterToETH{ value: msg.value }(\n operatorIds,\n cluster\n );\n\n // The SSV Network emits\n // ClusterMigratedToETH(msg.sender, operatorIds, msg.value, ssvClusterBalance, effectiveBalance, cluster)\n }\n\n /**\n *\n * Beacon Chain Proofs\n *\n */\n\n /// @notice Verifies a validator's index to its public key.\n /// Adds to the list of verified validators if the validator's withdrawal address is this strategy's address.\n /// Marks the validator as invalid and removes the deposit if the withdrawal address is not this strategy's address.\n /// @param nextBlockTimestamp The timestamp of the execution layer block after the beacon chain slot\n /// we are verifying.\n /// The next one is needed as the Beacon Oracle returns the parent beacon block root for a block timestamp,\n /// which is the beacon block root of the previous block.\n /// @param validatorIndex The index of the validator on the beacon chain.\n /// @param pubKeyHash The hash of the validator's public key using the Beacon Chain's format\n /// @param withdrawalCredentials contain the validator type and withdrawal address. These can be incorrect and/or\n /// malformed. In case of incorrect withdrawalCredentials the validator deposit has been front run\n /// @param validatorPubKeyProof The merkle proof for the validator public key to the beacon block root.\n /// This is 53 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n /// BeaconBlock.state.validators[validatorIndex].pubkey\n function verifyValidator(\n uint64 nextBlockTimestamp,\n uint40 validatorIndex,\n bytes32 pubKeyHash,\n bytes32 withdrawalCredentials,\n bytes calldata validatorPubKeyProof\n ) external {\n require(\n validator[pubKeyHash].state == ValidatorState.STAKED,\n \"Validator not staked\"\n );\n\n // Get the beacon block root of the slot we are verifying the validator in.\n // The parent beacon block root of the next block is the beacon block root of the slot we are verifying.\n bytes32 blockRoot = BeaconRoots.parentBlockRoot(nextBlockTimestamp);\n\n // Verify the validator index is for the validator with the given public key.\n // Also verify the validator's withdrawal credentials\n IBeaconProofs(BEACON_PROOFS).verifyValidator(\n blockRoot,\n pubKeyHash,\n validatorPubKeyProof,\n validatorIndex,\n withdrawalCredentials\n );\n\n // Store the validator state as verified\n validator[pubKeyHash] = ValidatorData({\n state: ValidatorState.VERIFIED,\n index: validatorIndex\n });\n\n bytes32 expectedWithdrawalCredentials = bytes32(\n abi.encodePacked(bytes1(0x02), bytes11(0), address(this))\n );\n\n // If the initial deposit was front-run and the withdrawal address is not this strategy\n // or the validator type is not a compounding validator (0x02)\n if (expectedWithdrawalCredentials != withdrawalCredentials) {\n // override the validator state\n validator[pubKeyHash].state = ValidatorState.INVALID;\n\n // Find and remove the deposit as the funds can not be recovered\n uint256 depositCount = depositList.length;\n for (uint256 i = 0; i < depositCount; i++) {\n DepositData memory deposit = deposits[depositList[i]];\n if (deposit.pubKeyHash == pubKeyHash) {\n // next verifyBalances will correctly account for the loss of a front-run\n // deposit. Doing it here accounts for the loss as soon as possible\n lastVerifiedEthBalance -= Math.min(\n lastVerifiedEthBalance,\n uint256(deposit.amountGwei) * 1 gwei\n );\n _removeDeposit(depositList[i], deposit);\n break;\n }\n }\n\n // Leave the `firstDeposit` flag as true so no more deposits to unverified validators can be made.\n // The Governor has to reset the `firstDeposit` to false before another deposit to\n // an unverified validator can be made.\n // The Governor can set a new `validatorRegistrator` if they suspect it has been compromised.\n\n emit ValidatorInvalid(pubKeyHash);\n return;\n }\n\n // Add the new validator to the list of verified validators\n verifiedValidators.push(pubKeyHash);\n\n // Reset the firstDeposit flag as the first deposit to an unverified validator has been verified.\n firstDeposit = false;\n\n emit ValidatorVerified(pubKeyHash, validatorIndex);\n }\n\n struct FirstPendingDepositSlotProofData {\n uint64 slot;\n bytes proof;\n }\n\n struct StrategyValidatorProofData {\n uint64 withdrawableEpoch;\n bytes withdrawableEpochProof;\n }\n\n /// @notice Verifies a deposit on the execution layer has been processed by the beacon chain.\n /// This means the accounting of the strategy's ETH moves from a pending deposit to a validator balance.\n ///\n /// Important: this function has a limitation where `depositProcessedSlot` that is passed by the off-chain\n /// verifier requires a slot immediately after it to propose a block otherwise the `BeaconRoots.parentBlockRoot`\n /// will fail. This shouldn't be a problem, since by the current behaviour of beacon chain only 1%-3% slots\n /// don't propose a block.\n /// @param pendingDepositRoot The unique identifier of the deposit emitted in `ETHStaked` from\n /// the `stakeEth` function.\n /// @param depositProcessedSlot Any slot on or after the strategy's deposit was processed on the beacon chain.\n /// Can not be a slot with pending deposits with the same slot as the deposit being verified.\n /// Can not be a slot before a missed slot as the Beacon Root contract will have the parent block root\n /// set for the next block timestamp in 12 seconds time.\n /// @param firstPendingDeposit a `FirstPendingDepositSlotProofData` struct containing:\n /// - slot: The beacon chain slot of the first deposit in the beacon chain's deposit queue.\n /// Can be any non-zero value if the deposit queue is empty.\n /// - proof: The merkle proof of the first pending deposit's slot to the beacon block root.\n /// Can be either:\n /// * 40 witness hashes for BeaconBlock.state.PendingDeposits[0].slot when the deposit queue is not empty.\n /// * 37 witness hashes for BeaconBlock.state.PendingDeposits[0] when the deposit queue is empty.\n /// The 32 byte witness hashes are concatenated together starting from the leaf node.\n /// @param strategyValidatorData a `StrategyValidatorProofData` struct containing:\n /// - withdrawableEpoch: The withdrawable epoch of the validator the strategy is depositing to.\n /// - withdrawableEpochProof: The merkle proof for the withdrawable epoch of the validator the strategy\n /// is depositing to, to the beacon block root.\n /// This is 53 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n // slither-disable-start reentrancy-no-eth\n function verifyDeposit(\n bytes32 pendingDepositRoot,\n uint64 depositProcessedSlot,\n FirstPendingDepositSlotProofData calldata firstPendingDeposit,\n StrategyValidatorProofData calldata strategyValidatorData\n ) external {\n // Load into memory the previously saved deposit data\n DepositData memory deposit = deposits[pendingDepositRoot];\n ValidatorData memory strategyValidator = validator[deposit.pubKeyHash];\n require(deposit.status == DepositStatus.PENDING, \"Deposit not pending\");\n require(firstPendingDeposit.slot != 0, \"Zero 1st pending deposit slot\");\n\n // We should allow the verification of deposits for validators that have been marked as exiting\n // to cover this situation:\n // - there are 2 pending deposits\n // - beacon chain has slashed the validator\n // - when verifyDeposit is called for the first deposit it sets the Validator state to EXITING\n // - verifyDeposit should allow a secondary call for the other deposit to a slashed validator\n require(\n strategyValidator.state == ValidatorState.VERIFIED ||\n strategyValidator.state == ValidatorState.ACTIVE ||\n strategyValidator.state == ValidatorState.EXITING,\n \"Not verified/active/exiting\"\n );\n // The verification slot must be after the deposit's slot.\n // This is needed for when the deposit queue is empty.\n require(deposit.slot < depositProcessedSlot, \"Slot not after deposit\");\n\n uint64 snapTimestamp = snappedBalance.timestamp;\n\n // This check prevents an accounting error that can happen if:\n // - snapBalances are snapped at the time of T\n // - deposit is processed on the beacon chain after time T and before verifyBalances()\n // - verifyDeposit is called before verifyBalances which removes a deposit from depositList\n // and deposit balance from totalDepositsWei\n // - verifyBalances is called under-reporting the strategy's balance\n require(\n (_calcNextBlockTimestamp(depositProcessedSlot) <= snapTimestamp) ||\n snapTimestamp == 0,\n \"Deposit after balance snapshot\"\n );\n\n // Get the parent beacon block root of the next block which is the block root of the deposit verification slot.\n // This will revert if the slot after the verification slot was missed.\n bytes32 depositBlockRoot = BeaconRoots.parentBlockRoot(\n _calcNextBlockTimestamp(depositProcessedSlot)\n );\n\n // Verify the slot of the first pending deposit matches the beacon chain\n bool isDepositQueueEmpty = IBeaconProofs(BEACON_PROOFS)\n .verifyFirstPendingDeposit(\n depositBlockRoot,\n firstPendingDeposit.slot,\n firstPendingDeposit.proof\n );\n\n // Verify the withdrawableEpoch on the validator of the strategy's deposit\n IBeaconProofs(BEACON_PROOFS).verifyValidatorWithdrawable(\n depositBlockRoot,\n strategyValidator.index,\n strategyValidatorData.withdrawableEpoch,\n strategyValidatorData.withdrawableEpochProof\n );\n\n uint64 firstPendingDepositEpoch = firstPendingDeposit.slot /\n SLOTS_PER_EPOCH;\n\n // If deposit queue is empty all deposits have certainly been processed. If not\n // a validator can either be not exiting and no further checks are required.\n // Or a validator is exiting then this function needs to make sure that the\n // pending deposit to an exited validator has certainly been processed. The\n // slot/epoch of first pending deposit is the one that contains the transaction\n // where the deposit to the ETH Deposit Contract has been made.\n //\n // Once the firstPendingDepositEpoch becomes greater than the withdrawableEpoch of\n // the slashed validator then the deposit has certainly been processed. When the beacon\n // chain reaches the withdrawableEpoch of the validator the deposit will no longer be\n // postponed. And any new deposits created (and present in the deposit queue)\n // will have an equal or larger withdrawableEpoch.\n require(\n strategyValidatorData.withdrawableEpoch == FAR_FUTURE_EPOCH ||\n strategyValidatorData.withdrawableEpoch <=\n firstPendingDepositEpoch ||\n isDepositQueueEmpty,\n \"Exit Deposit likely not proc.\"\n );\n\n // solhint-disable max-line-length\n // Check the deposit slot is before the first pending deposit's slot on the beacon chain.\n // If this is not true then we can't guarantee the deposit has been processed by the beacon chain.\n // The deposit's slot can not be the same slot as the first pending deposit as there could be\n // many deposits in the same block, hence have the same pending deposit slot.\n // If the deposit queue is empty then our deposit must have been processed on the beacon chain.\n // The deposit slot can be zero for validators consolidating to a compounding validator or 0x01 validator\n // being promoted to a compounding one. Reference:\n // - [switch_to_compounding_validator](https://ethereum.github.io/consensus-specs/specs/electra/beacon-chain/#new-switch_to_compounding_validator\n // - [queue_excess_active_balance](https://ethereum.github.io/consensus-specs/specs/electra/beacon-chain/#new-queue_excess_active_balance)\n // - [process_consolidation_request](https://ethereum.github.io/consensus-specs/specs/electra/beacon-chain/#new-process_consolidation_request)\n // We can not guarantee that the deposit has been processed in that case.\n // solhint-enable max-line-length\n require(\n deposit.slot < firstPendingDeposit.slot || isDepositQueueEmpty,\n \"Deposit likely not processed\"\n );\n\n // Remove the deposit now it has been verified as processed on the beacon chain.\n _removeDeposit(pendingDepositRoot, deposit);\n\n emit DepositVerified(\n pendingDepositRoot,\n uint256(deposit.amountGwei) * 1 gwei\n );\n }\n\n function _removeDeposit(\n bytes32 pendingDepositRoot,\n DepositData memory deposit\n ) internal {\n // After verifying the proof, update the contract storage\n deposits[pendingDepositRoot].status = DepositStatus.VERIFIED;\n // Move the last deposit to the index of the verified deposit\n bytes32 lastDeposit = depositList[depositList.length - 1];\n depositList[deposit.depositIndex] = lastDeposit;\n deposits[lastDeposit].depositIndex = deposit.depositIndex;\n // Delete the last deposit from the list\n depositList.pop();\n }\n\n /// @dev Calculates the timestamp of the next execution block from the given slot.\n /// @param slot The beacon chain slot number used for merkle proof verification.\n function _calcNextBlockTimestamp(uint64 slot)\n internal\n view\n returns (uint64)\n {\n // Calculate the next block timestamp from the slot.\n return SLOT_DURATION * slot + BEACON_GENESIS_TIMESTAMP + SLOT_DURATION;\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Stores the current ETH balance at the current block and beacon block root\n /// of the slot that is associated with the previous block.\n ///\n /// When snapping / verifying balance it is of a high importance that there is no\n /// miss-match in respect to ETH that is held by the contract and balances that are\n /// verified on the validators.\n ///\n /// First some context on the beacon-chain block building behaviour. Relevant parts of\n /// constructing a block on the beacon chain consist of:\n /// - process_withdrawals: ETH is deducted from the validator's balance\n /// - process_execution_payload: immediately after the previous step executing all the\n /// transactions\n /// - apply the withdrawals: adding ETH to the recipient which is the withdrawal address\n /// contained in the withdrawal credentials of the exited validators\n ///\n /// That means that balance increases which are part of the post-block execution state are\n /// done within the block, but the transaction that are contained within that block can not\n /// see / interact with the balance from the exited validators. Only transactions in the\n /// next block can do that.\n ///\n /// When snap balances is performed the state of the chain is snapped across 2 separate\n /// chain states:\n /// - ETH balance of the contract is recorded on block X -> and corresponding slot Y\n /// - beacon chain block root is recorded of block X - 1 -> and corresponding slot Y - 1\n /// given there were no missed slots. It could also be Y - 2, Y - 3 depending on how\n /// many slots have not managed to propose a block. For the sake of simplicity this slot\n /// will be referred to as Y - 1 as it makes no difference in the argument\n ///\n /// Given these 2 separate chain states it is paramount that verify balances can not experience\n /// miss-counting ETH or much more dangerous double counting of the ETH.\n ///\n /// When verifyBalances is called it is performed on the current block Z where Z > X. Verify\n /// balances adds up all the ETH (omitting WETH) controlled by this contract:\n /// - ETH balance in the contract on block X\n /// - ETH balance in Deposits on block Z that haven't been yet processed in slot Y - 1\n /// - ETH balance in validators that are active in slot Y - 1\n /// - skips the ETH balance in validators that have withdrawn in slot Y - 1 (or sooner)\n /// and have their balance visible to transactions in slot Y and corresponding block X\n /// (or sooner)\n ///\n /// Lets verify the correctness of ETH accounting given the above described behaviour.\n ///\n /// *ETH balance in the contract on block X*\n ///\n /// This is an ETH balance of the contract on a non current X block. Any ETH leaving the\n /// contract as a result of a withdrawal subtracts from the ETH accounted for on block X\n /// if `verifyBalances` has already been called. It also invalidates a `snapBalances` in\n /// case `verifyBalances` has not been called yet. Not performing this would result in not\n /// accounting for the withdrawn ETH that has happened anywhere in the block interval [X + 1, Z].\n ///\n /// Similarly to withdrawals any `stakeEth` deposits to the deposit contract adds to the ETH\n /// accounted for since the last `verifyBalances` has been called. And it invalidates the\n /// `snapBalances` in case `verifyBalances` hasn't been yet called. Not performing this\n /// would result in double counting the `stakedEth` since it would be present once in the\n /// snapped contract balance and the second time in deposit storage variables.\n ///\n /// This behaviour is correct.\n ///\n /// *ETH balance in Deposits on block Z that haven't been yet processed in slot Y - 1*\n ///\n /// The contract sums up all the ETH that has been deposited to the Beacon chain deposit\n /// contract at block Z. The execution layer doesn't have direct access to the state of\n /// deposits on the beacon chain. And if it is to sum up all the ETH that is marked to be\n /// deposited it needs to be sure to not double count ETH that is in deposits (storage vars)\n /// and could also be part of the validator balances. It does that by verifying that at\n /// slot Y - 1 none of the deposits visible on block Z have been processed. Meaning since\n /// the last snap till now all are still in queue. Which ensures they can not be part of\n /// the validator balances in later steps.\n ///\n /// This behaviour is correct.\n ///\n /// *ETH balance in validators that are active in slot Y - 1*\n ///\n /// The contract is verifying none of the deposits on Y - 1 slot have been processed and\n /// for that reason it checks the validator balances in the same slot. Ensuring accounting\n /// correctness.\n ///\n /// This behaviour is correct.\n ///\n /// *The withdrawn validators*\n ///\n /// The withdrawn validators could have their balances deducted in any slot before slot\n /// Y - 1 and the execution layer sees the balance increase in the subsequent slot. Lets\n /// look at the \"worst case scenario\" where the validator withdrawal is processed in the\n /// slot Y - 1 (snapped slot) and see their balance increase (in execution layer) in slot\n /// Y -> block X. The ETH balance on the contract is snapped at block X meaning that\n /// even if the validator exits at the latest possible time it is paramount that the ETH\n /// balance on the execution layer is recorded in the next block. Correctly accounting\n /// for the withdrawn ETH.\n ///\n /// Worth mentioning if the validator exit is processed by the slot Y and balance increase\n /// seen on the execution layer on block X + 1 the withdrawal is ignored by both the\n /// validator balance verification as well as execution layer contract balance snap.\n ///\n /// This behaviour is correct.\n ///\n /// The validator balances on the beacon chain can then be proved with `verifyBalances`.\n function snapBalances() external onlyRegistrator {\n uint64 currentTimestamp = SafeCast.toUint64(block.timestamp);\n require(\n snappedBalance.timestamp + SNAP_BALANCES_DELAY < currentTimestamp,\n \"Snap too soon\"\n );\n\n bytes32 blockRoot = BeaconRoots.parentBlockRoot(currentTimestamp);\n // Get the current ETH balance\n uint256 ethBalance = address(this).balance;\n\n // Store the snapped balance\n snappedBalance = Balances({\n blockRoot: blockRoot,\n timestamp: currentTimestamp,\n ethBalance: SafeCast.toUint128(ethBalance)\n });\n\n emit BalancesSnapped(blockRoot, ethBalance);\n }\n\n // A struct is used to avoid stack too deep errors\n struct BalanceProofs {\n // BeaconBlock.state.balances\n bytes32 balancesContainerRoot;\n bytes balancesContainerProof;\n // BeaconBlock.state.balances[validatorIndex]\n bytes32[] validatorBalanceLeaves;\n bytes[] validatorBalanceProofs;\n }\n\n struct PendingDepositProofs {\n bytes32 pendingDepositContainerRoot;\n bytes pendingDepositContainerProof;\n uint32[] pendingDepositIndexes;\n bytes[] pendingDepositProofs;\n }\n\n /// @notice Verifies the balances of all active validators on the beacon chain\n /// and checks each of the strategy's deposits are still to be processed by the beacon chain.\n /// @param balanceProofs a `BalanceProofs` struct containing the following:\n /// - balancesContainerRoot: The merkle root of the balances container\n /// - balancesContainerProof: The merkle proof for the balances container to the beacon block root.\n /// This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n /// - validatorBalanceLeaves: Array of leaf nodes containing the validator balance with three other balances.\n /// - validatorBalanceProofs: Array of merkle proofs for the validator balance to the Balances container root.\n /// This is 39 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n /// @param pendingDepositProofs a `PendingDepositProofs` struct containing the following:\n /// - pendingDepositContainerRoot: The merkle root of the pending deposits list container\n /// - pendingDepositContainerProof: The merkle proof from the pending deposits list container\n /// to the beacon block root.\n /// This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n /// - pendingDepositIndexes: Array of indexes in the pending deposits list container for each\n /// of the strategy's deposits.\n /// - pendingDepositProofs: Array of merkle proofs for each strategy deposit in the\n /// beacon chain's pending deposit list container to the pending deposits list container root.\n /// These are 28 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n // slither-disable-start reentrancy-no-eth\n function verifyBalances(\n BalanceProofs calldata balanceProofs,\n PendingDepositProofs calldata pendingDepositProofs\n ) external onlyRegistrator {\n // Load previously snapped balances for the given block root\n Balances memory balancesMem = snappedBalance;\n // Check the balances are the latest\n require(balancesMem.timestamp > 0, \"No snapped balances\");\n\n uint256 verifiedValidatorsCount = verifiedValidators.length;\n uint256 totalValidatorBalance = 0;\n uint256 depositsCount = depositList.length;\n\n // If there are no verified validators then we can skip the balance verification\n if (verifiedValidatorsCount > 0) {\n require(\n balanceProofs.validatorBalanceProofs.length ==\n verifiedValidatorsCount,\n \"Invalid balance proofs\"\n );\n require(\n balanceProofs.validatorBalanceLeaves.length ==\n verifiedValidatorsCount,\n \"Invalid balance leaves\"\n );\n // verify beaconBlock.state.balances root to beacon block root\n IBeaconProofs(BEACON_PROOFS).verifyBalancesContainer(\n balancesMem.blockRoot,\n balanceProofs.balancesContainerRoot,\n balanceProofs.balancesContainerProof\n );\n\n bytes32[]\n memory validatorHashesMem = _getPendingDepositValidatorHashes(\n depositsCount\n );\n\n // for each validator in reverse order so we can pop off exited validators at the end\n for (uint256 i = verifiedValidatorsCount; i > 0; ) {\n --i;\n ValidatorData memory validatorDataMem = validator[\n verifiedValidators[i]\n ];\n // verify validator's balance in beaconBlock.state.balances to the\n // beaconBlock.state.balances container root\n uint256 validatorBalanceGwei = IBeaconProofs(BEACON_PROOFS)\n .verifyValidatorBalance(\n balanceProofs.balancesContainerRoot,\n balanceProofs.validatorBalanceLeaves[i],\n balanceProofs.validatorBalanceProofs[i],\n validatorDataMem.index\n );\n\n // If the validator has exited and the balance is now zero\n if (validatorBalanceGwei == 0) {\n // Check if there are any pending deposits to this validator\n bool depositPending = false;\n for (uint256 j = 0; j < validatorHashesMem.length; j++) {\n if (validatorHashesMem[j] == verifiedValidators[i]) {\n depositPending = true;\n break;\n }\n }\n\n // If validator has a pending deposit we can not remove due to\n // the following situation:\n // - validator has a pending deposit\n // - validator has been slashed\n // - sweep cycle has withdrawn all ETH from the validator. Balance is 0\n // - beacon chain has processed the deposit and set the validator balance\n // to deposit amount\n // - if validator is no longer in the list of verifiedValidators its\n // balance will not be considered and be under-counted.\n if (!depositPending) {\n // Store the validator state as exited\n // This could have been in VERIFIED, ACTIVE or EXITING state\n validator[verifiedValidators[i]].state = ValidatorState\n .EXITED;\n\n // Remove the validator with a zero balance from the list of verified validators\n\n // Reduce the count of verified validators which is the last index before the pop removes it.\n verifiedValidatorsCount -= 1;\n\n // Move the last validator that has already been verified to the current index.\n // There's an extra SSTORE if i is the last active validator but that's fine,\n // It's not a common case and the code is simpler this way.\n verifiedValidators[i] = verifiedValidators[\n verifiedValidatorsCount\n ];\n // Delete the last validator from the list\n verifiedValidators.pop();\n }\n\n // The validator balance is zero so not need to add to totalValidatorBalance\n continue;\n } else if (\n validatorDataMem.state == ValidatorState.VERIFIED &&\n validatorBalanceGwei > MIN_ACTIVATION_BALANCE_GWEI\n ) {\n // Store the validator state as active. This does not necessarily mean the\n // validator is active on the beacon chain yet. It just means the validator has\n // enough balance that it can become active.\n validator[verifiedValidators[i]].state = ValidatorState\n .ACTIVE;\n }\n\n // convert Gwei balance to Wei and add to the total validator balance\n totalValidatorBalance += validatorBalanceGwei * 1 gwei;\n }\n }\n\n uint256 totalDepositsWei = 0;\n\n // If there are no deposits then we can skip the deposit verification.\n // This section is after the validator balance verifications so an exited validator will be marked\n // as EXITED before the deposits are verified. If there was a deposit to an exited validator\n // then the deposit can only be removed once the validator is fully exited.\n // It is possible that validator fully exits and a postponed deposit to an exited validator increases\n // its balance again. In such case the contract will erroneously consider a deposit applied before it\n // has been applied on the beacon chain showing a smaller than real `totalValidatorBalance`.\n if (depositsCount > 0) {\n require(\n pendingDepositProofs.pendingDepositProofs.length ==\n depositsCount,\n \"Invalid deposit proofs\"\n );\n require(\n pendingDepositProofs.pendingDepositIndexes.length ==\n depositsCount,\n \"Invalid deposit indexes\"\n );\n\n // Verify from the root of the pending deposit list container to the beacon block root\n IBeaconProofs(BEACON_PROOFS).verifyPendingDepositsContainer(\n balancesMem.blockRoot,\n pendingDepositProofs.pendingDepositContainerRoot,\n pendingDepositProofs.pendingDepositContainerProof\n );\n\n // For each staking strategy's deposit.\n for (uint256 i = 0; i < depositsCount; ++i) {\n bytes32 pendingDepositRoot = depositList[i];\n\n // Verify the strategy's deposit is still pending on the beacon chain.\n IBeaconProofs(BEACON_PROOFS).verifyPendingDeposit(\n pendingDepositProofs.pendingDepositContainerRoot,\n pendingDepositRoot,\n pendingDepositProofs.pendingDepositProofs[i],\n pendingDepositProofs.pendingDepositIndexes[i]\n );\n\n // Convert the deposit amount from Gwei to Wei and add to the total\n totalDepositsWei +=\n uint256(deposits[pendingDepositRoot].amountGwei) *\n 1 gwei;\n }\n }\n\n // Store the verified balance in storage\n lastVerifiedEthBalance =\n totalDepositsWei +\n totalValidatorBalance +\n balancesMem.ethBalance;\n // Reset the last snap timestamp so a new snapBalances has to be made\n snappedBalance.timestamp = 0;\n\n emit BalancesVerified(\n balancesMem.timestamp,\n totalDepositsWei,\n totalValidatorBalance,\n balancesMem.ethBalance\n );\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice get a list of all validator hashes present in the pending deposits\n /// list can have duplicate entries\n function _getPendingDepositValidatorHashes(uint256 depositsCount)\n internal\n view\n returns (bytes32[] memory validatorHashes)\n {\n validatorHashes = new bytes32[](depositsCount);\n for (uint256 i = 0; i < depositsCount; i++) {\n validatorHashes[i] = deposits[depositList[i]].pubKeyHash;\n }\n }\n\n /// @notice Hash a validator public key using the Beacon Chain's format\n function _hashPubKey(bytes memory pubKey) internal pure returns (bytes32) {\n require(pubKey.length == 48, \"Invalid public key\");\n return sha256(abi.encodePacked(pubKey, bytes16(0)));\n }\n\n /**\n *\n * WETH and ETH Accounting\n *\n */\n\n /// @dev Called when WETH is transferred out of the strategy so\n /// the strategy knows how much WETH it has on deposit.\n /// This is so it can emit the correct amount in the Deposit event in depositAll().\n function _transferWeth(uint256 _amount, address _recipient) internal {\n IERC20(WETH).safeTransfer(_recipient, _amount);\n\n // The min is required as more WETH can be withdrawn than deposited\n // as the strategy earns consensus and execution rewards.\n uint256 deductAmount = Math.min(_amount, depositedWethAccountedFor);\n depositedWethAccountedFor -= deductAmount;\n\n // No change in ETH balance so no need to snapshot the balances\n }\n\n /// @dev Converts ETH to WETH and updates the accounting.\n /// @param _ethAmount The amount of ETH in wei.\n function _convertEthToWeth(uint256 _ethAmount) internal {\n // slither-disable-next-line arbitrary-send-eth\n IWETH9(WETH).deposit{ value: _ethAmount }();\n\n depositedWethAccountedFor += _ethAmount;\n\n // Store the reduced ETH balance.\n // The ETH balance in this strategy contract can be more than the last verified ETH balance\n // due to partial withdrawals or full exits being processed by the beacon chain since the last snapBalances.\n // It can also happen from execution rewards (MEV) or ETH donations.\n lastVerifiedEthBalance -= Math.min(lastVerifiedEthBalance, _ethAmount);\n\n // The ETH balance was decreased to WETH so we need to invalidate the last balances snap.\n snappedBalance.timestamp = 0;\n }\n\n /// @dev Converts WETH to ETH and updates the accounting.\n /// @param _wethAmount The amount of WETH in wei.\n function _convertWethToEth(uint256 _wethAmount) internal {\n IWETH9(WETH).withdraw(_wethAmount);\n\n uint256 deductAmount = Math.min(_wethAmount, depositedWethAccountedFor);\n depositedWethAccountedFor -= deductAmount;\n\n // Store the increased ETH balance\n lastVerifiedEthBalance += _wethAmount;\n\n // The ETH balance was increased from WETH so we need to invalidate the last balances snap.\n snappedBalance.timestamp = 0;\n }\n\n /**\n *\n * View Functions\n *\n */\n\n /// @notice Returns the number of deposits waiting to be verified as processed on the beacon chain,\n /// or deposits that have been verified to an exiting validator and is now waiting for the\n /// validator's balance to be swept.\n function depositListLength() external view returns (uint256) {\n return depositList.length;\n }\n\n /// @notice Returns the number of verified validators.\n function verifiedValidatorsLength() external view returns (uint256) {\n return verifiedValidators.length;\n }\n}\n" + }, + "contracts/strategies/NativeStaking/ConsolidationController.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\n\nimport { CompoundingStakingSSVStrategy, CompoundingValidatorManager } from \"./CompoundingStakingSSVStrategy.sol\";\nimport { ValidatorAccountant } from \"./ValidatorAccountant.sol\";\nimport { Cluster } from \"../../interfaces/ISSVNetwork.sol\";\n\n/// @title Consolidation Controller\n/// @notice Orchestrates the consolidation of validators from old Native Staking Strategies\n/// to the new Compounding Staking Strategy.\n/// @author Origin Protocol Inc\ncontract ConsolidationController is Ownable {\n /// @dev Minimum time that must pass before a consolidation request can be processed.\n /// 261 epochs * 32 slots/epoch * 12 seconds/slot = 100224 seconds (~27.8 hours)\n /// Includes 256 epochs minimum withdrawability delay + 5 epochs from\n /// compute_activation_exit_epoch (MAX_SEED_LOOKAHEAD + 1).\n /// The actual time can be a lot longer than this depending on the number of\n /// requests in the beacon chain's pending consolidation queue.\n uint256 internal constant MIN_CONSOLIDATION_PERIOD = 261 * 32 * 12;\n\n /// @notice Address of the validator registrator account\n address public immutable validatorRegistrator;\n /// @dev The old Native Staking Strategy connected to the second SSV cluster\n address internal immutable nativeStakingStrategy2;\n /// @dev The old Native Staking Strategy connected to the third SSV cluster\n address internal immutable nativeStakingStrategy3;\n /// @dev The new Compounding Staking Strategy\n CompoundingStakingSSVStrategy internal immutable targetStrategy;\n\n /// @notice Number of validators being consolidated\n uint64 public consolidationCount;\n /// @notice Timestamp when the consolidation process was requested\n uint64 public consolidationStartTimestamp;\n /// @notice The address of the source Native Staking Strategy being consolidated from\n address public sourceStrategy;\n /// @notice The public key hash of the target validator on the new Compounding Staking Strategy\n bytes32 public targetPubKeyHash;\n /// @dev Tracks source validators that were requested for a consolidation round.\n /// Keyed by keccak256(sourcePubKeyHash, consolidationStartTimestamp).\n mapping(bytes32 => bool) private pendingSourceInRound;\n\n /// @dev Throws if called by any account other than the Validator Registrator\n modifier onlyRegistrator() {\n require(\n msg.sender == validatorRegistrator,\n \"Caller is not the Registrator\"\n );\n _;\n }\n\n /// @param _owner The owner who can request, fail and confirm consolidations\n /// @param _validatorRegistrator The validator registrator who does operations on the old staking strategy\n constructor(\n address _owner,\n address _validatorRegistrator,\n address _nativeStakingStrategy2,\n address _nativeStakingStrategy3,\n address _targetStrategy\n ) {\n _transferOwnership(_owner);\n\n validatorRegistrator = _validatorRegistrator;\n nativeStakingStrategy2 = _nativeStakingStrategy2;\n nativeStakingStrategy3 = _nativeStakingStrategy3;\n targetStrategy = CompoundingStakingSSVStrategy(\n payable(_targetStrategy)\n );\n }\n\n /**\n * @notice Request consolidation of validators from an old Native Staking Strategy\n * to the new Compounding Staking Strategy\n * @param _sourceStrategy The address of the old Native Staking Strategy\n * @param sourcePubKeys The public keys of the validators to be consolidated from the old Native Staking Strategy\n * @param targetPubKey The public key of the target validator on the new Compounding Staking Strategy\n */\n function requestConsolidation(\n address _sourceStrategy,\n bytes[] calldata sourcePubKeys,\n bytes calldata targetPubKey\n ) external payable onlyOwner {\n // Check no consolidations are already in progress\n require(consolidationCount == 0, \"Consolidation in progress\");\n // Check at least one source validator is provided\n require(sourcePubKeys.length > 0, \"Empty source validators\");\n // Check sourceStrategy is a valid old Native Staking Strategy\n _checkSourceStrategy(_sourceStrategy);\n\n // Check target validator is Active on the new Compounding Staking Strategy\n bytes32 targetPubKeyHashMem = _hashPubKey(targetPubKey);\n (CompoundingStakingSSVStrategy.ValidatorState state, ) = targetStrategy\n .validator(targetPubKeyHashMem);\n require(\n state == CompoundingValidatorManager.ValidatorState.ACTIVE,\n \"Target validator not active\"\n );\n // Check no pending deposits in the new target validator\n require(\n _hasPendingDeposit(targetPubKeyHashMem) == false,\n \"Target has pending deposit\"\n );\n\n // Store the state at the start of the consolidation process\n consolidationCount = SafeCast.toUint64(sourcePubKeys.length);\n uint64 consolidationStartTimestampMem = uint64(block.timestamp);\n consolidationStartTimestamp = consolidationStartTimestampMem;\n sourceStrategy = _sourceStrategy;\n targetPubKeyHash = targetPubKeyHashMem;\n\n // Store source validators for this consolidation round.\n for (uint256 i = 0; i < sourcePubKeys.length; ++i) {\n bytes32 roundKey = _sourceValidatorRoundKey(\n sourcePubKeys[i],\n consolidationStartTimestampMem\n );\n require(\n pendingSourceInRound[roundKey] == false,\n \"Duplicate source validator\"\n );\n pendingSourceInRound[roundKey] = true;\n }\n\n // Call requestConsolidation on the old Native Staking Strategy\n // to initiate the consolidations\n ValidatorAccountant(_sourceStrategy).requestConsolidation{\n value: msg.value\n }(sourcePubKeys, targetPubKey);\n\n // Snap the balances for the last time on the new Compounding Staking Strategy\n // if it hasn't been called recently. Otherwise skip to prevent a DoS\n // attack where an attacker front-runs this call with the permissionless snapBalances().\n (, uint64 lastSnapTimestamp, ) = targetStrategy.snappedBalance();\n if (\n uint64(block.timestamp) >\n lastSnapTimestamp + targetStrategy.SNAP_BALANCES_DELAY()\n ) {\n targetStrategy.snapBalances();\n }\n\n // No event emitted as ConsolidationRequested is emitted from the old Native Staking Strategy\n }\n\n /**\n * @notice A consolidation request can fail to be processed on the beacon chain\n * for various reasons. For example, the pending consolidation queue is full with 262,144 requests.\n * Or the source validator has exited from a voluntary exit request.\n * This reduces the consolidation count and changes the validator state back to STAKED.\n * @param sourcePubKeys The public keys of the source validators that failed to be consolidated.\n */\n function failConsolidation(bytes[] calldata sourcePubKeys)\n external\n onlyOwner\n {\n // Check consolidations are in progress\n require(consolidationCount > 0, \"No consolidation in progress\");\n // There a min time before a failed consolidation can be unwound.\n // This gives the beacon chain time to process the request.\n require(\n block.timestamp >=\n consolidationStartTimestamp + MIN_CONSOLIDATION_PERIOD,\n \"Source not withdrawable\"\n );\n require(\n sourcePubKeys.length <= consolidationCount,\n \"Exceeds consolidation count\"\n );\n uint64 consolidationStartTimestampMem = consolidationStartTimestamp;\n\n for (uint256 i = 0; i < sourcePubKeys.length; ++i) {\n bytes32 roundKey = _sourceValidatorRoundKey(\n sourcePubKeys[i],\n consolidationStartTimestampMem\n );\n require(pendingSourceInRound[roundKey], \"Unknown source validator\");\n pendingSourceInRound[roundKey] = false;\n }\n\n // Read into memory in case it gets reset in storage before\n // the external call to the source strategy\n address sourceStrategyMem = sourceStrategy;\n\n // Store updated consolidation state\n consolidationCount -= SafeCast.toUint64(sourcePubKeys.length);\n if (consolidationCount == 0) {\n // Reset the rest of the consolidation state\n consolidationStartTimestamp = 0;\n sourceStrategy = address(0);\n targetPubKeyHash = bytes32(0);\n }\n\n ValidatorAccountant(sourceStrategyMem).failConsolidation(sourcePubKeys);\n\n // No event emitted as ConsolidationFailed is emitted from the old Native Staking Strategy\n }\n\n /**\n * @notice Confirm the consolidation of validators from an old Native Staking Strategy\n * to the new Compounding Staking Strategy has been completed.\n * @param balanceProofs a `BalanceProofs` struct containing the following:\n * - balancesContainerRoot: The merkle root of the balances container\n * - balancesContainerProof: The merkle proof for the balances container to the beacon block root.\n * This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * - validatorBalanceLeaves: Array of leaf nodes containing the validator balance with three other balances.\n * - validatorBalanceProofs: Array of merkle proofs for the validator balance to the Balances container root.\n * This is 39 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * @param pendingDepositProofs a `PendingDepositProofs` struct containing the following:\n * - pendingDepositContainerRoot: The merkle root of the pending deposits list container\n * - pendingDepositContainerProof: The merkle proof from the pending deposits list container\n * to the beacon block root.\n * This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * - pendingDepositIndexes: Array of indexes in the pending deposits list container for each\n * of the strategy's deposits.\n * - pendingDepositProofs: Array of merkle proofs for each strategy deposit in the\n * beacon chain's pending deposit list container to the pending deposits list container root.\n * These are 28 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n */\n function confirmConsolidation(\n CompoundingValidatorManager.BalanceProofs calldata balanceProofs,\n CompoundingValidatorManager.PendingDepositProofs\n calldata pendingDepositProofs\n ) external onlyOwner {\n // Check consolidations are in progress\n require(consolidationCount > 0, \"No consolidation in progress\");\n // There a min time before a consolidation can be processed on the beacon chain\n (, uint64 snappedTimestamp, ) = targetStrategy.snappedBalance();\n require(\n uint64(snappedTimestamp) >\n consolidationStartTimestamp + MIN_CONSOLIDATION_PERIOD,\n \"Source not withdrawable\"\n );\n\n // Load into memory as the storage is about to be reset.\n // These are used in the external contract calls\n address sourceStrategyMem = sourceStrategy;\n uint256 consolidationCountMem = consolidationCount;\n\n // Reset consolidation state before external calls\n consolidationCount = 0;\n consolidationStartTimestamp = 0;\n sourceStrategy = address(0);\n targetPubKeyHash = bytes32(0);\n\n // Verify balances on the new Compounding Staking Strategy and update the strategy's balance\n targetStrategy.verifyBalances(balanceProofs, pendingDepositProofs);\n\n // Reduce the balance of the old Native Staking Strategy\n ValidatorAccountant(sourceStrategyMem).confirmConsolidation(\n consolidationCountMem\n );\n\n // No event emitted as ConsolidationConfirmed is emitted from the old Native Staking Strategy\n }\n\n /**\n *\n * Functions that forward to the old Native Staking Strategy\n *\n */\n\n /// @notice The validator registrator of the old Native Staking Strategy can call doAccounting\n /// @param _sourceStrategy The address of the old Native Staking Strategy\n /// @return accountingValid true if accounting was successful, false if fuse is blown\n function doAccounting(address _sourceStrategy)\n external\n onlyRegistrator\n returns (bool accountingValid)\n {\n // Check sourceStrategy is a valid old Native Staking Strategy\n _checkSourceStrategy(_sourceStrategy);\n\n return ValidatorAccountant(_sourceStrategy).doAccounting();\n }\n\n /**\n * @notice Exit of source validators are allowed during the consolidation process\n * as consolidated validators will be in EXITING state hence can not be consolidated after exit.\n * Only callable by the validator registrator.\n * @param _sourceStrategy The address of the old Native Staking Strategy\n * @param publicKey The public key of the validator to exit which must have STAKED state.\n * @param operatorIds The operator IDs for the source SSV cluster\n */\n function exitSsvValidator(\n address _sourceStrategy,\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external onlyRegistrator {\n // Check sourceStrategy is a valid old Native Staking Strategy\n _checkSourceStrategy(_sourceStrategy);\n\n ValidatorAccountant(_sourceStrategy).exitSsvValidator(\n publicKey,\n operatorIds\n );\n }\n\n /**\n * @notice Removing source validators is not allowed during the consolidation process\n * as consolidated validators will be in EXITING state hence can not be consolidated after removal.\n * Only callable by the validator registrator.\n * @param _sourceStrategy The address of the old Native Staking Strategy\n * @param publicKey The public key of the validator to remove which must have EXITING or REGISTERED state.\n * @param operatorIds The operator IDs for the source SSV cluster\n * @param cluster The SSV cluster information for the source validator\n */\n function removeSsvValidator(\n address _sourceStrategy,\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator {\n // Check sourceStrategy is a valid old Native Staking Strategy\n _checkSourceStrategy(_sourceStrategy);\n // Prevent removing a validator from the SSV cluster before the consolidation\n // process has been completed for the source strategy being consolidated.\n // This prevents validators that have been exited rather than consolidated but that's ok.\n // The exited validator can be removed after the consolidation process is complete.\n require(_sourceStrategy != sourceStrategy, \"Consolidation in progress\");\n\n ValidatorAccountant(_sourceStrategy).removeSsvValidator(\n publicKey,\n operatorIds,\n cluster\n );\n }\n\n /**\n *\n * Functions that forward to the new Compounding Staking Strategy\n *\n */\n\n /// @notice Forwards to the new Compounding Staking Strategy.\n /// Is only callable by the validator registrator when a consolidation is in progress.\n /// Anyone can call when there are no consolidations in progress.\n function snapBalances() external {\n if (consolidationCount > 0 && msg.sender != validatorRegistrator) {\n revert(\"Consolidation in progress\");\n }\n if (consolidationCount > 0) {\n require(\n block.timestamp >\n consolidationStartTimestamp + MIN_CONSOLIDATION_PERIOD,\n \"Source not withdrawable\"\n );\n }\n\n targetStrategy.snapBalances();\n }\n\n /**\n * @notice Anyone can verify balances on the new Compounding Staking Strategy\n * as long as there are no consolidations in progress.\n * @param balanceProofs a `BalanceProofs` struct containing the following:\n * - balancesContainerRoot: The merkle root of the balances container\n * - balancesContainerProof: The merkle proof for the balances container to the beacon block root.\n * This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * - validatorBalanceLeaves: Array of leaf nodes containing the validator balance with three other balances.\n * - validatorBalanceProofs: Array of merkle proofs for the validator balance to the Balances container root.\n * This is 39 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * @param pendingDepositProofs a `PendingDepositProofs` struct containing the following:\n * - pendingDepositContainerRoot: The merkle root of the pending deposits list container\n * - pendingDepositContainerProof: The merkle proof from the pending deposits list container\n * to the beacon block root.\n * This is 9 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n * - pendingDepositIndexes: Array of indexes in the pending deposits list container for each\n * of the strategy's deposits.\n * - pendingDepositProofs: Array of merkle proofs for each strategy deposit in the\n * beacon chain's pending deposit list container to the pending deposits list container root.\n * These are 28 witness hashes of 32 bytes each concatenated together starting from the leaf node.\n */\n function verifyBalances(\n CompoundingValidatorManager.BalanceProofs calldata balanceProofs,\n CompoundingValidatorManager.PendingDepositProofs\n calldata pendingDepositProofs\n ) external {\n (, uint64 snappedTimestamp, ) = targetStrategy.snappedBalance();\n // Can not verify balances while consolidations are in progress\n // if the snap was taken after the consolidation process started.\n // This still allows verifying a pre-existing snap.\n if (\n consolidationCount > 0 &&\n snappedTimestamp > consolidationStartTimestamp\n ) {\n revert(\"Consolidation in progress\");\n }\n\n targetStrategy.verifyBalances(balanceProofs, pendingDepositProofs);\n }\n\n /// @notice Partial withdrawals are allowed during consolidation from the new Compounding Staking Strategy.\n /// This includes partial withdrawals from the target validator.\n // Full validator exits from any Compounding Staking Strategy validator are\n /// not allowed during the migration period.\n /// Only the registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param amountGwei The amount of ETH to be withdrawn from the validator in Gwei.\n /// A zero amount is not allowed.\n function validatorWithdrawal(bytes calldata publicKey, uint64 amountGwei)\n external\n payable\n onlyRegistrator\n {\n // Prevent full exits from any new compounding validators.\n // This includes when there is no consolidation in progress.\n // This reduces the risk of an exit request being processed before a consolidation request\n require(amountGwei > 0, \"No exit during migration\");\n targetStrategy.validatorWithdrawal{ value: msg.value }(\n publicKey,\n amountGwei\n );\n }\n\n /**\n * @notice Deposits to Compounding Staking Strategy validators that are\n * not the target of a consolidation are allowed.\n * Only the registrator can call this function.\n * @param validatorStakeData validator data needed to stake.\n * The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot.\n * @param depositAmountGwei The amount of WETH to stake to the validator in Gwei.\n */\n function stakeEth(\n CompoundingValidatorManager.ValidatorStakeData\n calldata validatorStakeData,\n uint64 depositAmountGwei\n ) external onlyRegistrator {\n require(\n _hashPubKey(validatorStakeData.pubkey) != targetPubKeyHash,\n \"Stake to consolidation target\"\n );\n\n targetStrategy.stakeEth(validatorStakeData, depositAmountGwei);\n }\n\n /// removeSsvValidator from the new Compounding Staking Strategy is not allowed until after\n /// all the validators have been consolidated. This is done by restoring the validator registrator\n /// back to the account used before the consolidation upgrades.\n\n /**\n *\n * Internal Functions\n *\n */\n\n /// @dev Check if there are any pending deposits for a validator with a given public key hash.\n /// Need to iterate over the target strategy’s `deposits`\n /// @return True if there is at least one pending deposit for the validator\n function _hasPendingDeposit(bytes32 _targetPubKeyHash)\n internal\n view\n returns (bool)\n {\n uint256 depositsCount = targetStrategy.depositListLength();\n for (uint256 i = 0; i < depositsCount; ++i) {\n (\n bytes32 depositPubKeyHash,\n ,\n ,\n ,\n CompoundingValidatorManager.DepositStatus status\n ) = targetStrategy.deposits(targetStrategy.depositList(i));\n if (\n depositPubKeyHash == _targetPubKeyHash &&\n status == CompoundingValidatorManager.DepositStatus.PENDING\n ) {\n return true;\n }\n }\n return false;\n }\n\n /// @dev Hash a validator public key using the Beacon Chain's format\n /// @param pubKey The full validator public key\n /// @return The hashed public key using the Beacon Chain's hashing for BLSPubkey\n function _hashPubKey(bytes memory pubKey) internal pure returns (bytes32) {\n require(pubKey.length == 48, \"Invalid public key\");\n return sha256(abi.encodePacked(pubKey, bytes16(0)));\n }\n\n /// @dev Build a key for tracking source validators in a consolidation round.\n function _sourceValidatorRoundKey(\n bytes memory sourcePubKey,\n uint64 roundTimestamp\n ) internal pure returns (bytes32) {\n return keccak256(abi.encode(_hashPubKey(sourcePubKey), roundTimestamp));\n }\n\n /// @dev Check source strategy is a valid old Native Staking Strategy\n /// @param _sourceStrategy The address of the old Native Staking Strategy\n function _checkSourceStrategy(address _sourceStrategy) internal view {\n require(\n _sourceStrategy == nativeStakingStrategy2 ||\n _sourceStrategy == nativeStakingStrategy3,\n \"Invalid source strategy\"\n );\n }\n}\n" + }, + "contracts/strategies/NativeStaking/FeeAccumulator.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\n/**\n * @title Fee Accumulator for Native Staking SSV Strategy\n * @notice Receives execution rewards which includes tx fees and\n * MEV rewards like tx priority and tx ordering.\n * It does NOT include swept ETH from beacon chain consensus rewards or full validator withdrawals.\n * @author Origin Protocol Inc\n */\ncontract FeeAccumulator {\n /// @notice The address of the Native Staking Strategy\n address public immutable STRATEGY;\n\n event ExecutionRewardsCollected(address indexed strategy, uint256 amount);\n\n /**\n * @param _strategy Address of the Native Staking Strategy\n */\n constructor(address _strategy) {\n STRATEGY = _strategy;\n }\n\n /**\n * @notice sends all ETH in this FeeAccumulator contract to the Native Staking Strategy.\n * @return eth The amount of execution rewards that were sent to the Native Staking Strategy\n */\n function collect() external returns (uint256 eth) {\n require(msg.sender == STRATEGY, \"Caller is not the Strategy\");\n\n eth = address(this).balance;\n if (eth > 0) {\n // Send the ETH to the Native Staking Strategy\n Address.sendValue(payable(STRATEGY), eth);\n\n emit ExecutionRewardsCollected(STRATEGY, eth);\n }\n }\n\n /**\n * @dev Accept ETH\n */\n receive() external payable {}\n}\n" + }, + "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { FeeAccumulator } from \"./FeeAccumulator.sol\";\nimport { ValidatorAccountant } from \"./ValidatorAccountant.sol\";\nimport { ISSVNetwork } from \"../../interfaces/ISSVNetwork.sol\";\n\nstruct ValidatorStakeData {\n bytes pubkey;\n bytes signature;\n bytes32 depositDataRoot;\n}\n\n/// @title Native Staking SSV Strategy\n/// @notice Strategy to deploy funds into DVT validators powered by the SSV Network\n/// @author Origin Protocol Inc\n/// @dev This contract handles WETH and ETH and in some operations interchanges between the two. Any WETH that\n/// is on the contract across multiple blocks (and not just transitory within a transaction) is considered an\n/// asset. Meaning deposits increase the balance of the asset and withdrawal decrease it. As opposed to all\n/// our other strategies the WETH doesn't immediately get deposited into an underlying strategy and can be present\n/// across multiple blocks waiting to be unwrapped to ETH and staked to validators. This separation of WETH and ETH is\n/// required since the rewards (reward token) is also in ETH.\n///\n/// To simplify the accounting of WETH there is another difference in behavior compared to the other strategies.\n/// To withdraw WETH asset - exit message is posted to validators and the ETH hits this contract with multiple days\n/// delay. In order to simplify the WETH accounting upon detection of such an event the ValidatorAccountant\n/// immediately wraps ETH to WETH and sends it to the Vault.\n///\n/// On the other hand any ETH on the contract (across multiple blocks) is there either:\n/// - as a result of already accounted for consensus rewards\n/// - as a result of not yet accounted for consensus rewards\n/// - as a results of not yet accounted for full validator withdrawals (or validator slashes)\n///\n/// Even though the strategy assets and rewards are a very similar asset the consensus layer rewards and the\n/// execution layer rewards are considered rewards and those are dripped to the Vault over a configurable time\n/// interval and not immediately.\ncontract NativeStakingSSVStrategy is\n ValidatorAccountant,\n InitializableAbstractStrategy\n{\n using SafeERC20 for IERC20;\n\n /// @notice SSV ERC20 token that serves as a payment for operating SSV validators\n address public immutable SSV_TOKEN;\n /// @notice Fee collector address\n /// @dev this address will receive maximal extractable value (MEV) rewards. These are\n /// rewards for arranging transactions in a way that benefits the validator.\n address payable public immutable FEE_ACCUMULATOR_ADDRESS;\n\n /// @dev This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately\n /// deposit it to an underlying platform. Rather a special privilege account stakes it to the validators.\n /// For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been\n /// deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track\n /// of WETH that has already been accounted for.\n /// This value represents the amount of WETH balance of this contract that has already been accounted for by the\n /// deposit events.\n /// It is important to note that this variable is not concerned with WETH that is a result of full/partial\n /// withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to\n /// be staked.\n uint256 public depositedWethAccountedFor;\n\n // For future use\n uint256[49] private __gap;\n\n /// @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI,\n /// and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _ssvToken Address of the Erc20 SSV Token contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _maxValidators Maximum number of validators that can be registered in the strategy\n /// @param _feeAccumulator Address of the fee accumulator receiving execution layer validator rewards\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _wethAddress,\n address _ssvToken,\n address _ssvNetwork,\n uint256 _maxValidators,\n address _feeAccumulator,\n address _beaconChainDepositContract\n )\n InitializableAbstractStrategy(_baseConfig)\n ValidatorAccountant(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork,\n _maxValidators\n )\n {\n SSV_TOKEN = _ssvToken;\n FEE_ACCUMULATOR_ADDRESS = payable(_feeAccumulator);\n }\n\n /// @notice Set up initial internal state including\n /// 1. approving the SSVNetwork to transfer SSV tokens from this strategy contract\n /// 2. setting the recipient of SSV validator MEV rewards to the FeeAccumulator contract.\n /// @param _rewardTokenAddresses Address of reward token for platform\n /// @param _assets Addresses of initial supported assets\n /// @param _pTokens Platform Token corresponding addresses\n function initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n\n // Approves the SSV Network contract to transfer SSV tokens for deposits\n IERC20(SSV_TOKEN).approve(SSV_NETWORK, type(uint256).max);\n\n // Set the FeeAccumulator as the address for SSV validators to send MEV rewards to\n ISSVNetwork(SSV_NETWORK).setFeeRecipientAddress(\n FEE_ACCUMULATOR_ADDRESS\n );\n }\n\n /// @notice Unlike other strategies, this does not deposit assets into the underlying platform.\n /// It just checks the asset is WETH and emits the Deposit event.\n /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used.\n /// Will NOT revert if the strategy is paused from an accounting failure.\n /// @param _asset Address of asset to deposit. Has to be WETH.\n /// @param _amount Amount of assets that were transferred to the strategy by the vault.\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n require(_asset == WETH, \"Unsupported asset\");\n depositedWethAccountedFor += _amount;\n _deposit(_asset, _amount);\n }\n\n /// @dev Deposit WETH to this strategy so it can later be staked into a validator.\n /// @param _asset Address of WETH\n /// @param _amount Amount of WETH to deposit\n function _deposit(address _asset, uint256 _amount) internal {\n require(_amount > 0, \"Must deposit something\");\n /*\n * We could do a check here that would revert when \"_amount % 32 ether != 0\". With the idea of\n * not allowing deposits that will result in WETH sitting on the strategy after all the possible batches\n * of 32ETH have been staked.\n * But someone could mess with our strategy by sending some WETH to it. And we might want to deposit just\n * enough WETH to add it up to 32 so it can be staked. For that reason the check is left out.\n *\n * WETH sitting on the strategy won't interfere with the accounting since accounting only operates on ETH.\n */\n emit Deposit(_asset, address(0), _amount);\n }\n\n /// @notice Unlike other strategies, this does not deposit assets into the underlying platform.\n /// It just emits the Deposit event.\n /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used.\n /// Will NOT revert if the strategy is paused from an accounting failure.\n function depositAll() external override onlyVault nonReentrant {\n uint256 wethBalance = IERC20(WETH).balanceOf(address(this));\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\n\n if (newWeth > 0) {\n depositedWethAccountedFor = wethBalance;\n\n _deposit(WETH, newWeth);\n }\n }\n\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract.\n /// That can happen when:\n /// - after mints if the strategy is the default\n /// - time between depositToStrategy and stakeEth\n /// - the deposit was not a multiple of 32 WETH\n /// - someone sent WETH directly to this contract\n /// Will NOT revert if the strategy is paused from an accounting failure.\n /// @param _recipient Address to receive withdrawn assets\n /// @param _asset WETH to withdraw\n /// @param _amount Amount of WETH to withdraw\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_asset == WETH, \"Unsupported asset\");\n _withdraw(_recipient, _asset, _amount);\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n _wethWithdrawn(_amount);\n\n IERC20(_asset).safeTransfer(_recipient, _amount);\n emit Withdrawal(_asset, address(0), _amount);\n }\n\n /// @notice transfer all WETH deposits back to the vault.\n /// This does not withdraw from the validators. That has to be done separately with the\n /// `exitSsvValidator` and `removeSsvValidator` operations.\n /// This does not withdraw any execution rewards from the FeeAccumulator or\n /// consensus rewards in this strategy.\n /// Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn.\n /// ETH from full validator withdrawals is sent to the Vault using `doAccounting`.\n /// Will NOT revert if the strategy is paused from an accounting failure.\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 wethBalance = IERC20(WETH).balanceOf(address(this));\n if (wethBalance > 0) {\n _withdraw(vaultAddress, WETH, wethBalance);\n }\n }\n\n /// @notice Returns the total value of (W)ETH that is staked to the validators\n /// and WETH deposits that are still to be staked.\n /// This does not include ETH from consensus rewards sitting in this strategy\n /// or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested\n /// and sent to the Dripper so will eventually be sent to the Vault as WETH.\n /// @param _asset Address of weth asset\n /// @return balance Total value of (W)ETH\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == WETH, \"Unsupported asset\");\n\n balance =\n // add the ETH that has been staked in validators\n activeDepositedValidators *\n FULL_STAKE +\n // add the WETH in the strategy from deposits that are still to be staked\n IERC20(WETH).balanceOf(address(this));\n }\n\n function pause() external onlyStrategist {\n _pause();\n }\n\n /// @notice Returns bool indicating whether asset is supported by strategy.\n /// @param _asset The address of the asset token.\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == WETH;\n }\n\n /// @notice Approves the SSV Network contract to transfer SSV tokens for deposits\n function safeApproveAllTokens() external override {\n // Approves the SSV Network contract to transfer SSV tokens for deposits\n IERC20(SSV_TOKEN).approve(SSV_NETWORK, type(uint256).max);\n }\n\n /// @notice Set the FeeAccumulator as the address for SSV validators to send MEV rewards to\n function setFeeRecipient() external {\n ISSVNetwork(SSV_NETWORK).setFeeRecipientAddress(\n FEE_ACCUMULATOR_ADDRESS\n );\n }\n\n /**\n * @notice Only accept ETH from the FeeAccumulator and the WETH contract - required when\n * unwrapping WETH just before staking it to the validator.\n * The strategy will also receive ETH from the priority fees of transactions when producing blocks\n * as defined in EIP-1559.\n * The tx fees come from the Beacon chain so do not need any EVM level permissions to receive ETH.\n * The tx fees are paid with each block produced. They are not included in the consensus rewards\n * which are periodically swept from the validators to this strategy.\n * For accounting purposes, the priority fees of transactions will be considered consensus rewards\n * and will be included in the AccountingConsensusRewards event.\n * @dev don't want to receive donations from anyone else as donations over the fuse limits will\n * mess with the accounting of the consensus rewards and validator full withdrawals.\n */\n receive() external payable {\n require(\n msg.sender == FEE_ACCUMULATOR_ADDRESS || msg.sender == WETH,\n \"Eth not from allowed contracts\"\n );\n }\n\n /***************************************\n Internal functions\n ****************************************/\n\n function _abstractSetPToken(address _asset, address) internal override {}\n\n /// @dev Convert accumulated ETH to WETH and send to the Harvester.\n /// Will revert if the strategy is paused for accounting.\n function _collectRewardTokens() internal override whenNotPaused {\n // collect ETH from execution rewards from the fee accumulator\n uint256 executionRewards = FeeAccumulator(FEE_ACCUMULATOR_ADDRESS)\n .collect();\n\n // total ETH rewards to be harvested = execution rewards + consensus rewards\n uint256 ethRewards = executionRewards + consensusRewards;\n\n require(\n address(this).balance >= ethRewards,\n \"Insufficient eth balance\"\n );\n\n if (ethRewards > 0) {\n // reset the counter keeping track of beacon chain consensus rewards\n consensusRewards = 0;\n\n // Convert ETH rewards to WETH\n IWETH9(WETH).deposit{ value: ethRewards }();\n\n IERC20(WETH).safeTransfer(harvesterAddress, ethRewards);\n emit RewardTokenCollected(harvesterAddress, WETH, ethRewards);\n }\n }\n\n /// @dev emits Withdrawal event from NativeStakingSSVStrategy\n function _wethWithdrawnToVault(uint256 _amount) internal override {\n emit Withdrawal(WETH, address(0), _amount);\n }\n\n /// @dev Called when WETH is withdrawn from the strategy or staked to a validator so\n /// the strategy knows how much WETH it has on deposit.\n /// This is so it can emit the correct amount in the Deposit event in depositAll().\n function _wethWithdrawn(uint256 _amount) internal override {\n /* In an ideal world we wouldn't need to reduce the deduction amount when the\n * depositedWethAccountedFor is smaller than the _amount.\n *\n * The reason this is required is that a malicious actor could sent WETH directly\n * to this contract and that would circumvent the increase of depositedWethAccountedFor\n * property. When the ETH would be staked the depositedWethAccountedFor amount could\n * be deducted so much that it would be negative.\n */\n uint256 deductAmount = Math.min(_amount, depositedWethAccountedFor);\n depositedWethAccountedFor -= deductAmount;\n }\n}\n" + }, + "contracts/strategies/NativeStaking/ValidatorAccountant.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ValidatorRegistrator } from \"./ValidatorRegistrator.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\n\n/// @title Validator Accountant\n/// @notice Attributes the ETH swept from beacon chain validators to this strategy contract\n/// as either full or partial withdrawals. Partial withdrawals being consensus rewards.\n/// Full withdrawals are from exited validators.\n/// @author Origin Protocol Inc\nabstract contract ValidatorAccountant is ValidatorRegistrator {\n /// @notice The minimum amount of blocks that need to pass between two calls to manuallyFixAccounting\n uint256 public constant MIN_FIX_ACCOUNTING_CADENCE = 7200; // 1 day\n\n /// @notice Keeps track of the total consensus rewards swept from the beacon chain\n uint256 public consensusRewards;\n\n /// @notice start of fuse interval\n uint256 public fuseIntervalStart;\n /// @notice end of fuse interval\n uint256 public fuseIntervalEnd;\n /// @notice last block number manuallyFixAccounting has been called\n uint256 public lastFixAccountingBlockNumber;\n\n uint256[49] private __gap;\n\n event FuseIntervalUpdated(uint256 start, uint256 end);\n event AccountingFullyWithdrawnValidator(\n uint256 noOfValidators,\n uint256 remainingValidators,\n uint256 wethSentToVault\n );\n event AccountingValidatorSlashed(\n uint256 remainingValidators,\n uint256 wethSentToVault\n );\n event AccountingConsensusRewards(uint256 amount);\n\n event AccountingManuallyFixed(\n int256 validatorsDelta,\n int256 consensusRewardsDelta,\n uint256 wethToVault\n );\n\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _vaultAddress Address of the Vault\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _maxValidators Maximum number of validators that can be registered in the strategy\n constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork,\n uint256 _maxValidators\n )\n ValidatorRegistrator(\n _wethAddress,\n _vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork,\n _maxValidators\n )\n {}\n\n /// @notice set fuse interval values\n function setFuseInterval(\n uint256 _fuseIntervalStart,\n uint256 _fuseIntervalEnd\n ) external onlyGovernor {\n require(\n _fuseIntervalStart < _fuseIntervalEnd &&\n _fuseIntervalEnd < 32 ether &&\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\n \"Incorrect fuse interval\"\n );\n\n fuseIntervalStart = _fuseIntervalStart;\n fuseIntervalEnd = _fuseIntervalEnd;\n\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\n }\n\n /* solhint-disable max-line-length */\n /// This notion page offers a good explanation of how the accounting functions\n /// https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d\n /// In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart,\n /// the accounting function will treat that ETH as Beacon chain consensus rewards.\n /// On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32,\n /// the accounting function will treat that as a validator slashing.\n /// @notice Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when\n /// accounting is valid and fuse isn't \"blown\". Returns false when fuse is blown.\n /// @dev This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it\n /// for now.\n /// @return accountingValid true if accounting was successful, false if fuse is blown\n /* solhint-enable max-line-length */\n function doAccounting()\n external\n onlyRegistrator\n whenNotPaused\n nonReentrant\n returns (bool accountingValid)\n {\n // pause the accounting on failure\n accountingValid = _doAccounting(true);\n }\n\n // slither-disable-start reentrancy-eth\n function _doAccounting(bool pauseOnFail)\n internal\n returns (bool accountingValid)\n {\n if (address(this).balance < consensusRewards) {\n return _failAccounting(pauseOnFail);\n }\n\n // Calculate all the new ETH that has been swept to the contract since the last accounting\n uint256 newSweptETH = address(this).balance - consensusRewards;\n accountingValid = true;\n\n // send the ETH that is from fully withdrawn validators to the Vault\n if (newSweptETH >= FULL_STAKE) {\n uint256 fullyWithdrawnValidators;\n // explicitly cast to uint256 as we want to round to a whole number of validators\n fullyWithdrawnValidators = uint256(newSweptETH / FULL_STAKE);\n activeDepositedValidators -= fullyWithdrawnValidators;\n\n uint256 wethToVault = FULL_STAKE * fullyWithdrawnValidators;\n IWETH9(WETH).deposit{ value: wethToVault }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH).transfer(VAULT_ADDRESS, wethToVault);\n _wethWithdrawnToVault(wethToVault);\n\n emit AccountingFullyWithdrawnValidator(\n fullyWithdrawnValidators,\n activeDepositedValidators,\n wethToVault\n );\n }\n\n uint256 ethRemaining = address(this).balance - consensusRewards;\n // should be less than a whole validator stake\n require(ethRemaining < FULL_STAKE, \"Unexpected accounting\");\n\n // If no Beacon chain consensus rewards swept\n if (ethRemaining == 0) {\n // do nothing\n return accountingValid;\n } else if (ethRemaining < fuseIntervalStart) {\n // Beacon chain consensus rewards swept (partial validator withdrawals)\n // solhint-disable-next-line reentrancy\n consensusRewards += ethRemaining;\n emit AccountingConsensusRewards(ethRemaining);\n } else if (ethRemaining > fuseIntervalEnd) {\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\n IWETH9(WETH).deposit{ value: ethRemaining }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH).transfer(VAULT_ADDRESS, ethRemaining);\n activeDepositedValidators -= 1;\n\n _wethWithdrawnToVault(ethRemaining);\n\n emit AccountingValidatorSlashed(\n activeDepositedValidators,\n ethRemaining\n );\n }\n // Oh no... Fuse is blown. The Strategist needs to adjust the accounting values.\n else {\n return _failAccounting(pauseOnFail);\n }\n }\n\n // slither-disable-end reentrancy-eth\n\n /// @dev pause any further accounting if required and return false\n function _failAccounting(bool pauseOnFail)\n internal\n returns (bool accountingValid)\n {\n // pause if not already\n if (pauseOnFail) {\n _pause();\n }\n // fail the accounting\n accountingValid = false;\n }\n\n /// @notice Allow the Strategist to fix the accounting of this strategy and unpause.\n /// @param _validatorsDelta adjust the active validators by up to plus three or minus three\n /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down\n /// @param _ethToVaultAmount the amount of ETH that gets wrapped into WETH and sent to the Vault\n /// @dev There is a case when a validator(s) gets slashed so much that the eth swept from\n /// the beacon chain enters the fuse area and there are no consensus rewards on the contract\n /// to \"dip into\"/use. To increase the amount of unaccounted ETH over the fuse end interval\n /// we need to reduce the amount of active deposited validators and immediately send WETH\n /// to the vault, so it doesn't interfere with further accounting.\n function manuallyFixAccounting(\n int256 _validatorsDelta,\n int256 _consensusRewardsDelta,\n uint256 _ethToVaultAmount\n ) external onlyStrategist whenPaused nonReentrant {\n require(\n lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE <\n block.number,\n \"Fix accounting called too soon\"\n );\n require(\n _validatorsDelta >= -3 &&\n _validatorsDelta <= 3 &&\n // new value must be positive\n int256(activeDepositedValidators) + _validatorsDelta >= 0,\n \"Invalid validatorsDelta\"\n );\n require(\n _consensusRewardsDelta >= -332 ether &&\n _consensusRewardsDelta <= 332 ether &&\n // new value must be positive\n int256(consensusRewards) + _consensusRewardsDelta >= 0,\n \"Invalid consensusRewardsDelta\"\n );\n require(_ethToVaultAmount <= 32 ether * 3, \"Invalid wethToVaultAmount\");\n\n activeDepositedValidators = uint256(\n int256(activeDepositedValidators) + _validatorsDelta\n );\n consensusRewards = uint256(\n int256(consensusRewards) + _consensusRewardsDelta\n );\n lastFixAccountingBlockNumber = block.number;\n if (_ethToVaultAmount > 0) {\n IWETH9(WETH).deposit{ value: _ethToVaultAmount }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH).transfer(VAULT_ADDRESS, _ethToVaultAmount);\n _wethWithdrawnToVault(_ethToVaultAmount);\n }\n\n emit AccountingManuallyFixed(\n _validatorsDelta,\n _consensusRewardsDelta,\n _ethToVaultAmount\n );\n\n // rerun the accounting to see if it has now been fixed.\n // Do not pause the accounting on failure as it is already paused\n require(_doAccounting(false), \"Fuse still blown\");\n\n // unpause since doAccounting was successful\n _unpause();\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n /// @dev allows for NativeStakingSSVStrategy contract to emit the Withdrawal event\n function _wethWithdrawnToVault(uint256 _amount) internal virtual;\n}\n" + }, + "contracts/strategies/NativeStaking/ValidatorRegistrator.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { Governable } from \"../../governance/Governable.sol\";\nimport { IDepositContract } from \"../../interfaces/IDepositContract.sol\";\nimport { IVault } from \"../../interfaces/IVault.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { ISSVNetwork, Cluster } from \"../../interfaces/ISSVNetwork.sol\";\nimport { BeaconConsolidation } from \"../../beacon/BeaconConsolidation.sol\";\n\nstruct ValidatorStakeData {\n bytes pubkey;\n bytes signature;\n bytes32 depositDataRoot;\n}\n\n/**\n * @title Registrator of the validators\n * @notice This contract implements all the required functionality to register, exit and remove validators.\n * @author Origin Protocol Inc\n */\nabstract contract ValidatorRegistrator is Governable, Pausable {\n /// @notice The maximum amount of ETH that can be staked by a validator\n /// @dev this can change in the future with EIP-7251, Increase the MAX_EFFECTIVE_BALANCE\n uint256 public constant FULL_STAKE = 32 ether;\n\n /// @notice The address of the Wrapped ETH (WETH) token contract\n address public immutable WETH;\n /// @notice The address of the beacon chain deposit contract\n address public immutable BEACON_CHAIN_DEPOSIT_CONTRACT;\n /// @notice The address of the SSV Network contract used to interface with\n address public immutable SSV_NETWORK;\n /// @notice Address of the OETH Vault proxy contract\n address public immutable VAULT_ADDRESS;\n /// @notice Maximum number of validators that can be registered in this strategy\n uint256 public immutable MAX_VALIDATORS;\n\n /// @notice Address of the registrator - allowed to register, exit and remove validators\n address public validatorRegistrator;\n /// @notice The number of validators that have 32 (!) ETH actively deposited. When a new deposit\n /// to a validator happens this number increases, when a validator exit is detected this number\n /// decreases.\n uint256 public activeDepositedValidators;\n /// @notice State of the validators keccak256(pubKey) => state\n mapping(bytes32 => VALIDATOR_STATE) public validatorsStates;\n /// @notice The account that is allowed to reset stakeETHTally\n address public stakingMonitor;\n /// @notice Amount of ETH that can be staked before staking on the contract is suspended\n /// and the `stakingMonitor` needs to approve further staking by calling `resetStakeETHTally`\n uint256 public stakeETHThreshold;\n /// @notice Amount of ETH that has been staked since the `stakingMonitor` last called `resetStakeETHTally`.\n /// This can not go above `stakeETHThreshold`.\n uint256 public stakeETHTally;\n // For future use\n uint256[47] private __gap;\n\n enum VALIDATOR_STATE {\n NON_REGISTERED, // validator is not registered on the SSV network\n REGISTERED, // validator is registered on the SSV network\n STAKED, // validator has funds staked\n EXITING, // exit message has been posted and validator is in the process of exiting\n EXIT_COMPLETE // validator has funds withdrawn to the EigenPod and is removed from the SSV\n }\n\n event RegistratorChanged(address indexed newAddress);\n event StakingMonitorChanged(address indexed newAddress);\n event ETHStaked(bytes32 indexed pubKeyHash, bytes pubKey, uint256 amount);\n event SSVValidatorRegistered(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint64[] operatorIds\n );\n event SSVValidatorExitInitiated(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint64[] operatorIds\n );\n event SSVValidatorExitCompleted(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint64[] operatorIds\n );\n event ConsolidationRequested(\n bytes[] sourcePubKeys,\n bytes targetPubKey,\n uint256 consolidationCount\n );\n event ConsolidationFailed(\n bytes[] sourcePubKeys,\n uint256 consolidationCount\n );\n event ConsolidationConfirmed(\n uint256 consolidationCount,\n uint256 activeDepositedValidators\n );\n event StakeETHThresholdChanged(uint256 amount);\n event StakeETHTallyReset();\n\n /// @dev Throws if called by any account other than the Registrator\n modifier onlyRegistrator() {\n require(\n msg.sender == validatorRegistrator,\n \"Caller is not the Registrator\"\n );\n _;\n }\n\n /// @dev Throws if called by any account other than the Staking monitor\n modifier onlyStakingMonitor() {\n require(msg.sender == stakingMonitor, \"Caller is not the Monitor\");\n _;\n }\n\n /// @dev Throws if called by any account other than the Strategist\n modifier onlyStrategist() {\n require(\n msg.sender == IVault(VAULT_ADDRESS).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n _;\n }\n\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _vaultAddress Address of the Vault\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _maxValidators Maximum number of validators that can be registered in the strategy\n constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork,\n uint256 _maxValidators\n ) {\n WETH = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK = _ssvNetwork;\n VAULT_ADDRESS = _vaultAddress;\n MAX_VALIDATORS = _maxValidators;\n }\n\n /// @notice Set the address of the registrator which can register, exit and remove validators\n function setRegistrator(address _address) external onlyGovernor {\n validatorRegistrator = _address;\n emit RegistratorChanged(_address);\n }\n\n /// @notice Set the address of the staking monitor that is allowed to reset stakeETHTally\n function setStakingMonitor(address _address) external onlyGovernor {\n stakingMonitor = _address;\n emit StakingMonitorChanged(_address);\n }\n\n /// @notice Set the amount of ETH that can be staked before staking monitor\n // needs to a approve further staking by resetting the stake ETH tally\n function setStakeETHThreshold(uint256 _amount) external onlyGovernor {\n stakeETHThreshold = _amount;\n emit StakeETHThresholdChanged(_amount);\n }\n\n /// @notice Reset the stakeETHTally\n function resetStakeETHTally() external onlyStakingMonitor {\n stakeETHTally = 0;\n emit StakeETHTallyReset();\n }\n\n /// @notice Stakes WETH to the node validators\n /// @param validators A list of validator data needed to stake.\n /// The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot.\n /// Only the registrator can call this function.\n // slither-disable-start reentrancy-eth\n function stakeEth(ValidatorStakeData[] calldata validators)\n external\n onlyRegistrator\n whenNotPaused\n nonReentrant\n {\n uint256 requiredETH = validators.length * FULL_STAKE;\n\n // Check there is enough WETH from the deposits sitting in this strategy contract\n require(\n requiredETH <= IWETH9(WETH).balanceOf(address(this)),\n \"Insufficient WETH\"\n );\n require(\n activeDepositedValidators + validators.length <= MAX_VALIDATORS,\n \"Max validators reached\"\n );\n\n require(\n stakeETHTally + requiredETH <= stakeETHThreshold,\n \"Staking ETH over threshold\"\n );\n stakeETHTally += requiredETH;\n\n // Convert required ETH from WETH\n IWETH9(WETH).withdraw(requiredETH);\n _wethWithdrawn(requiredETH);\n\n /* 0x01 to indicate that withdrawal credentials will contain an EOA address that the sweeping function\n * can sweep funds to.\n * bytes11(0) to fill up the required zeros\n * remaining bytes20 are for the address\n */\n bytes memory withdrawalCredentials = abi.encodePacked(\n bytes1(0x01),\n bytes11(0),\n address(this)\n );\n\n // For each validator\n for (uint256 i = 0; i < validators.length; ++i) {\n bytes32 pubKeyHash = keccak256(validators[i].pubkey);\n\n require(\n validatorsStates[pubKeyHash] == VALIDATOR_STATE.REGISTERED,\n \"Validator not registered\"\n );\n\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\n value: FULL_STAKE\n }(\n validators[i].pubkey,\n withdrawalCredentials,\n validators[i].signature,\n validators[i].depositDataRoot\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.STAKED;\n\n emit ETHStaked(pubKeyHash, validators[i].pubkey, FULL_STAKE);\n }\n // save gas by changing this storage variable only once rather each time in the loop.\n activeDepositedValidators += validators.length;\n }\n\n // slither-disable-end reentrancy-eth\n\n /// @notice Registers a new validator in the SSV Cluster.\n /// Only the registrator can call this function.\n /// @param publicKeys The public keys of the validators\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param sharesData The shares data for each validator\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n // slither-disable-start reentrancy-no-eth\n function registerSsvValidators(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds,\n bytes[] calldata sharesData,\n Cluster calldata cluster\n ) external payable onlyRegistrator whenNotPaused {\n require(\n publicKeys.length == sharesData.length,\n \"Pubkey sharesData mismatch\"\n );\n // Check each public key has not already been used\n bytes32 pubKeyHash;\n VALIDATOR_STATE currentState;\n for (uint256 i = 0; i < publicKeys.length; ++i) {\n pubKeyHash = keccak256(publicKeys[i]);\n currentState = validatorsStates[pubKeyHash];\n require(\n currentState == VALIDATOR_STATE.NON_REGISTERED,\n \"Validator already registered\"\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.REGISTERED;\n\n emit SSVValidatorRegistered(pubKeyHash, publicKeys[i], operatorIds);\n }\n\n ISSVNetwork(SSV_NETWORK).bulkRegisterValidator{ value: msg.value }(\n publicKeys,\n operatorIds,\n sharesData,\n cluster\n );\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Exit a validator from the Beacon chain.\n /// The staked ETH will eventually swept to this native staking strategy.\n /// Only the registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n // slither-disable-start reentrancy-no-eth\n function exitSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external onlyRegistrator whenNotPaused {\n bytes32 pubKeyHash = keccak256(publicKey);\n VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];\n require(currentState == VALIDATOR_STATE.STAKED, \"Validator not staked\");\n\n ISSVNetwork(SSV_NETWORK).exitValidator(publicKey, operatorIds);\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXITING;\n\n emit SSVValidatorExitInitiated(pubKeyHash, publicKey, operatorIds);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Remove a validator from the SSV Cluster.\n /// Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain.\n /// If removed before the validator has exited the beacon chain will result in the validator being slashed.\n /// Only the registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n // slither-disable-start reentrancy-no-eth\n function removeSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n bytes32 pubKeyHash = keccak256(publicKey);\n VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];\n // Can remove SSV validators that were incorrectly registered and can not be deposited to.\n require(\n currentState == VALIDATOR_STATE.EXITING ||\n currentState == VALIDATOR_STATE.REGISTERED,\n \"Validator not regd or exiting\"\n );\n\n ISSVNetwork(SSV_NETWORK).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXIT_COMPLETE;\n\n emit SSVValidatorExitCompleted(pubKeyHash, publicKey, operatorIds);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Migrate the SSV cluster to use ETH for payment instead of SSV tokens.\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n function migrateClusterToETH(\n uint64[] memory operatorIds,\n Cluster memory cluster\n ) external payable onlyGovernor {\n ISSVNetwork(SSV_NETWORK).migrateClusterToETH{ value: msg.value }(\n operatorIds,\n cluster\n );\n\n // The SSV Network emits\n // ClusterMigratedToETH(msg.sender, operatorIds, msg.value, ssvClusterBalance, effectiveBalance, cluster)\n }\n\n /***************************************\n Consolidation functions\n ****************************************/\n\n /**\n * @notice Initiates the consolidation of multiple source sweeping validators to a single compounding validator.\n * @dev The validator registrator should be set to the ConsolidationController contract which\n * has checks against the target validator.\n * @param sourcePubKeys The full public keys of the source validators to be consolidated.\n * @param targetPubKey The full public key of the target validator to consolidate into.\n */\n // slither-disable-start reentrancy-no-eth\n function requestConsolidation(\n bytes[] calldata sourcePubKeys,\n bytes calldata targetPubKey\n ) external payable nonReentrant whenNotPaused onlyRegistrator {\n // Hash using the Native Staking Strategy's hashing method.\n // This is different to the Beacon chain's method.\n bytes32 targetPubKeyHash = keccak256(targetPubKey);\n bytes32 sourcePubKeyHash;\n uint256 totalConsolidationFees = 0;\n\n // For each source validator\n for (uint256 i = 0; i < sourcePubKeys.length; ++i) {\n sourcePubKeyHash = keccak256(sourcePubKeys[i]);\n require(sourcePubKeys[i].length == 48, \"Invalid source public key\");\n require(sourcePubKeyHash != targetPubKeyHash, \"Self consolidation\");\n require(\n validatorsStates[sourcePubKeyHash] == VALIDATOR_STATE.STAKED,\n \"Source validator not staked\"\n );\n\n // Store the state of the source validator as exiting so it can be removed\n // after the consolidation is confirmed\n validatorsStates[sourcePubKeyHash] = VALIDATOR_STATE.EXITING;\n\n // Request consolidation from source to target validator\n totalConsolidationFees += BeaconConsolidation.request(\n sourcePubKeys[i],\n targetPubKey\n );\n }\n\n require(\n totalConsolidationFees <= msg.value,\n \"Insufficient consolidation fee\"\n );\n\n emit ConsolidationRequested(\n sourcePubKeys,\n targetPubKey,\n sourcePubKeys.length\n );\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /**\n * @notice A consolidation request can fail to be processed on the beacon chain\n * for various reasons. For example, the pending consolidation queue is full with 262,144 requests.\n * This restores the validator states back to STAKED so they can be consolidated again or exited.\n * @param sourcePubKeys The full public keys of the source validators that failed to be consolidated.\n */\n function failConsolidation(bytes[] calldata sourcePubKeys)\n external\n nonReentrant\n whenNotPaused\n onlyRegistrator\n {\n bytes32 sourcePubKeyHash;\n\n // For each failed source validator\n for (uint256 i = 0; i < sourcePubKeys.length; ++i) {\n require(sourcePubKeys[i].length == 48, \"Invalid source public key\");\n sourcePubKeyHash = keccak256(sourcePubKeys[i]);\n require(\n validatorsStates[sourcePubKeyHash] == VALIDATOR_STATE.EXITING,\n \"Source validator not exiting\"\n );\n\n // Store the state of the source validator back to staked\n validatorsStates[sourcePubKeyHash] = VALIDATOR_STATE.STAKED;\n }\n\n emit ConsolidationFailed(sourcePubKeys, sourcePubKeys.length);\n }\n\n /**\n * @notice Confirms that a consolidation has completed successfully on the beacon chain.\n * This reduces the number of active deposited validators managed by this strategy which\n * reduces the strategy's balance.\n * @param consolidationCount The number of source validators that were consolidated.\n */\n function confirmConsolidation(uint256 consolidationCount)\n external\n nonReentrant\n whenNotPaused\n onlyRegistrator\n {\n // Store the reduced number of active deposited validators\n // managed by this strategy\n activeDepositedValidators -= consolidationCount;\n\n emit ConsolidationConfirmed(\n consolidationCount,\n activeDepositedValidators\n );\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n /// @dev Called when WETH is withdrawn from the strategy or staked to a validator so\n /// the strategy knows how much WETH it has on deposit.\n /// This is so it can emit the correct amount in the Deposit event in depositAll().\n function _wethWithdrawn(uint256 _amount) internal virtual;\n}\n" + }, + "contracts/strategies/sonic/SonicStakingStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SonicValidatorDelegator } from \"./SonicValidatorDelegator.sol\";\nimport { IWrappedSonic } from \"../../interfaces/sonic/IWrappedSonic.sol\";\n\n/**\n * @title Staking Strategy for Sonic's native S currency\n * @author Origin Protocol Inc\n */\ncontract SonicStakingStrategy is SonicValidatorDelegator {\n // For future use\n uint256[50] private __gap;\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _wrappedSonic,\n address _sfc\n ) SonicValidatorDelegator(_baseConfig, _wrappedSonic, _sfc) {}\n\n /// @notice Deposit wrapped S asset into the underlying platform.\n /// @param _asset Address of asset to deposit. Has to be Wrapped Sonic (wS).\n /// @param _amount Amount of assets that were transferred to the strategy by the vault.\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n require(_asset == wrappedSonic, \"Unsupported asset\");\n _deposit(_asset, _amount);\n }\n\n /**\n * @notice Deposit Wrapped Sonic (wS) to this strategy and delegate to a validator.\n * @param _asset Address of Wrapped Sonic (wS) token\n * @param _amount Amount of Wrapped Sonic (wS) to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal virtual {\n require(_amount > 0, \"Must deposit something\");\n\n _delegate(_amount);\n emit Deposit(_asset, address(0), _amount);\n }\n\n /**\n * @notice Deposit the entire balance of wrapped S in this strategy contract into\n * the underlying platform.\n */\n function depositAll() external virtual override onlyVault nonReentrant {\n uint256 wSBalance = IERC20(wrappedSonic).balanceOf(address(this));\n\n if (wSBalance > 0) {\n _deposit(wrappedSonic, wSBalance);\n }\n }\n\n /// @notice Withdraw Wrapped Sonic (wS) from this strategy contract.\n /// Used only if some wS is lingering on the contract.\n /// That can happen only when someone sends wS directly to this contract\n /// @param _recipient Address to receive withdrawn assets\n /// @param _asset Address of the Wrapped Sonic (wS) token\n /// @param _amount Amount of Wrapped Sonic (wS) to withdraw\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_asset == wrappedSonic, \"Unsupported asset\");\n _withdraw(_recipient, _asset, _amount);\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal override {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n // slither-disable-next-line unchecked-transfer unused-return\n IERC20(_asset).transfer(_recipient, _amount);\n\n emit Withdrawal(wrappedSonic, address(0), _amount);\n }\n\n /// @notice Transfer all Wrapped Sonic (wS) deposits back to the vault.\n /// This does not withdraw from delegated validators. That has to be done separately with `undelegate`.\n /// Any native S in this strategy will be withdrawn.\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 balance = address(this).balance;\n if (balance > 0) {\n IWrappedSonic(wrappedSonic).deposit{ value: balance }();\n }\n uint256 wSBalance = IERC20(wrappedSonic).balanceOf(address(this));\n if (wSBalance > 0) {\n _withdraw(vaultAddress, wrappedSonic, wSBalance);\n }\n }\n\n /**\n * @dev Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset token\n */\n function supportsAsset(address _asset)\n public\n view\n virtual\n override\n returns (bool)\n {\n return _asset == wrappedSonic;\n }\n\n /**\n * @notice is not supported for this strategy as the\n * Wrapped Sonic (wS) token is set at deploy time.\n */\n function setPTokenAddress(address, address)\n external\n view\n override\n onlyGovernor\n {\n revert(\"unsupported function\");\n }\n\n /// @notice is not used by this strategy as all staking rewards are restaked\n function collectRewardTokens() external override nonReentrant {\n revert(\"unsupported function\");\n }\n\n /**\n * @notice is not supported for this strategy as the\n * Wrapped Sonic (wS) token is set at deploy time.\n */\n function removePToken(uint256) external view override onlyGovernor {\n revert(\"unsupported function\");\n }\n\n /// @dev is not used by this strategy but must be implemented as it's abstract\n /// in the inherited `InitializableAbstractStrategy` contract.\n function _abstractSetPToken(address, address) internal virtual override {}\n\n /// @notice is not used by this strategy\n function safeApproveAllTokens() external override onlyGovernor {}\n}\n" + }, + "contracts/strategies/sonic/SonicSwapXAMOStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title SwapX Algorithmic Market Maker (AMO) Strategy\n * @notice AMO strategy for the SwapX OS/wS stable pool\n * @author Origin Protocol Inc\n */\nimport { StableSwapAMMStrategy } from \"../algebra/StableSwapAMMStrategy.sol\";\nimport { IGauge } from \"../../interfaces/algebra/IAlgebraGauge.sol\";\n\ncontract SonicSwapXAMOStrategy is StableSwapAMMStrategy {\n /**\n * @param _baseConfig The `platformAddress` is the address of the SwapX pool.\n * The `vaultAddress` is the address of the Origin Sonic Vault.\n * @param _gauge Address of the SwapX gauge for the pool.\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _gauge)\n StableSwapAMMStrategy(_baseConfig, _gauge, IGauge(_gauge).TOKEN())\n {}\n}\n" + }, + "contracts/strategies/sonic/SonicValidatorDelegator.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IVault } from \"../../interfaces/IVault.sol\";\nimport { ISFC } from \"../../interfaces/sonic/ISFC.sol\";\nimport { IWrappedSonic } from \"../../interfaces/sonic/IWrappedSonic.sol\";\n\n/**\n * @title Manages delegation to Sonic validators\n * @notice This contract implements all the required functionality to delegate to,\n undelegate from and withdraw from validators.\n * @author Origin Protocol Inc\n */\nabstract contract SonicValidatorDelegator is InitializableAbstractStrategy {\n /// @notice Address of Sonic's wrapped S token\n address public immutable wrappedSonic;\n /// @notice Sonic's Special Fee Contract (SFC)\n ISFC public immutable sfc;\n\n /// @notice a unique ID for each withdrawal request\n uint256 public nextWithdrawId;\n /// @notice Sonic (S) that is pending withdrawal after undelegating\n uint256 public pendingWithdrawals;\n\n /// @notice List of supported validator IDs that can be delegated to\n uint256[] public supportedValidators;\n\n /// @notice Default validator id to deposit to\n uint256 public defaultValidatorId;\n\n struct WithdrawRequest {\n uint256 validatorId;\n uint256 undelegatedAmount;\n uint256 timestamp;\n }\n /// @notice Mapping of withdrawIds to validatorIds and undelegatedAmounts\n mapping(uint256 => WithdrawRequest) public withdrawals;\n\n /// @notice Address of the registrator - allowed to register, exit and remove validators\n address public validatorRegistrator;\n\n // For future use\n uint256[44] private __gap;\n\n event Delegated(uint256 indexed validatorId, uint256 delegatedAmount);\n event Undelegated(\n uint256 indexed withdrawId,\n uint256 indexed validatorId,\n uint256 undelegatedAmount\n );\n event Withdrawn(\n uint256 indexed withdrawId,\n uint256 indexed validatorId,\n uint256 undelegatedAmount,\n uint256 withdrawnAmount\n );\n event RegistratorChanged(address indexed newAddress);\n event SupportedValidator(uint256 indexed validatorId);\n event UnsupportedValidator(uint256 indexed validatorId);\n event DefaultValidatorIdChanged(uint256 indexed validatorId);\n\n /// @dev Throws if called by any account other than the Registrator or Strategist\n modifier onlyRegistratorOrStrategist() {\n require(\n msg.sender == validatorRegistrator ||\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Registrator or Strategist\"\n );\n _;\n }\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _wrappedSonic,\n address _sfc\n ) InitializableAbstractStrategy(_baseConfig) {\n wrappedSonic = _wrappedSonic;\n sfc = ISFC(_sfc);\n }\n\n function initialize() external virtual onlyGovernor initializer {\n address[] memory rewardTokens = new address[](0);\n address[] memory assets = new address[](1);\n address[] memory pTokens = new address[](1);\n\n assets[0] = address(wrappedSonic);\n pTokens[0] = address(platformAddress);\n\n InitializableAbstractStrategy._initialize(\n rewardTokens,\n assets,\n pTokens\n );\n }\n\n /// @notice Returns the total value of Sonic (S) that is delegated validators.\n /// Wrapped Sonic (wS) deposits that are still to be delegated and any undelegated amounts\n /// still pending a withdrawal.\n /// @param _asset Address of Wrapped Sonic (wS) token\n /// @return balance Total value managed by the strategy\n function checkBalance(address _asset)\n external\n view\n virtual\n override\n returns (uint256 balance)\n {\n require(_asset == wrappedSonic, \"Unsupported asset\");\n\n // add the Wrapped Sonic (wS) in the strategy from deposits that are still to be delegated\n // and any undelegated amounts still pending a withdrawal\n balance =\n IERC20(wrappedSonic).balanceOf(address(this)) +\n pendingWithdrawals;\n\n // For each supported validator, get the staked amount and pending rewards\n uint256 validatorLen = supportedValidators.length;\n for (uint256 i = 0; i < validatorLen; i++) {\n uint256 validator = supportedValidators[i];\n balance += sfc.getStake(address(this), validator);\n balance += sfc.pendingRewards(address(this), validator);\n }\n }\n\n /**\n * @dev Delegate from this strategy to a specific Sonic validator. Called\n * automatically on asset deposit\n * @param _amount the amount of Sonic (S) to delegate.\n */\n function _delegate(uint256 _amount) internal {\n require(\n isSupportedValidator(defaultValidatorId),\n \"Validator not supported\"\n );\n\n // unwrap Wrapped Sonic (wS) to native Sonic (S)\n IWrappedSonic(wrappedSonic).withdraw(_amount);\n\n //slither-disable-next-line arbitrary-send-eth\n sfc.delegate{ value: _amount }(defaultValidatorId);\n\n emit Delegated(defaultValidatorId, _amount);\n }\n\n /**\n * @notice Undelegate from a specific Sonic validator.\n * This needs to be followed by a `withdrawFromSFC` two weeks later.\n * @param _validatorId The Sonic validator ID to undelegate from.\n * @param _undelegateAmount the amount of Sonic (S) to undelegate.\n * @return withdrawId The unique ID of the withdrawal request.\n */\n function undelegate(uint256 _validatorId, uint256 _undelegateAmount)\n external\n onlyRegistratorOrStrategist\n nonReentrant\n returns (uint256 withdrawId)\n {\n withdrawId = _undelegate(_validatorId, _undelegateAmount);\n }\n\n function _undelegate(uint256 _validatorId, uint256 _undelegateAmount)\n internal\n returns (uint256 withdrawId)\n {\n // Can still undelegate even if the validator is no longer supported\n require(_undelegateAmount > 0, \"Must undelegate something\");\n\n uint256 amountDelegated = sfc.getStake(address(this), _validatorId);\n require(\n _undelegateAmount <= amountDelegated,\n \"Insufficient delegation\"\n );\n\n withdrawId = nextWithdrawId++;\n\n withdrawals[withdrawId] = WithdrawRequest(\n _validatorId,\n _undelegateAmount,\n block.timestamp\n );\n pendingWithdrawals += _undelegateAmount;\n\n sfc.undelegate(_validatorId, withdrawId, _undelegateAmount);\n\n emit Undelegated(withdrawId, _validatorId, _undelegateAmount);\n }\n\n /**\n * @notice Withdraw native S from a previously undelegated validator.\n * The native S is wrapped wS and transferred to the Vault.\n * @param _withdrawId The unique withdraw ID used to `undelegate`\n * @return withdrawnAmount The amount of Sonic (S) withdrawn.\n * This can be less than the undelegated amount in the event of slashing.\n */\n function withdrawFromSFC(uint256 _withdrawId)\n external\n onlyRegistratorOrStrategist\n nonReentrant\n returns (uint256 withdrawnAmount)\n {\n require(_withdrawId < nextWithdrawId, \"Invalid withdrawId\");\n\n // Can still withdraw even if the validator is no longer supported\n // Load the withdrawal from storage into memory\n WithdrawRequest memory withdrawal = withdrawals[_withdrawId];\n require(!isWithdrawnFromSFC(_withdrawId), \"Already withdrawn\");\n\n withdrawals[_withdrawId].undelegatedAmount = 0;\n pendingWithdrawals -= withdrawal.undelegatedAmount;\n\n uint256 sBalanceBefore = address(this).balance;\n\n // Try to withdraw from SFC\n try sfc.withdraw(withdrawal.validatorId, _withdrawId) {\n // continue below\n } catch (bytes memory err) {\n bytes4 errorSelector = bytes4(err);\n\n // If the validator has been fully slashed, SFC's withdraw function will\n // revert with a StakeIsFullySlashed custom error.\n if (errorSelector == ISFC.StakeIsFullySlashed.selector) {\n // The validator was fully slashed, so all the delegated amounts were lost.\n // Will swallow the error as we still want to update the\n // withdrawals and pendingWithdrawals storage variables.\n\n // The return param defaults to zero but lets set it explicitly so it's clear\n withdrawnAmount = 0;\n\n emit Withdrawn(\n _withdrawId,\n withdrawal.validatorId,\n withdrawal.undelegatedAmount,\n withdrawnAmount\n );\n\n // Exit here as there is nothing to transfer to the Vault\n return withdrawnAmount;\n } else {\n // Bubble up any other SFC custom errors.\n // Inline assembly is currently the only way to generically rethrow the exact same custom error\n // from the raw bytes err in a catch block while preserving its original selector and parameters.\n // solhint-disable-next-line no-inline-assembly\n assembly {\n revert(add(32, err), mload(err))\n }\n }\n }\n\n // Set return parameter\n withdrawnAmount = address(this).balance - sBalanceBefore;\n\n // Wrap Sonic (S) to Wrapped Sonic (wS)\n IWrappedSonic(wrappedSonic).deposit{ value: withdrawnAmount }();\n\n // Transfer the Wrapped Sonic (wS) to the Vault\n _withdraw(vaultAddress, wrappedSonic, withdrawnAmount);\n\n // withdrawal.undelegatedAmount & withdrawnAmount can differ in case of slashing\n emit Withdrawn(\n _withdrawId,\n withdrawal.validatorId,\n withdrawal.undelegatedAmount,\n withdrawnAmount\n );\n }\n\n /// @notice returns a bool whether a withdrawalId has already been withdrawn or not\n /// @param _withdrawId The unique withdraw ID used to `undelegate`\n function isWithdrawnFromSFC(uint256 _withdrawId)\n public\n view\n returns (bool)\n {\n WithdrawRequest memory withdrawal = withdrawals[_withdrawId];\n require(withdrawal.validatorId > 0, \"Invalid withdrawId\");\n return withdrawal.undelegatedAmount == 0;\n }\n\n /**\n * @notice Restake any pending validator rewards for all supported validators\n * @param _validatorIds List of Sonic validator IDs to restake rewards\n */\n function restakeRewards(uint256[] calldata _validatorIds)\n external\n nonReentrant\n {\n for (uint256 i = 0; i < _validatorIds.length; ++i) {\n require(\n isSupportedValidator(_validatorIds[i]),\n \"Validator not supported\"\n );\n\n uint256 rewards = sfc.pendingRewards(\n address(this),\n _validatorIds[i]\n );\n\n if (rewards > 0) {\n sfc.restakeRewards(_validatorIds[i]);\n }\n }\n\n // The SFC contract will emit Delegated and RestakedRewards events.\n // The checkBalance function should not change as the pending rewards will moved to the staked amount.\n }\n\n /**\n * @notice Claim any pending rewards from validators\n * @param _validatorIds List of Sonic validator IDs to claim rewards\n */\n function collectRewards(uint256[] calldata _validatorIds)\n external\n onlyRegistratorOrStrategist\n nonReentrant\n {\n uint256 sBalanceBefore = address(this).balance;\n\n for (uint256 i = 0; i < _validatorIds.length; ++i) {\n uint256 rewards = sfc.pendingRewards(\n address(this),\n _validatorIds[i]\n );\n\n if (rewards > 0) {\n // The SFC contract will emit ClaimedRewards(delegator (this), validatorId, rewards)\n sfc.claimRewards(_validatorIds[i]);\n }\n }\n\n uint256 rewardsAmount = address(this).balance - sBalanceBefore;\n\n // Wrap Sonic (S) to Wrapped Sonic (wS)\n IWrappedSonic(wrappedSonic).deposit{ value: rewardsAmount }();\n\n // Transfer the Wrapped Sonic (wS) to the Vault\n _withdraw(vaultAddress, wrappedSonic, rewardsAmount);\n }\n\n /**\n * @notice To receive native S from SFC and Wrapped Sonic (wS)\n *\n * @dev This does not prevent donating S tokens to the contract\n * as wrappedSonic has a `withdrawTo` function where a third party\n * owner of wrappedSonic can withdraw to this contract.\n */\n receive() external payable {\n require(\n msg.sender == address(sfc) || msg.sender == wrappedSonic,\n \"S not from allowed contracts\"\n );\n }\n\n /***************************************\n Admin functions\n ****************************************/\n\n /// @notice Set the address of the Registrator which can undelegate, withdraw and collect rewards\n /// @param _validatorRegistrator The address of the Registrator\n function setRegistrator(address _validatorRegistrator)\n external\n onlyGovernor\n {\n validatorRegistrator = _validatorRegistrator;\n emit RegistratorChanged(_validatorRegistrator);\n }\n\n /// @notice Set the default validatorId to delegate to on deposit\n /// @param _validatorId The validator identifier. eg 18\n function setDefaultValidatorId(uint256 _validatorId)\n external\n onlyRegistratorOrStrategist\n {\n require(isSupportedValidator(_validatorId), \"Validator not supported\");\n defaultValidatorId = _validatorId;\n emit DefaultValidatorIdChanged(_validatorId);\n }\n\n /// @notice Allows a validator to be delegated to by the Registrator\n /// @param _validatorId The validator identifier. eg 18\n function supportValidator(uint256 _validatorId) external onlyGovernor {\n require(\n !isSupportedValidator(_validatorId),\n \"Validator already supported\"\n );\n\n supportedValidators.push(_validatorId);\n\n emit SupportedValidator(_validatorId);\n }\n\n /// @notice Removes a validator from the supported list.\n /// Unsupported validators can still be undelegated from, withdrawn from and rewards collected.\n /// @param _validatorId The validator identifier. eg 18\n function unsupportValidator(uint256 _validatorId) external onlyGovernor {\n require(isSupportedValidator(_validatorId), \"Validator not supported\");\n\n uint256 validatorLen = supportedValidators.length;\n for (uint256 i = 0; i < validatorLen; ++i) {\n if (supportedValidators[i] == _validatorId) {\n supportedValidators[i] = supportedValidators[validatorLen - 1];\n supportedValidators.pop();\n break;\n }\n }\n\n uint256 stake = sfc.getStake(address(this), _validatorId);\n\n // undelegate if validator still has funds staked\n if (stake > 0) {\n _undelegate(_validatorId, stake);\n }\n emit UnsupportedValidator(_validatorId);\n }\n\n /// @notice Returns the length of the supportedValidators array\n function supportedValidatorsLength() external view returns (uint256) {\n return supportedValidators.length;\n }\n\n /// @notice Returns whether a validator is supported by this strategy\n /// @param _validatorId The validator identifier\n function isSupportedValidator(uint256 _validatorId)\n public\n view\n returns (bool)\n {\n uint256 validatorLen = supportedValidators.length;\n for (uint256 i = 0; i < validatorLen; ++i) {\n if (supportedValidators[i] == _validatorId) {\n return true;\n }\n }\n return false;\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal virtual;\n}\n" + }, + "contracts/strategies/VaultValueChecker.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IOUSD } from \"../interfaces/IOUSD.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract VaultValueChecker {\n IVault public immutable vault;\n IOUSD public immutable ousd;\n // Snapshot expiration time in seconds.\n // Used to prevent accidental use of an old snapshot, but\n // is not zero to allow easy testing of strategist actions in fork testing\n uint256 constant SNAPSHOT_EXPIRES = 5 * 60;\n\n struct Snapshot {\n uint256 vaultValue;\n uint256 totalSupply;\n uint256 time;\n }\n // By doing per user snapshots, we prevent a reentrancy attack\n // from a third party that updates the snapshot in the middle\n // of an allocation process\n\n mapping(address => Snapshot) public snapshots;\n\n constructor(address _vault, address _ousd) {\n vault = IVault(_vault);\n ousd = IOUSD(_ousd);\n }\n\n function takeSnapshot() external {\n snapshots[msg.sender] = Snapshot({\n vaultValue: vault.totalValue(),\n totalSupply: ousd.totalSupply(),\n time: block.timestamp\n });\n }\n\n function checkDelta(\n int256 expectedProfit,\n int256 profitVariance,\n int256 expectedVaultChange,\n int256 vaultChangeVariance\n ) external {\n // Intentionaly not view so that this method shows up in TX builders\n Snapshot memory snapshot = snapshots[msg.sender];\n int256 vaultChange = toInt256(vault.totalValue()) -\n toInt256(snapshot.vaultValue);\n int256 supplyChange = toInt256(ousd.totalSupply()) -\n toInt256(snapshot.totalSupply);\n int256 profit = vaultChange - supplyChange;\n\n require(\n snapshot.time >= block.timestamp - SNAPSHOT_EXPIRES,\n \"Snapshot too old\"\n );\n require(snapshot.time <= block.timestamp, \"Snapshot too new\");\n require(profit >= expectedProfit - profitVariance, \"Profit too low\");\n require(profit <= expectedProfit + profitVariance, \"Profit too high\");\n require(\n vaultChange >= expectedVaultChange - vaultChangeVariance,\n \"Vault value change too low\"\n );\n require(\n vaultChange <= expectedVaultChange + vaultChangeVariance,\n \"Vault value change too high\"\n );\n }\n\n function toInt256(uint256 value) internal pure returns (int256) {\n // From openzeppelin math/SafeCast.sol\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(\n value <= uint256(type(int256).max),\n \"SafeCast: value doesn't fit in an int256\"\n );\n return int256(value);\n }\n}\n\ncontract OETHVaultValueChecker is VaultValueChecker {\n constructor(address _vault, address _ousd)\n VaultValueChecker(_vault, _ousd)\n {}\n}\n" + }, + "contracts/token/OETH.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { OUSD } from \"./OUSD.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\ncontract OETH is OUSD {\n function symbol() external pure override returns (string memory) {\n return \"OETH\";\n }\n\n function name() external pure override returns (string memory) {\n return \"Origin Ether\";\n }\n\n function decimals() external pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/token/OETHBase.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { OUSD } from \"./OUSD.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\ncontract OETHBase is OUSD {\n constructor() {\n // Nobody owns the implementation contract\n _setGovernor(address(0));\n }\n\n function symbol() external pure override returns (string memory) {\n return \"superOETHb\";\n }\n\n function name() external pure override returns (string memory) {\n return \"Super OETH\";\n }\n\n function decimals() external pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/token/OETHPlume.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { OUSD } from \"./OUSD.sol\";\n\n/**\n * @title Super OETH (Plume) Token Contract\n * @author Origin Protocol Inc\n */\ncontract OETHPlume is OUSD {\n constructor() {\n // Nobody owns the implementation contract\n _setGovernor(address(0));\n }\n\n function symbol() external pure override returns (string memory) {\n return \"superOETHp\";\n }\n\n function name() external pure override returns (string memory) {\n return \"Super OETH\";\n }\n\n function decimals() external pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/token/OSonic.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { OUSD } from \"./OUSD.sol\";\n\n/**\n * @title Origin Sonic (OS) token on Sonic\n * @author Origin Protocol Inc\n */\ncontract OSonic is OUSD {\n function symbol() external pure override returns (string memory) {\n return \"OS\";\n }\n\n function name() external pure override returns (string memory) {\n return \"Origin Sonic\";\n }\n}\n" + }, + "contracts/token/OUSD.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Token Contract\n * @dev ERC20 compatible contract for OUSD\n * @dev Implements an elastic supply\n * @author Origin Protocol Inc\n */\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\ncontract OUSD is Governable {\n using SafeCast for int256;\n using SafeCast for uint256;\n\n /// @dev Event triggered when the supply changes\n /// @param totalSupply Updated token total supply\n /// @param rebasingCredits Updated token rebasing credits\n /// @param rebasingCreditsPerToken Updated token rebasing credits per token\n event TotalSupplyUpdatedHighres(\n uint256 totalSupply,\n uint256 rebasingCredits,\n uint256 rebasingCreditsPerToken\n );\n /// @dev Event triggered when an account opts in for rebasing\n /// @param account Address of the account\n event AccountRebasingEnabled(address account);\n /// @dev Event triggered when an account opts out of rebasing\n /// @param account Address of the account\n event AccountRebasingDisabled(address account);\n /// @dev Emitted when `value` tokens are moved from one account `from` to\n /// another `to`.\n /// @param from Address of the account tokens are moved from\n /// @param to Address of the account tokens are moved to\n /// @param value Amount of tokens transferred\n event Transfer(address indexed from, address indexed to, uint256 value);\n /// @dev Emitted when the allowance of a `spender` for an `owner` is set by\n /// a call to {approve}. `value` is the new allowance.\n /// @param owner Address of the owner approving allowance\n /// @param spender Address of the spender allowance is granted to\n /// @param value Amount of tokens spender can transfer\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n /// @dev Yield resulting from {changeSupply} that a `source` account would\n /// receive is directed to `target` account.\n /// @param source Address of the source forwarding the yield\n /// @param target Address of the target receiving the yield\n event YieldDelegated(address source, address target);\n /// @dev Yield delegation from `source` account to the `target` account is\n /// suspended.\n /// @param source Address of the source suspending yield forwarding\n /// @param target Address of the target no longer receiving yield from `source`\n /// account\n event YieldUndelegated(address source, address target);\n\n enum RebaseOptions {\n NotSet,\n StdNonRebasing,\n StdRebasing,\n YieldDelegationSource,\n YieldDelegationTarget\n }\n\n uint256[154] private _gap; // Slots to align with deployed contract\n uint256 private constant MAX_SUPPLY = type(uint128).max;\n /// @dev The amount of tokens in existence\n uint256 public totalSupply;\n mapping(address => mapping(address => uint256)) private allowances;\n /// @dev The vault with privileges to execute {mint}, {burn}\n /// and {changeSupply}\n address public vaultAddress;\n mapping(address => uint256) internal creditBalances;\n // the 2 storage variables below need trailing underscores to not name collide with public functions\n uint256 private rebasingCredits_; // Sum of all rebasing credits (creditBalances for rebasing accounts)\n uint256 private rebasingCreditsPerToken_;\n /// @dev The amount of tokens that are not rebasing - receiving yield\n uint256 public nonRebasingSupply;\n mapping(address => uint256) internal alternativeCreditsPerToken;\n /// @dev A map of all addresses and their respective RebaseOptions\n mapping(address => RebaseOptions) public rebaseState;\n mapping(address => uint256) private __deprecated_isUpgraded;\n /// @dev A map of addresses that have yields forwarded to. This is an\n /// inverse mapping of {yieldFrom}\n /// Key Account forwarding yield\n /// Value Account receiving yield\n mapping(address => address) public yieldTo;\n /// @dev A map of addresses that are receiving the yield. This is an\n /// inverse mapping of {yieldTo}\n /// Key Account receiving yield\n /// Value Account forwarding yield\n mapping(address => address) public yieldFrom;\n\n uint256 private constant RESOLUTION_INCREASE = 1e9;\n uint256[34] private __gap; // including below gap totals up to 200\n\n /// @dev Verifies that the caller is the Governor or Strategist.\n modifier onlyGovernorOrStrategist() {\n require(\n isGovernor() || msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n /// @dev Initializes the contract and sets necessary variables.\n /// @param _vaultAddress Address of the vault contract\n /// @param _initialCreditsPerToken The starting rebasing credits per token.\n function initialize(address _vaultAddress, uint256 _initialCreditsPerToken)\n external\n onlyGovernor\n {\n require(_vaultAddress != address(0), \"Zero vault address\");\n require(vaultAddress == address(0), \"Already initialized\");\n\n rebasingCreditsPerToken_ = _initialCreditsPerToken;\n vaultAddress = _vaultAddress;\n }\n\n /// @dev Returns the symbol of the token, a shorter version\n /// of the name.\n function symbol() external pure virtual returns (string memory) {\n return \"OUSD\";\n }\n\n /// @dev Returns the name of the token.\n function name() external pure virtual returns (string memory) {\n return \"Origin Dollar\";\n }\n\n /// @dev Returns the number of decimals used to get its user representation.\n function decimals() external pure virtual returns (uint8) {\n return 18;\n }\n\n /**\n * @dev Verifies that the caller is the Vault contract\n */\n modifier onlyVault() {\n require(vaultAddress == msg.sender, \"Caller is not the Vault\");\n _;\n }\n\n /**\n * @return High resolution rebasingCreditsPerToken\n */\n function rebasingCreditsPerTokenHighres() external view returns (uint256) {\n return rebasingCreditsPerToken_;\n }\n\n /**\n * @return Low resolution rebasingCreditsPerToken\n */\n function rebasingCreditsPerToken() external view returns (uint256) {\n return rebasingCreditsPerToken_ / RESOLUTION_INCREASE;\n }\n\n /**\n * @return High resolution total number of rebasing credits\n */\n function rebasingCreditsHighres() external view returns (uint256) {\n return rebasingCredits_;\n }\n\n /**\n * @return Low resolution total number of rebasing credits\n */\n function rebasingCredits() external view returns (uint256) {\n return rebasingCredits_ / RESOLUTION_INCREASE;\n }\n\n /**\n * @notice Gets the balance of the specified address.\n * @param _account Address to query the balance of.\n * @return A uint256 representing the amount of base units owned by the\n * specified address.\n */\n function balanceOf(address _account) public view returns (uint256) {\n RebaseOptions state = rebaseState[_account];\n if (state == RebaseOptions.YieldDelegationSource) {\n // Saves a slot read when transferring to or from a yield delegating source\n // since we know creditBalances equals the balance.\n return creditBalances[_account];\n }\n uint256 baseBalance = (creditBalances[_account] * 1e18) /\n _creditsPerToken(_account);\n if (state == RebaseOptions.YieldDelegationTarget) {\n // creditBalances of yieldFrom accounts equals token balances\n return baseBalance - creditBalances[yieldFrom[_account]];\n }\n return baseBalance;\n }\n\n /**\n * @notice Gets the credits balance of the specified address.\n * @dev Backwards compatible with old low res credits per token.\n * @param _account The address to query the balance of.\n * @return (uint256, uint256) Credit balance and credits per token of the\n * address\n */\n function creditsBalanceOf(address _account)\n external\n view\n returns (uint256, uint256)\n {\n uint256 cpt = _creditsPerToken(_account);\n if (cpt == 1e27) {\n // For a period before the resolution upgrade, we created all new\n // contract accounts at high resolution. Since they are not changing\n // as a result of this upgrade, we will return their true values\n return (creditBalances[_account], cpt);\n } else {\n return (\n creditBalances[_account] / RESOLUTION_INCREASE,\n cpt / RESOLUTION_INCREASE\n );\n }\n }\n\n /**\n * @notice Gets the credits balance of the specified address.\n * @param _account The address to query the balance of.\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\n * address, and isUpgraded\n */\n function creditsBalanceOfHighres(address _account)\n external\n view\n returns (\n uint256,\n uint256,\n bool\n )\n {\n return (\n creditBalances[_account],\n _creditsPerToken(_account),\n true // all accounts have their resolution \"upgraded\"\n );\n }\n\n // Backwards compatible view\n function nonRebasingCreditsPerToken(address _account)\n external\n view\n returns (uint256)\n {\n return alternativeCreditsPerToken[_account];\n }\n\n /**\n * @notice Transfer tokens to a specified address.\n * @param _to the address to transfer to.\n * @param _value the amount to be transferred.\n * @return true on success.\n */\n function transfer(address _to, uint256 _value) external returns (bool) {\n require(_to != address(0), \"Transfer to zero address\");\n\n _executeTransfer(msg.sender, _to, _value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n /**\n * @notice Transfer tokens from one address to another.\n * @param _from The address you want to send tokens from.\n * @param _to The address you want to transfer to.\n * @param _value The amount of tokens to be transferred.\n * @return true on success.\n */\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool) {\n require(_to != address(0), \"Transfer to zero address\");\n uint256 userAllowance = allowances[_from][msg.sender];\n require(_value <= userAllowance, \"Allowance exceeded\");\n\n unchecked {\n allowances[_from][msg.sender] = userAllowance - _value;\n }\n\n _executeTransfer(_from, _to, _value);\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function _executeTransfer(\n address _from,\n address _to,\n uint256 _value\n ) internal {\n (\n int256 fromRebasingCreditsDiff,\n int256 fromNonRebasingSupplyDiff\n ) = _adjustAccount(_from, -_value.toInt256());\n (\n int256 toRebasingCreditsDiff,\n int256 toNonRebasingSupplyDiff\n ) = _adjustAccount(_to, _value.toInt256());\n\n _adjustGlobals(\n fromRebasingCreditsDiff + toRebasingCreditsDiff,\n fromNonRebasingSupplyDiff + toNonRebasingSupplyDiff\n );\n }\n\n function _adjustAccount(address _account, int256 _balanceChange)\n internal\n returns (int256 rebasingCreditsDiff, int256 nonRebasingSupplyDiff)\n {\n RebaseOptions state = rebaseState[_account];\n int256 currentBalance = balanceOf(_account).toInt256();\n if (currentBalance + _balanceChange < 0) {\n revert(\"Transfer amount exceeds balance\");\n }\n uint256 newBalance = (currentBalance + _balanceChange).toUint256();\n\n if (state == RebaseOptions.YieldDelegationSource) {\n address target = yieldTo[_account];\n uint256 targetOldBalance = balanceOf(target);\n uint256 targetNewCredits = _balanceToRebasingCredits(\n targetOldBalance + newBalance\n );\n rebasingCreditsDiff =\n targetNewCredits.toInt256() -\n creditBalances[target].toInt256();\n\n creditBalances[_account] = newBalance;\n creditBalances[target] = targetNewCredits;\n } else if (state == RebaseOptions.YieldDelegationTarget) {\n uint256 newCredits = _balanceToRebasingCredits(\n newBalance + creditBalances[yieldFrom[_account]]\n );\n rebasingCreditsDiff =\n newCredits.toInt256() -\n creditBalances[_account].toInt256();\n creditBalances[_account] = newCredits;\n } else {\n _autoMigrate(_account);\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\n _account\n ];\n if (alternativeCreditsPerTokenMem > 0) {\n nonRebasingSupplyDiff = _balanceChange;\n if (alternativeCreditsPerTokenMem != 1e18) {\n alternativeCreditsPerToken[_account] = 1e18;\n }\n creditBalances[_account] = newBalance;\n } else {\n uint256 newCredits = _balanceToRebasingCredits(newBalance);\n rebasingCreditsDiff =\n newCredits.toInt256() -\n creditBalances[_account].toInt256();\n creditBalances[_account] = newCredits;\n }\n }\n }\n\n function _adjustGlobals(\n int256 _rebasingCreditsDiff,\n int256 _nonRebasingSupplyDiff\n ) internal {\n if (_rebasingCreditsDiff != 0) {\n rebasingCredits_ = (rebasingCredits_.toInt256() +\n _rebasingCreditsDiff).toUint256();\n }\n if (_nonRebasingSupplyDiff != 0) {\n nonRebasingSupply = (nonRebasingSupply.toInt256() +\n _nonRebasingSupplyDiff).toUint256();\n }\n }\n\n /**\n * @notice Function to check the amount of tokens that _owner has allowed\n * to `_spender`.\n * @param _owner The address which owns the funds.\n * @param _spender The address which will spend the funds.\n * @return The number of tokens still available for the _spender.\n */\n function allowance(address _owner, address _spender)\n external\n view\n returns (uint256)\n {\n return allowances[_owner][_spender];\n }\n\n /**\n * @notice Approve the passed address to spend the specified amount of\n * tokens on behalf of msg.sender.\n * @param _spender The address which will spend the funds.\n * @param _value The amount of tokens to be spent.\n * @return true on success.\n */\n function approve(address _spender, uint256 _value) external returns (bool) {\n allowances[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n /**\n * @notice Creates `_amount` tokens and assigns them to `_account`,\n * increasing the total supply.\n */\n function mint(address _account, uint256 _amount) external onlyVault {\n require(_account != address(0), \"Mint to the zero address\");\n\n // Account\n (\n int256 toRebasingCreditsDiff,\n int256 toNonRebasingSupplyDiff\n ) = _adjustAccount(_account, _amount.toInt256());\n // Globals\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\n totalSupply = totalSupply + _amount;\n\n require(totalSupply < MAX_SUPPLY, \"Max supply\");\n emit Transfer(address(0), _account, _amount);\n }\n\n /**\n * @notice Destroys `_amount` tokens from `_account`,\n * reducing the total supply.\n */\n function burn(address _account, uint256 _amount) external onlyVault {\n require(_account != address(0), \"Burn from the zero address\");\n if (_amount == 0) {\n return;\n }\n\n // Account\n (\n int256 toRebasingCreditsDiff,\n int256 toNonRebasingSupplyDiff\n ) = _adjustAccount(_account, -_amount.toInt256());\n // Globals\n _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\n totalSupply = totalSupply - _amount;\n\n emit Transfer(_account, address(0), _amount);\n }\n\n /**\n * @dev Get the credits per token for an account. Returns a fixed amount\n * if the account is non-rebasing.\n * @param _account Address of the account.\n */\n function _creditsPerToken(address _account)\n internal\n view\n returns (uint256)\n {\n uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\n _account\n ];\n if (alternativeCreditsPerTokenMem != 0) {\n return alternativeCreditsPerTokenMem;\n } else {\n return rebasingCreditsPerToken_;\n }\n }\n\n /**\n * @dev Auto migrate contracts to be non rebasing,\n * unless they have opted into yield.\n * @param _account Address of the account.\n */\n function _autoMigrate(address _account) internal {\n uint256 codeLen = _account.code.length;\n bool isEOA = (codeLen == 0) ||\n (codeLen == 23 && bytes3(_account.code) == 0xef0100);\n // In previous code versions, contracts would not have had their\n // rebaseState[_account] set to RebaseOptions.NonRebasing when migrated\n // therefore we check the actual accounting used on the account as well.\n if (\n (!isEOA) &&\n rebaseState[_account] == RebaseOptions.NotSet &&\n alternativeCreditsPerToken[_account] == 0\n ) {\n _rebaseOptOut(_account);\n }\n }\n\n /**\n * @dev Calculates credits from contract's global rebasingCreditsPerToken_, and\n * also balance that corresponds to those credits. The latter is important\n * when adjusting the contract's global nonRebasingSupply to circumvent any\n * possible rounding errors.\n *\n * @param _balance Balance of the account.\n */\n function _balanceToRebasingCredits(uint256 _balance)\n internal\n view\n returns (uint256 rebasingCredits)\n {\n // Rounds up, because we need to ensure that accounts always have\n // at least the balance that they should have.\n // Note this should always be used on an absolute account value,\n // not on a possibly negative diff, because then the rounding would be wrong.\n return ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18;\n }\n\n /**\n * @notice The calling account will start receiving yield after a successful call.\n * @param _account Address of the account.\n */\n function governanceRebaseOptIn(address _account) external onlyGovernor {\n require(_account != address(0), \"Zero address not allowed\");\n _rebaseOptIn(_account);\n }\n\n /**\n * @notice The calling account will start receiving yield after a successful call.\n */\n function rebaseOptIn() external {\n _rebaseOptIn(msg.sender);\n }\n\n function _rebaseOptIn(address _account) internal {\n uint256 balance = balanceOf(_account);\n\n // prettier-ignore\n require(\n alternativeCreditsPerToken[_account] > 0 ||\n // Accounts may explicitly `rebaseOptIn` regardless of\n // accounting if they have a 0 balance.\n creditBalances[_account] == 0\n ,\n \"Account must be non-rebasing\"\n );\n RebaseOptions state = rebaseState[_account];\n // prettier-ignore\n require(\n state == RebaseOptions.StdNonRebasing ||\n state == RebaseOptions.NotSet,\n \"Only standard non-rebasing accounts can opt in\"\n );\n\n uint256 newCredits = _balanceToRebasingCredits(balance);\n\n // Account\n rebaseState[_account] = RebaseOptions.StdRebasing;\n alternativeCreditsPerToken[_account] = 0;\n creditBalances[_account] = newCredits;\n // Globals\n _adjustGlobals(newCredits.toInt256(), -balance.toInt256());\n\n emit AccountRebasingEnabled(_account);\n }\n\n /**\n * @notice The calling account will no longer receive yield\n */\n function rebaseOptOut() external {\n _rebaseOptOut(msg.sender);\n }\n\n function _rebaseOptOut(address _account) internal {\n require(\n alternativeCreditsPerToken[_account] == 0,\n \"Account must be rebasing\"\n );\n RebaseOptions state = rebaseState[_account];\n require(\n state == RebaseOptions.StdRebasing || state == RebaseOptions.NotSet,\n \"Only standard rebasing accounts can opt out\"\n );\n\n uint256 oldCredits = creditBalances[_account];\n uint256 balance = balanceOf(_account);\n\n // Account\n rebaseState[_account] = RebaseOptions.StdNonRebasing;\n alternativeCreditsPerToken[_account] = 1e18;\n creditBalances[_account] = balance;\n // Globals\n _adjustGlobals(-oldCredits.toInt256(), balance.toInt256());\n\n emit AccountRebasingDisabled(_account);\n }\n\n /**\n * @notice Distribute yield to users. This changes the exchange rate\n * between \"credits\" and OUSD tokens to change rebasing user's balances.\n * @param _newTotalSupply New total supply of OUSD.\n */\n function changeSupply(uint256 _newTotalSupply) external onlyVault {\n require(totalSupply > 0, \"Cannot increase 0 supply\");\n\n if (totalSupply == _newTotalSupply) {\n emit TotalSupplyUpdatedHighres(\n totalSupply,\n rebasingCredits_,\n rebasingCreditsPerToken_\n );\n return;\n }\n\n totalSupply = _newTotalSupply > MAX_SUPPLY\n ? MAX_SUPPLY\n : _newTotalSupply;\n\n uint256 rebasingSupply = totalSupply - nonRebasingSupply;\n // round up in the favour of the protocol\n rebasingCreditsPerToken_ =\n (rebasingCredits_ * 1e18 + rebasingSupply - 1) /\n rebasingSupply;\n\n require(rebasingCreditsPerToken_ > 0, \"Invalid change in supply\");\n\n emit TotalSupplyUpdatedHighres(\n totalSupply,\n rebasingCredits_,\n rebasingCreditsPerToken_\n );\n }\n\n /*\n * @notice Send the yield from one account to another account.\n * Each account keeps its own balances.\n */\n function delegateYield(address _from, address _to)\n external\n onlyGovernorOrStrategist\n {\n require(_from != address(0), \"Zero from address not allowed\");\n require(_to != address(0), \"Zero to address not allowed\");\n\n require(_from != _to, \"Cannot delegate to self\");\n require(\n yieldFrom[_to] == address(0) &&\n yieldTo[_to] == address(0) &&\n yieldFrom[_from] == address(0) &&\n yieldTo[_from] == address(0),\n \"Blocked by existing yield delegation\"\n );\n RebaseOptions stateFrom = rebaseState[_from];\n RebaseOptions stateTo = rebaseState[_to];\n\n require(\n stateFrom == RebaseOptions.NotSet ||\n stateFrom == RebaseOptions.StdNonRebasing ||\n stateFrom == RebaseOptions.StdRebasing,\n \"Invalid rebaseState from\"\n );\n\n require(\n stateTo == RebaseOptions.NotSet ||\n stateTo == RebaseOptions.StdNonRebasing ||\n stateTo == RebaseOptions.StdRebasing,\n \"Invalid rebaseState to\"\n );\n\n if (alternativeCreditsPerToken[_from] == 0) {\n _rebaseOptOut(_from);\n }\n if (alternativeCreditsPerToken[_to] > 0) {\n _rebaseOptIn(_to);\n }\n\n uint256 fromBalance = balanceOf(_from);\n uint256 toBalance = balanceOf(_to);\n uint256 oldToCredits = creditBalances[_to];\n uint256 newToCredits = _balanceToRebasingCredits(\n fromBalance + toBalance\n );\n\n // Set up the bidirectional links\n yieldTo[_from] = _to;\n yieldFrom[_to] = _from;\n\n // Local\n rebaseState[_from] = RebaseOptions.YieldDelegationSource;\n alternativeCreditsPerToken[_from] = 1e18;\n creditBalances[_from] = fromBalance;\n rebaseState[_to] = RebaseOptions.YieldDelegationTarget;\n creditBalances[_to] = newToCredits;\n\n // Global\n int256 creditsChange = newToCredits.toInt256() -\n oldToCredits.toInt256();\n _adjustGlobals(creditsChange, -(fromBalance).toInt256());\n emit YieldDelegated(_from, _to);\n }\n\n /*\n * @notice Stop sending the yield from one account to another account.\n */\n function undelegateYield(address _from) external onlyGovernorOrStrategist {\n // Require a delegation, which will also ensure a valid delegation\n require(yieldTo[_from] != address(0), \"Zero address not allowed\");\n\n address to = yieldTo[_from];\n uint256 fromBalance = balanceOf(_from);\n uint256 toBalance = balanceOf(to);\n uint256 oldToCredits = creditBalances[to];\n uint256 newToCredits = _balanceToRebasingCredits(toBalance);\n\n // Remove the bidirectional links\n yieldFrom[to] = address(0);\n yieldTo[_from] = address(0);\n\n // Local\n rebaseState[_from] = RebaseOptions.StdNonRebasing;\n // alternativeCreditsPerToken[from] already 1e18 from `delegateYield()`\n creditBalances[_from] = fromBalance;\n rebaseState[to] = RebaseOptions.StdRebasing;\n // alternativeCreditsPerToken[to] already 0 from `delegateYield()`\n creditBalances[to] = newToCredits;\n\n // Global\n int256 creditsChange = newToCredits.toInt256() -\n oldToCredits.toInt256();\n _adjustGlobals(creditsChange, fromBalance.toInt256());\n emit YieldUndelegated(_from, to);\n }\n}\n" + }, + "contracts/token/WOETH.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ERC4626 } from \"../../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { OETH } from \"./OETH.sol\";\n\n/**\n * @title Wrapped OETH Token Contract\n * @author Origin Protocol Inc\n *\n * @dev An important capability of this contract is that it isn't susceptible to changes of the\n * exchange rate of WOETH/OETH if/when someone sends the underlying asset (OETH) to the contract.\n * If OETH weren't rebasing this could be achieved by solely tracking the ERC20 transfers of the OETH\n * token on mint, deposit, redeem, withdraw. The issue is that OETH is rebasing and OETH balances\n * will change when the token rebases.\n * For that reason the contract logic checks the actual underlying OETH token balance only once\n * (either on a fresh contract creation or upgrade) and considering the WOETH supply and\n * rebasingCreditsPerToken calculates the _adjuster. Once the adjuster is calculated any donations\n * to the contract are ignored. The totalSupply (instead of querying OETH balance) works off of\n * adjuster the current WOETH supply and rebasingCreditsPerToken. This makes WOETH value accrual\n * completely follow OETH's value accrual.\n * WOETH is safe to use in lending markets as the VualtCore's _rebase contains safeguards preventing\n * any sudden large rebases.\n */\n\ncontract WOETH is ERC4626, Governable, Initializable {\n using SafeERC20 for IERC20;\n /* This is a 1e27 adjustment constant that expresses the difference in exchange rate between\n * OETH's rebase since inception (expressed with rebasingCreditsPerToken) and WOETH to OETH\n * conversion.\n *\n * If WOETH and OETH are deployed at the same time, the value of adjuster is a neutral 1e27\n */\n uint256 public adjuster;\n uint256[49] private __gap;\n\n // no need to set ERC20 name and symbol since they are overridden in WOETH & WOETHBase\n constructor(ERC20 underlying_) ERC20(\"\", \"\") ERC4626(underlying_) {}\n\n /**\n * @notice Enable OETH rebasing for this contract\n */\n function initialize() external onlyGovernor initializer {\n OETH(address(asset())).rebaseOptIn();\n\n initialize2();\n }\n\n /**\n * @notice secondary initializer that newly deployed contracts will execute as part\n * of primary initialize function and the existing contracts will have it called\n * as a governance operation.\n */\n function initialize2() public onlyGovernor {\n require(adjuster == 0, \"Initialize2 already called\");\n\n if (totalSupply() == 0) {\n adjuster = 1e27;\n } else {\n adjuster =\n (rebasingCreditsPerTokenHighres() *\n ERC20(asset()).balanceOf(address(this))) /\n totalSupply();\n }\n }\n\n function name()\n public\n view\n virtual\n override(ERC20, IERC20Metadata)\n returns (string memory)\n {\n return \"Wrapped OETH\";\n }\n\n function symbol()\n public\n view\n virtual\n override(ERC20, IERC20Metadata)\n returns (string memory)\n {\n return \"wOETH\";\n }\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends. Cannot transfer OETH\n * @param asset_ Address for the asset\n * @param amount_ Amount of the asset to transfer\n */\n function transferToken(address asset_, uint256 amount_)\n external\n onlyGovernor\n {\n require(asset_ != address(asset()), \"Cannot collect core asset\");\n IERC20(asset_).safeTransfer(governor(), amount_);\n }\n\n /// @inheritdoc ERC4626\n function convertToShares(uint256 assets)\n public\n view\n virtual\n override\n returns (uint256 shares)\n {\n return (assets * rebasingCreditsPerTokenHighres()) / adjuster;\n }\n\n /// @inheritdoc ERC4626\n function convertToAssets(uint256 shares)\n public\n view\n virtual\n override\n returns (uint256 assets)\n {\n return (shares * adjuster) / rebasingCreditsPerTokenHighres();\n }\n\n /// @inheritdoc ERC4626\n function totalAssets() public view override returns (uint256) {\n return (totalSupply() * adjuster) / rebasingCreditsPerTokenHighres();\n }\n\n function rebasingCreditsPerTokenHighres() internal view returns (uint256) {\n return OETH(asset()).rebasingCreditsPerTokenHighres();\n }\n}\n" + }, + "contracts/token/WOETHBase.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { WOETH } from \"./WOETH.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\n\ncontract WOETHBase is WOETH {\n constructor(ERC20 underlying_) WOETH(underlying_) {}\n\n function name() public view virtual override returns (string memory) {\n return \"Wrapped Super OETH\";\n }\n\n function symbol() public view virtual override returns (string memory) {\n return \"wsuperOETHb\";\n }\n}\n" + }, + "contracts/token/WOETHPlume.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { WOETH } from \"./WOETH.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\n/**\n * @title wOETH (Plume) Token Contract\n * @author Origin Protocol Inc\n */\n\ncontract WOETHPlume is WOETH {\n constructor(ERC20 underlying_) WOETH(underlying_) {}\n\n function name() public view virtual override returns (string memory) {\n return \"Wrapped Super OETH\";\n }\n\n function symbol() public view virtual override returns (string memory) {\n return \"wsuperOETHp\";\n }\n}\n" + }, + "contracts/token/WOSonic.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { WOETH } from \"./WOETH.sol\";\n\n/**\n * @title Wrapped Origin Sonic (wOS) token on Sonic\n * @author Origin Protocol Inc\n */\ncontract WOSonic is WOETH {\n constructor(ERC20 underlying_) WOETH(underlying_) {}\n\n function name()\n public\n view\n virtual\n override(WOETH)\n returns (string memory)\n {\n return \"Wrapped OS\";\n }\n\n function symbol()\n public\n view\n virtual\n override(WOETH)\n returns (string memory)\n {\n return \"wOS\";\n }\n}\n" + }, + "contracts/token/WrappedOusd.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { WOETH } from \"./WOETH.sol\";\n\n/**\n * @title Wrapped OUSD Token Contract\n * @author Origin Protocol Inc\n */\ncontract WrappedOusd is WOETH {\n constructor(ERC20 underlying_) WOETH(underlying_) {}\n\n function name()\n public\n view\n virtual\n override(WOETH)\n returns (string memory)\n {\n return \"Wrapped OUSD\";\n }\n\n function symbol()\n public\n view\n virtual\n override(WOETH)\n returns (string memory)\n {\n return \"WOUSD\";\n }\n}\n" + }, + "contracts/utils/BytesHelper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nuint256 constant UINT32_LENGTH = 4;\nuint256 constant UINT64_LENGTH = 8;\nuint256 constant UINT256_LENGTH = 32;\n// Address is 20 bytes, but we expect the data to be padded with 0s to 32 bytes\nuint256 constant ADDRESS_LENGTH = 32;\n\nlibrary BytesHelper {\n /**\n * @dev Extract a slice from bytes memory\n * @param data The bytes memory to slice\n * @param start The start index (inclusive)\n * @param end The end index (exclusive)\n * @return result A new bytes memory containing the slice\n */\n function extractSlice(\n bytes memory data,\n uint256 start,\n uint256 end\n ) internal pure returns (bytes memory) {\n require(end >= start, \"Invalid slice range\");\n require(end <= data.length, \"Slice end exceeds data length\");\n\n uint256 length = end - start;\n bytes memory result = new bytes(length);\n\n // Simple byte-by-byte copy\n for (uint256 i = 0; i < length; i++) {\n result[i] = data[start + i];\n }\n\n return result;\n }\n\n /**\n * @dev Decode a uint32 from a bytes memory\n * @param data The bytes memory to decode\n * @return uint32 The decoded uint32\n */\n function decodeUint32(bytes memory data) internal pure returns (uint32) {\n require(data.length == 4, \"Invalid data length\");\n return uint32(uint256(bytes32(data)) >> 224);\n }\n\n /**\n * @dev Extract a uint32 from a bytes memory\n * @param data The bytes memory to extract from\n * @param start The start index (inclusive)\n * @return uint32 The extracted uint32\n */\n function extractUint32(bytes memory data, uint256 start)\n internal\n pure\n returns (uint32)\n {\n return decodeUint32(extractSlice(data, start, start + UINT32_LENGTH));\n }\n\n /**\n * @dev Decode an address from a bytes memory.\n * Expects the data to be padded with 0s to 32 bytes.\n * @param data The bytes memory to decode\n * @return address The decoded address\n */\n function decodeAddress(bytes memory data) internal pure returns (address) {\n // We expect the data to be padded with 0s, so length is 32 not 20\n require(data.length == 32, \"Invalid data length\");\n return abi.decode(data, (address));\n }\n\n /**\n * @dev Extract an address from a bytes memory\n * @param data The bytes memory to extract from\n * @param start The start index (inclusive)\n * @return address The extracted address\n */\n function extractAddress(bytes memory data, uint256 start)\n internal\n pure\n returns (address)\n {\n return decodeAddress(extractSlice(data, start, start + ADDRESS_LENGTH));\n }\n\n /**\n * @dev Decode a uint256 from a bytes memory\n * @param data The bytes memory to decode\n * @return uint256 The decoded uint256\n */\n function decodeUint256(bytes memory data) internal pure returns (uint256) {\n require(data.length == 32, \"Invalid data length\");\n return abi.decode(data, (uint256));\n }\n\n /**\n * @dev Extract a uint256 from a bytes memory\n * @param data The bytes memory to extract from\n * @param start The start index (inclusive)\n * @return uint256 The extracted uint256\n */\n function extractUint256(bytes memory data, uint256 start)\n internal\n pure\n returns (uint256)\n {\n return decodeUint256(extractSlice(data, start, start + UINT256_LENGTH));\n }\n}\n" + }, + "contracts/utils/Helpers.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IBasicToken } from \"../interfaces/IBasicToken.sol\";\n\nlibrary Helpers {\n /**\n * @notice Fetch the `symbol()` from an ERC20 token\n * @dev Grabs the `symbol()` from a contract\n * @param _token Address of the ERC20 token\n * @return string Symbol of the ERC20 token\n */\n function getSymbol(address _token) internal view returns (string memory) {\n string memory symbol = IBasicToken(_token).symbol();\n return symbol;\n }\n\n /**\n * @notice Fetch the `decimals()` from an ERC20 token\n * @dev Grabs the `decimals()` from a contract and fails if\n * the decimal value does not live within a certain range\n * @param _token Address of the ERC20 token\n * @return uint256 Decimals of the ERC20 token\n */\n function getDecimals(address _token) internal view returns (uint256) {\n uint256 decimals = IBasicToken(_token).decimals();\n require(\n decimals >= 4 && decimals <= 18,\n \"Token must have sufficient decimal places\"\n );\n\n return decimals;\n }\n}\n" + }, + "contracts/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Base contract any contracts that need to initialize state after deployment.\n * @author Origin Protocol Inc\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private initializing;\n\n /**\n * @dev Modifier to protect an initializer function from being invoked twice.\n */\n modifier initializer() {\n require(\n initializing || !initialized,\n \"Initializable: contract is already initialized\"\n );\n\n bool isTopLevelCall = !initializing;\n if (isTopLevelCall) {\n initializing = true;\n initialized = true;\n }\n\n _;\n\n if (isTopLevelCall) {\n initializing = false;\n }\n }\n\n uint256[50] private ______gap;\n}\n" + }, + "contracts/utils/InitializableAbstractStrategy.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Base contract for vault strategies.\n * @author Origin Protocol Inc\n */\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nabstract contract InitializableAbstractStrategy is Initializable, Governable {\n using SafeERC20 for IERC20;\n\n event PTokenAdded(address indexed _asset, address _pToken);\n event PTokenRemoved(address indexed _asset, address _pToken);\n event Deposit(address indexed _asset, address _pToken, uint256 _amount);\n event Withdrawal(address indexed _asset, address _pToken, uint256 _amount);\n event RewardTokenCollected(\n address recipient,\n address rewardToken,\n uint256 amount\n );\n event RewardTokenAddressesUpdated(\n address[] _oldAddresses,\n address[] _newAddresses\n );\n event HarvesterAddressesUpdated(\n address _oldHarvesterAddress,\n address _newHarvesterAddress\n );\n\n /// @notice Address of the underlying platform\n address public immutable platformAddress;\n /// @notice Address of the OToken vault\n address public immutable vaultAddress;\n\n /// @dev Replaced with an immutable variable\n // slither-disable-next-line constable-states\n address private _deprecated_platformAddress;\n\n /// @dev Replaced with an immutable\n // slither-disable-next-line constable-states\n address private _deprecated_vaultAddress;\n\n /// @notice asset => pToken (Platform Specific Token Address)\n mapping(address => address) public assetToPToken;\n\n /// @notice Full list of all assets supported by the strategy\n address[] internal assetsMapped;\n\n // Deprecated: Reward token address\n // slither-disable-next-line constable-states\n address private _deprecated_rewardTokenAddress;\n\n // Deprecated: now resides in Harvester's rewardTokenConfigs\n // slither-disable-next-line constable-states\n uint256 private _deprecated_rewardLiquidationThreshold;\n\n /// @notice Address of the Harvester contract allowed to collect reward tokens\n address public harvesterAddress;\n\n /// @notice Address of the reward tokens. eg CRV, BAL, CVX, AURA\n address[] public rewardTokenAddresses;\n\n /* Reserved for future expansion. Used to be 100 storage slots\n * and has decreased to accommodate:\n * - harvesterAddress\n * - rewardTokenAddresses\n */\n int256[98] private _reserved;\n\n struct BaseStrategyConfig {\n address platformAddress; // Address of the underlying platform\n address vaultAddress; // Address of the OToken's Vault\n }\n\n /**\n * @dev Verifies that the caller is the Governor or Strategist.\n */\n modifier onlyGovernorOrStrategist() virtual {\n require(\n isGovernor() || msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n /**\n * @param _config The platform and OToken vault addresses\n */\n constructor(BaseStrategyConfig memory _config) {\n platformAddress = _config.platformAddress;\n vaultAddress = _config.vaultAddress;\n }\n\n /**\n * @dev Internal initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function _initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) internal {\n rewardTokenAddresses = _rewardTokenAddresses;\n\n uint256 assetCount = _assets.length;\n require(assetCount == _pTokens.length, \"Invalid input arrays\");\n for (uint256 i = 0; i < assetCount; ++i) {\n _setPTokenAddress(_assets[i], _pTokens[i]);\n }\n }\n\n /**\n * @notice Collect accumulated reward token and send to Vault.\n * No-ops when the harvester address is not set.\n */\n function collectRewardTokens()\n external\n virtual\n onlyHarvesterOrStrategist\n nonReentrant\n {\n if (harvesterAddress == address(0)) {\n return;\n }\n _collectRewardTokens();\n }\n\n /**\n * @dev Default implementation that transfers reward tokens to the Harvester.\n * Implementing strategies need to add custom logic to collect the rewards.\n */\n function _collectRewardTokens() internal virtual {\n if (harvesterAddress == address(0)) {\n return;\n }\n uint256 rewardTokenCount = rewardTokenAddresses.length;\n for (uint256 i = 0; i < rewardTokenCount; ++i) {\n IERC20 rewardToken = IERC20(rewardTokenAddresses[i]);\n uint256 balance = rewardToken.balanceOf(address(this));\n if (balance > 0) {\n emit RewardTokenCollected(\n harvesterAddress,\n address(rewardToken),\n balance\n );\n rewardToken.safeTransfer(harvesterAddress, balance);\n }\n }\n }\n\n /**\n * @dev Verifies that the caller is the Vault.\n */\n modifier onlyVault() {\n require(msg.sender == vaultAddress, \"Caller is not the Vault\");\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Harvester or Strategist.\n */\n modifier onlyHarvesterOrStrategist() {\n require(\n msg.sender == harvesterAddress ||\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Harvester or Strategist\"\n );\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Vault or Governor.\n */\n modifier onlyVaultOrGovernor() {\n require(\n msg.sender == vaultAddress || msg.sender == governor(),\n \"Caller is not the Vault or Governor\"\n );\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Vault, Governor, or Strategist.\n */\n modifier onlyVaultOrGovernorOrStrategist() {\n require(\n msg.sender == vaultAddress ||\n msg.sender == governor() ||\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Vault, Governor, or Strategist\"\n );\n _;\n }\n\n /**\n * @notice Set the reward token addresses. Any old addresses will be overwritten.\n * @param _rewardTokenAddresses Array of reward token addresses\n */\n function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\n external\n onlyGovernor\n {\n uint256 rewardTokenCount = _rewardTokenAddresses.length;\n for (uint256 i = 0; i < rewardTokenCount; ++i) {\n require(\n _rewardTokenAddresses[i] != address(0),\n \"Can not set an empty address as a reward token\"\n );\n }\n\n emit RewardTokenAddressesUpdated(\n rewardTokenAddresses,\n _rewardTokenAddresses\n );\n rewardTokenAddresses = _rewardTokenAddresses;\n }\n\n /**\n * @notice Get the reward token addresses.\n * @return address[] the reward token addresses.\n */\n function getRewardTokenAddresses()\n external\n view\n returns (address[] memory)\n {\n return rewardTokenAddresses;\n }\n\n /**\n * @notice Provide support for asset by passing its pToken address.\n * This method can only be called by the system Governor\n * @param _asset Address for the asset\n * @param _pToken Address for the corresponding platform token\n */\n function setPTokenAddress(address _asset, address _pToken)\n external\n virtual\n onlyGovernor\n {\n _setPTokenAddress(_asset, _pToken);\n }\n\n /**\n * @notice Remove a supported asset by passing its index.\n * This method can only be called by the system Governor\n * @param _assetIndex Index of the asset to be removed\n */\n function removePToken(uint256 _assetIndex) external virtual onlyGovernor {\n require(_assetIndex < assetsMapped.length, \"Invalid index\");\n address asset = assetsMapped[_assetIndex];\n address pToken = assetToPToken[asset];\n\n if (_assetIndex < assetsMapped.length - 1) {\n assetsMapped[_assetIndex] = assetsMapped[assetsMapped.length - 1];\n }\n assetsMapped.pop();\n assetToPToken[asset] = address(0);\n\n emit PTokenRemoved(asset, pToken);\n }\n\n /**\n * @notice Provide support for asset by passing its pToken address.\n * Add to internal mappings and execute the platform specific,\n * abstract method `_abstractSetPToken`\n * @param _asset Address for the asset\n * @param _pToken Address for the corresponding platform token\n */\n function _setPTokenAddress(address _asset, address _pToken) internal {\n require(assetToPToken[_asset] == address(0), \"pToken already set\");\n require(\n _asset != address(0) && _pToken != address(0),\n \"Invalid addresses\"\n );\n\n assetToPToken[_asset] = _pToken;\n assetsMapped.push(_asset);\n\n emit PTokenAdded(_asset, _pToken);\n\n _abstractSetPToken(_asset, _pToken);\n }\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * strategy contracts, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n public\n virtual\n onlyGovernor\n {\n require(!supportsAsset(_asset), \"Cannot transfer supported asset\");\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /**\n * @notice Set the Harvester contract that can collect rewards.\n * @param _harvesterAddress Address of the harvester contract.\n */\n function setHarvesterAddress(address _harvesterAddress)\n external\n onlyGovernorOrStrategist\n {\n emit HarvesterAddressesUpdated(harvesterAddress, _harvesterAddress);\n harvesterAddress = _harvesterAddress;\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n virtual;\n\n function safeApproveAllTokens() external virtual;\n\n /**\n * @notice Deposit an amount of assets into the platform\n * @param _asset Address for the asset\n * @param _amount Units of asset to deposit\n */\n function deposit(address _asset, uint256 _amount) external virtual;\n\n /**\n * @notice Deposit all supported assets in this strategy contract to the platform\n */\n function depositAll() external virtual;\n\n /**\n * @notice Withdraw an `amount` of assets from the platform and\n * send to the `_recipient`.\n * @param _recipient Address to which the asset should be sent\n * @param _asset Address of the asset\n * @param _amount Units of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external virtual;\n\n /**\n * @notice Withdraw all supported assets from platform and\n * sends to the OToken's Vault.\n */\n function withdrawAll() external virtual;\n\n /**\n * @notice Get the total asset value held in the platform.\n * This includes any interest that was generated since depositing.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n virtual\n returns (uint256 balance);\n\n /**\n * @notice Check if an asset is supported.\n * @param _asset Address of the asset\n * @return bool Whether asset is supported\n */\n function supportsAsset(address _asset) public view virtual returns (bool);\n}\n" + }, + "contracts/utils/PRBMath.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Copied from the PRBMath library\n// https://github.com/PaulRBerg/prb-math/blob/main/src/Common.sol\n\n/// @notice Calculates the square root of x using the Babylonian method.\n///\n/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n///\n/// Notes:\n/// - If x is not a perfect square, the result is rounded down.\n/// - Credits to OpenZeppelin for the explanations in comments below.\n///\n/// @param x The uint256 number for which to calculate the square root.\n/// @return result The result as a uint256.\n/// @custom:smtchecker abstract-function-nondet\nfunction sqrt(uint256 x) pure returns (uint256 result) {\n if (x == 0) {\n return 0;\n }\n\n // For our first guess, we calculate the biggest power of 2 which is smaller than the square root of x.\n //\n // We know that the \"msb\" (most significant bit) of x is a power of 2 such that we have:\n //\n // $$\n // msb(x) <= x <= 2*msb(x)$\n // $$\n //\n // We write $msb(x)$ as $2^k$, and we get:\n //\n // $$\n // k = log_2(x)\n // $$\n //\n // Thus, we can write the initial inequality as:\n //\n // $$\n // 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\\\\n // sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\\\\n // 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1}\n // $$\n //\n // Consequently, $2^{log_2(x) /2} is a good first approximation of sqrt(x) with at least one correct bit.\n uint256 xAux = uint256(x);\n result = 1;\n if (xAux >= 2**128) {\n xAux >>= 128;\n result <<= 64;\n }\n if (xAux >= 2**64) {\n xAux >>= 64;\n result <<= 32;\n }\n if (xAux >= 2**32) {\n xAux >>= 32;\n result <<= 16;\n }\n if (xAux >= 2**16) {\n xAux >>= 16;\n result <<= 8;\n }\n if (xAux >= 2**8) {\n xAux >>= 8;\n result <<= 4;\n }\n if (xAux >= 2**4) {\n xAux >>= 4;\n result <<= 2;\n }\n if (xAux >= 2**2) {\n result <<= 1;\n }\n\n // At this point, `result` is an estimation with at least one bit of precision. We know the true value has at\n // most 128 bits, since it is the square root of a uint256. Newton's method converges quadratically (precision\n // doubles at every iteration). We thus need at most 7 iteration to turn our partial result with one bit of\n // precision into the expected uint128 result.\n unchecked {\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n\n // If x is not a perfect square, round the result toward zero.\n uint256 roundedResult = x / result;\n if (result >= roundedResult) {\n result = roundedResult;\n }\n }\n}\n" + }, + "contracts/utils/StableMath.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\n// Based on StableMath from Stability Labs Pty. Ltd.\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\n\nlibrary StableMath {\n using SafeMath for uint256;\n\n /**\n * @dev Scaling unit for use in specific calculations,\n * where 1 * 10**18, or 1e18 represents a unit '1'\n */\n uint256 private constant FULL_SCALE = 1e18;\n\n /***************************************\n Helpers\n ****************************************/\n\n /**\n * @dev Adjust the scale of an integer\n * @param to Decimals to scale to\n * @param from Decimals to scale from\n */\n function scaleBy(\n uint256 x,\n uint256 to,\n uint256 from\n ) internal pure returns (uint256) {\n if (to > from) {\n x = x.mul(10**(to - from));\n } else if (to < from) {\n // slither-disable-next-line divide-before-multiply\n x = x.div(10**(from - to));\n }\n return x;\n }\n\n /***************************************\n Precise Arithmetic\n ****************************************/\n\n /**\n * @dev Multiplies two precise units, and then truncates by the full scale\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit\n */\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\n return mulTruncateScale(x, y, FULL_SCALE);\n }\n\n /**\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @param scale Scale unit\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit\n */\n function mulTruncateScale(\n uint256 x,\n uint256 y,\n uint256 scale\n ) internal pure returns (uint256) {\n // e.g. assume scale = fullScale\n // z = 10e18 * 9e17 = 9e36\n uint256 z = x.mul(y);\n // return 9e36 / 1e18 = 9e18\n return z.div(scale);\n }\n\n /**\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit, rounded up to the closest base unit.\n */\n function mulTruncateCeil(uint256 x, uint256 y)\n internal\n pure\n returns (uint256)\n {\n // e.g. 8e17 * 17268172638 = 138145381104e17\n uint256 scaled = x.mul(y);\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\n return ceil.div(FULL_SCALE);\n }\n\n /**\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\n * @param x Left hand input to division\n * @param y Right hand input to division\n * @return Result after multiplying the left operand by the scale, and\n * executing the division on the right hand input.\n */\n function divPrecisely(uint256 x, uint256 y)\n internal\n pure\n returns (uint256)\n {\n // e.g. 8e18 * 1e18 = 8e36\n uint256 z = x.mul(FULL_SCALE);\n // e.g. 8e36 / 10e18 = 8e17\n return z.div(y);\n }\n}\n" + }, + "contracts/vault/OETHBaseVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OETH Base VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OETHBaseVault is VaultAdmin {\n constructor(address _weth) VaultAdmin(_weth) {}\n}\n" + }, + "contracts/vault/OETHPlumeVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OETH Plume VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OETHPlumeVault is VaultAdmin {\n constructor(address _weth) VaultAdmin(_weth) {}\n\n // @inheritdoc VaultAdmin\n function _mint(\n address,\n uint256 _amount,\n uint256\n ) internal virtual {\n // Only Strategist or Governor can mint using the Vault for now.\n // This allows the strateigst to fund the Vault with WETH when\n // removing liquidi from wOETH strategy.\n require(\n msg.sender == strategistAddr || isGovernor(),\n \"Caller is not the Strategist or Governor\"\n );\n\n super._mint(_amount);\n }\n}\n" + }, + "contracts/vault/OETHVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OETH VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OETHVault is VaultAdmin {\n constructor(address _weth) VaultAdmin(_weth) {}\n}\n" + }, + "contracts/vault/OSVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title Origin Sonic VaultAdmin contract on Sonic\n * @author Origin Protocol Inc\n */\ncontract OSVault is VaultAdmin {\n constructor(address _wS) VaultAdmin(_wS) {}\n}\n" + }, + "contracts/vault/OUSDVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OUSD VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OUSDVault is VaultAdmin {\n constructor(address _usdc) VaultAdmin(_usdc) {}\n}\n" + }, + "contracts/vault/VaultAdmin.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultAdmin contract\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\n * @author Origin Protocol Inc\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport \"./VaultCore.sol\";\n\nabstract contract VaultAdmin is VaultCore {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n using SafeCast for uint256;\n\n /**\n * @dev Verifies that the caller is the Governor or Strategist.\n */\n modifier onlyGovernorOrStrategist() {\n require(\n msg.sender == strategistAddr || isGovernor(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n constructor(address _asset) VaultCore(_asset) {}\n\n /***************************************\n Configuration\n ****************************************/\n /**\n * @notice Set a buffer of asset to keep in the Vault to handle most\n * redemptions without needing to spend gas unwinding asset from a Strategy.\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\n */\n function setVaultBuffer(uint256 _vaultBuffer)\n external\n onlyGovernorOrStrategist\n {\n require(_vaultBuffer <= 1e18, \"Invalid value\");\n vaultBuffer = _vaultBuffer;\n emit VaultBufferUpdated(_vaultBuffer);\n }\n\n /**\n * @notice Sets the minimum amount of OTokens in a mint to trigger an\n * automatic allocation of funds afterwords.\n * @param _threshold OToken amount with 18 fixed decimals.\n */\n function setAutoAllocateThreshold(uint256 _threshold)\n external\n onlyGovernor\n {\n autoAllocateThreshold = _threshold;\n emit AllocateThresholdUpdated(_threshold);\n }\n\n /**\n * @notice Set address of Strategist\n * @param _address Address of Strategist\n */\n function setStrategistAddr(address _address) external onlyGovernor {\n strategistAddr = _address;\n emit StrategistUpdated(_address);\n }\n\n /**\n * @notice Set the address authorized to call `rebase()`.\n * @param _operator New operator address. May be set to the zero address\n * to disable operator-initiated rebases.\n */\n function setOperatorAddr(address _operator) external onlyGovernor {\n operatorAddr = _operator;\n emit OperatorUpdated(_operator);\n }\n\n /**\n * @notice Set the default Strategy for asset, i.e. the one which\n * the asset will be automatically allocated to and withdrawn from\n * @param _strategy Address of the Strategy\n */\n function setDefaultStrategy(address _strategy)\n external\n onlyGovernorOrStrategist\n {\n emit DefaultStrategyUpdated(_strategy);\n // If its a zero address being passed for the strategy we are removing\n // the default strategy\n if (_strategy != address(0)) {\n // Make sure the strategy meets some criteria\n require(strategies[_strategy].isSupported, \"Strategy not approved\");\n require(\n IStrategy(_strategy).supportsAsset(asset),\n \"Asset not supported by Strategy\"\n );\n }\n defaultStrategy = _strategy;\n }\n\n /**\n * @notice Changes the async withdrawal claim period for OETH & superOETHb\n * @param _delay Delay period (should be between 10 mins to 7 days).\n * Set to 0 to disable async withdrawals\n */\n function setWithdrawalClaimDelay(uint256 _delay) external onlyGovernor {\n require(\n _delay == 0 || (_delay >= 10 minutes && _delay <= 15 days),\n \"Invalid claim delay period\"\n );\n withdrawalClaimDelay = _delay;\n emit WithdrawalClaimDelayUpdated(_delay);\n }\n\n // slither-disable-start reentrancy-no-eth\n /**\n * @notice Set a yield streaming max rate. This spreads yield over\n * time if it is above the max rate. This is a per rebase APR which\n * due to compounding differs from the yearly APR. Governance should\n * consider this fact when picking a desired APR\n * @param apr in 1e18 notation. 3 * 1e18 = 3% APR\n */\n function setRebaseRateMax(uint256 apr) external onlyGovernorOrStrategist {\n // The old yield will be at the old rate\n _rebase();\n // Change the rate\n uint256 newPerSecond = apr / 100 / 365 days;\n require(newPerSecond <= MAX_REBASE_PER_SECOND, \"Rate too high\");\n rebasePerSecondMax = newPerSecond.toUint64();\n emit RebasePerSecondMaxChanged(newPerSecond);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n // slither-disable-start reentrancy-no-eth\n /**\n * @notice Set the drip duration period\n * @param _dripDuration Time in seconds to target a constant yield rate\n */\n function setDripDuration(uint256 _dripDuration)\n external\n onlyGovernorOrStrategist\n {\n // The old yield will be at the old rate\n _rebase();\n dripDuration = _dripDuration.toUint64();\n emit DripDurationChanged(_dripDuration);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /***************************************\n Strategy Config\n ****************************************/\n\n /**\n * @notice Add a strategy to the Vault.\n * @param _addr Address of the strategy to add\n */\n function approveStrategy(address _addr) external onlyGovernor {\n require(!strategies[_addr].isSupported, \"Strategy already approved\");\n require(\n IStrategy(_addr).supportsAsset(asset),\n \"Asset not supported by Strategy\"\n );\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\n allStrategies.push(_addr);\n emit StrategyApproved(_addr);\n }\n\n /**\n * @notice Remove a strategy from the Vault.\n * @param _addr Address of the strategy to remove\n */\n\n function removeStrategy(address _addr) external onlyGovernor {\n require(strategies[_addr].isSupported, \"Strategy not approved\");\n require(defaultStrategy != _addr, \"Strategy is default for asset\");\n\n // Initialize strategyIndex with out of bounds result so function will\n // revert if no valid index found\n uint256 stratCount = allStrategies.length;\n uint256 strategyIndex = stratCount;\n for (uint256 i = 0; i < stratCount; ++i) {\n if (allStrategies[i] == _addr) {\n strategyIndex = i;\n break;\n }\n }\n\n if (strategyIndex < stratCount) {\n allStrategies[strategyIndex] = allStrategies[stratCount - 1];\n allStrategies.pop();\n\n // Withdraw all assets BEFORE marking as unsupported so that AMO\n // strategies can call burnForStrategy/mintForStrategy during withdrawAll\n IStrategy strategy = IStrategy(_addr);\n // slither-disable-next-line reentrancy-no-eth\n strategy.withdrawAll();\n\n // Mark the strategy as not supported\n strategies[_addr].isSupported = false;\n isMintWhitelistedStrategy[_addr] = false;\n\n // 1e13 for 18 decimals. And 1e1(10) for 6 decimals\n uint256 maxDustBalance = uint256(1e13).scaleBy(assetDecimals, 18);\n\n /*\n * Some strategies are not able to withdraw all of their funds in a synchronous call.\n * Prevent the possible accidental removal of such strategies before their funds are withdrawn.\n */\n require(\n strategy.checkBalance(asset) < maxDustBalance,\n \"Strategy has funds\"\n );\n emit StrategyRemoved(_addr);\n }\n }\n\n /**\n * @notice Adds a strategy to the mint whitelist.\n * Reverts if strategy isn't approved on Vault.\n * @param strategyAddr Strategy address\n */\n function addStrategyToMintWhitelist(address strategyAddr)\n external\n onlyGovernor\n {\n require(strategies[strategyAddr].isSupported, \"Strategy not approved\");\n\n require(\n !isMintWhitelistedStrategy[strategyAddr],\n \"Already whitelisted\"\n );\n\n isMintWhitelistedStrategy[strategyAddr] = true;\n\n emit StrategyAddedToMintWhitelist(strategyAddr);\n }\n\n /**\n * @notice Removes a strategy from the mint whitelist.\n * @param strategyAddr Strategy address\n */\n function removeStrategyFromMintWhitelist(address strategyAddr)\n external\n onlyGovernor\n {\n // Intentionally skipping `strategies.isSupported` check since\n // we may wanna remove an address even after removing the strategy\n\n require(isMintWhitelistedStrategy[strategyAddr], \"Not whitelisted\");\n\n isMintWhitelistedStrategy[strategyAddr] = false;\n\n emit StrategyRemovedFromMintWhitelist(strategyAddr);\n }\n\n /***************************************\n Strategies\n ****************************************/\n\n /**\n * @notice Deposit multiple asset from the vault into the strategy.\n * @param _strategyToAddress Address of the Strategy to deposit asset into.\n * @param _assets Array of asset address that will be deposited into the strategy.\n * @param _amounts Array of amounts of each corresponding asset to deposit.\n */\n function depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external onlyGovernorOrStrategist nonReentrant {\n _depositToStrategy(_strategyToAddress, _assets, _amounts);\n }\n\n function _depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) internal virtual {\n require(\n strategies[_strategyToAddress].isSupported,\n \"Invalid to Strategy\"\n );\n require(\n _assets.length == 1 && _amounts.length == 1 && _assets[0] == asset,\n \"Only asset is supported\"\n );\n\n // Check the there is enough asset to transfer once the backing\n // asset reserved for the withdrawal queue is accounted for\n require(\n _amounts[0] <= _assetAvailable(),\n \"Not enough assets available\"\n );\n\n // Send required amount of funds to the strategy\n IERC20(asset).safeTransfer(_strategyToAddress, _amounts[0]);\n\n // Deposit all the funds that have been sent to the strategy\n IStrategy(_strategyToAddress).depositAll();\n }\n\n /**\n * @notice Withdraw multiple asset from the strategy to the vault.\n * @param _strategyFromAddress Address of the Strategy to withdraw asset from.\n * @param _assets Array of asset address that will be withdrawn from the strategy.\n * @param _amounts Array of amounts of each corresponding asset to withdraw.\n */\n function withdrawFromStrategy(\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external onlyGovernorOrStrategist nonReentrant {\n _withdrawFromStrategy(\n address(this),\n _strategyFromAddress,\n _assets,\n _amounts\n );\n }\n\n /**\n * @param _recipient can either be a strategy or the Vault\n */\n function _withdrawFromStrategy(\n address _recipient,\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) internal virtual {\n require(\n strategies[_strategyFromAddress].isSupported,\n \"Invalid from Strategy\"\n );\n require(_assets.length == _amounts.length, \"Parameter length mismatch\");\n\n uint256 assetCount = _assets.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n // Withdraw from Strategy to the recipient\n IStrategy(_strategyFromAddress).withdraw(\n _recipient,\n _assets[i],\n _amounts[i]\n );\n }\n\n _addWithdrawalQueueLiquidity();\n }\n\n /**\n * @notice Sets the maximum allowable difference between\n * total supply and asset' value.\n */\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\n maxSupplyDiff = _maxSupplyDiff;\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\n }\n\n /**\n * @notice Sets the trusteeAddress that can receive a portion of yield.\n * Setting to the zero address disables this feature.\n */\n function setTrusteeAddress(address _address) external onlyGovernor {\n trusteeAddress = _address;\n emit TrusteeAddressChanged(_address);\n }\n\n /**\n * @notice Sets the TrusteeFeeBps to the percentage of yield that should be\n * received in basis points.\n */\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\n require(_basis <= 5000, \"basis cannot exceed 50%\");\n trusteeFeeBps = _basis;\n emit TrusteeFeeBpsChanged(_basis);\n }\n\n /***************************************\n Pause\n ****************************************/\n\n /**\n * @notice Set the deposit paused flag to true to prevent rebasing.\n */\n function pauseRebase() external onlyGovernorOrStrategist {\n rebasePaused = true;\n emit RebasePaused();\n }\n\n /**\n * @notice Set the deposit paused flag to true to allow rebasing.\n */\n function unpauseRebase() external onlyGovernorOrStrategist {\n rebasePaused = false;\n emit RebaseUnpaused();\n }\n\n /**\n * @notice Set the deposit paused flag to true to prevent capital movement.\n */\n function pauseCapital() external onlyGovernorOrStrategist {\n capitalPaused = true;\n emit CapitalPaused();\n }\n\n /**\n * @notice Set the deposit paused flag to false to enable capital movement.\n */\n function unpauseCapital() external onlyGovernorOrStrategist {\n capitalPaused = false;\n emit CapitalUnpaused();\n }\n\n /***************************************\n Utils\n ****************************************/\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n require(asset != _asset, \"Only unsupported asset\");\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /***************************************\n Strategies Admin\n ****************************************/\n\n /**\n * @notice Withdraws all asset from the strategy and sends asset to the Vault.\n * @param _strategyAddr Strategy address.\n */\n function withdrawAllFromStrategy(address _strategyAddr)\n external\n onlyGovernorOrStrategist\n {\n _withdrawAllFromStrategy(_strategyAddr);\n }\n\n function _withdrawAllFromStrategy(address _strategyAddr) internal virtual {\n require(\n strategies[_strategyAddr].isSupported,\n \"Strategy is not supported\"\n );\n IStrategy strategy = IStrategy(_strategyAddr);\n strategy.withdrawAll();\n _addWithdrawalQueueLiquidity();\n }\n\n /**\n * @notice Withdraws all asset from all the strategies and sends asset to the Vault.\n */\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\n _withdrawAllFromStrategies();\n }\n\n function _withdrawAllFromStrategies() internal virtual {\n uint256 stratCount = allStrategies.length;\n for (uint256 i = 0; i < stratCount; ++i) {\n IStrategy(allStrategies[i]).withdrawAll();\n }\n _addWithdrawalQueueLiquidity();\n }\n}\n" + }, + "contracts/vault/VaultCore.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultCore contract\n * @notice The Vault contract stores asset. On a deposit, OTokens will be minted\n and sent to the depositor. On a withdrawal, OTokens will be burned and\n asset will be sent to the withdrawer. The Vault accepts deposits of\n interest from yield bearing strategies which will modify the supply\n of OTokens.\n * @author Origin Protocol Inc\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\n\nimport \"./VaultInitializer.sol\";\n\nabstract contract VaultCore is VaultInitializer {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n /**\n * @dev Verifies that the rebasing is not paused.\n */\n modifier whenNotRebasePaused() {\n require(!rebasePaused, \"Rebasing paused\");\n _;\n }\n\n /**\n * @dev Verifies that the deposits are not paused.\n */\n modifier whenNotCapitalPaused() {\n require(!capitalPaused, \"Capital paused\");\n _;\n }\n\n constructor(address _asset) VaultInitializer(_asset) {}\n\n ////////////////////////////////////////////////////\n /// MINT / BURN ///\n ////////////////////////////////////////////////////\n /**\n * @notice Deposit a supported asset and mint OTokens.\n * @dev Deprecated: use `mint(uint256 _amount)` instead.\n * @dev Deprecated: param _asset Address of the asset being deposited\n * @param _amount Amount of the asset being deposited\n * @dev Deprecated: param _minimumOusdAmount Minimum OTokens to mint\n */\n function mint(\n address,\n uint256 _amount,\n uint256\n ) external whenNotCapitalPaused nonReentrant {\n _mint(_amount);\n }\n\n /**\n * @notice Deposit a supported asset and mint OTokens.\n * @param _amount Amount of the asset being deposited\n */\n function mint(uint256 _amount) external whenNotCapitalPaused nonReentrant {\n _mint(_amount);\n }\n\n // slither-disable-start reentrancy-no-eth\n /**\n * @dev Deposit a supported asset and mint OTokens.\n * @param _amount Amount of the asset being deposited\n */\n function _mint(uint256 _amount) internal virtual {\n require(_amount > 0, \"Amount must be greater than 0\");\n\n // Scale amount to 18 decimals\n uint256 scaledAmount = _amount.scaleBy(18, assetDecimals);\n\n emit Mint(msg.sender, scaledAmount);\n\n // Mint oTokens\n oToken.mint(msg.sender, scaledAmount);\n\n IERC20(asset).safeTransferFrom(msg.sender, address(this), _amount);\n\n // Give priority to the withdrawal queue for the new asset liquidity\n _addWithdrawalQueueLiquidity();\n\n // Auto-allocate if necessary\n if (scaledAmount >= autoAllocateThreshold) {\n _allocate();\n }\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /**\n * @notice Mint OTokens for an allowed Strategy\n * @param _amount Amount of OToken to mint\n *\n * Notice: can't use `nonReentrant` modifier since the `mint` function can\n * call `allocate`, and that can trigger an AMO strategy to call this function\n * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision.\n *\n * Also important to understand is that this is a limitation imposed by the test suite.\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\n * that are moving funds between the Vault and end user wallets can influence strategies\n * utilizing this function.\n */\n function mintForStrategy(uint256 _amount)\n external\n virtual\n whenNotCapitalPaused\n {\n require(\n strategies[msg.sender].isSupported == true,\n \"Unsupported strategy\"\n );\n require(\n isMintWhitelistedStrategy[msg.sender] == true,\n \"Not whitelisted strategy\"\n );\n\n emit Mint(msg.sender, _amount);\n // Mint matching amount of OTokens\n oToken.mint(msg.sender, _amount);\n }\n\n /**\n * @notice Burn OTokens for an allowed Strategy\n * @param _amount Amount of OToken to burn\n *\n * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could\n * require withdrawal on an AMO strategy and that one can call `burnForStrategy`\n * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision.\n *\n * Also important to understand is that this is a limitation imposed by the test suite.\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\n * that are moving funds between the Vault and end user wallets can influence strategies\n * utilizing this function.\n */\n function burnForStrategy(uint256 _amount)\n external\n virtual\n whenNotCapitalPaused\n {\n require(\n strategies[msg.sender].isSupported == true,\n \"Unsupported strategy\"\n );\n require(\n isMintWhitelistedStrategy[msg.sender] == true,\n \"Not whitelisted strategy\"\n );\n\n emit Redeem(msg.sender, _amount);\n\n // Burn OTokens\n oToken.burn(msg.sender, _amount);\n }\n\n ////////////////////////////////////////////////////\n /// ASYNC WITHDRAWALS ///\n ////////////////////////////////////////////////////\n /**\n * @notice Request an asynchronous withdrawal of asset in exchange for OToken.\n * The OToken is burned on request and the asset is transferred to the withdrawer on claim.\n * This request can be claimed once the withdrawal queue's `claimable` amount\n * is greater than or equal this request's `queued` amount.\n * There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs\n * enough asset liquidity in the Vault to satisfy all the outstanding requests to that point in the queue.\n * OToken is converted to asset at 1:1.\n * @param _amount Amount of OToken to burn.\n * @return requestId Unique ID for the withdrawal request\n * @return queued Cumulative total of all asset queued including already claimed requests.\n */\n function requestWithdrawal(uint256 _amount)\n external\n virtual\n whenNotCapitalPaused\n nonReentrant\n returns (uint256 requestId, uint256 queued)\n {\n require(_amount > 0, \"Amount must be greater than 0\");\n require(withdrawalClaimDelay > 0, \"Async withdrawals not enabled\");\n\n // The check that the requester has enough OToken is done in to later burn call\n\n requestId = withdrawalQueueMetadata.nextWithdrawalIndex;\n queued =\n withdrawalQueueMetadata.queued +\n _amount.scaleBy(assetDecimals, 18);\n\n // Store the next withdrawal request\n withdrawalQueueMetadata.nextWithdrawalIndex = SafeCast.toUint128(\n requestId + 1\n );\n // Store the updated queued amount which reserves asset in the withdrawal queue\n // and reduces the vault's total asset\n withdrawalQueueMetadata.queued = SafeCast.toUint128(queued);\n // Store the user's withdrawal request\n // `queued` is in asset decimals, while `amount` is in OToken decimals (18)\n withdrawalRequests[requestId] = WithdrawalRequest({\n withdrawer: msg.sender,\n claimed: false,\n timestamp: uint40(block.timestamp),\n amount: SafeCast.toUint128(_amount),\n queued: SafeCast.toUint128(queued)\n });\n\n // Burn the user's OToken\n oToken.burn(msg.sender, _amount);\n\n // Prevent withdrawal if the vault is solvent by more than the allowed percentage\n _postRedeem();\n\n emit WithdrawalRequested(msg.sender, requestId, _amount, queued);\n }\n\n // slither-disable-start reentrancy-no-eth\n /**\n * @notice Claim a previously requested withdrawal once it is claimable.\n * This request can be claimed once the withdrawal queue's `claimable` amount\n * is greater than or equal this request's `queued` amount and 10 minutes has passed.\n * If the requests is not claimable, the transaction will revert with `Queue pending liquidity`.\n * If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`.\n * OToken is converted to asset at 1:1.\n * @param _requestId Unique ID for the withdrawal request\n * @return amount Amount of asset transferred to the withdrawer\n */\n function claimWithdrawal(uint256 _requestId)\n external\n virtual\n whenNotCapitalPaused\n nonReentrant\n returns (uint256 amount)\n {\n // Try and get more liquidity if there is not enough available\n if (\n withdrawalRequests[_requestId].queued >\n withdrawalQueueMetadata.claimable\n ) {\n // Add any asset to the withdrawal queue\n // this needs to remain here as:\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\n // - funds can be withdrawn from a strategy\n //\n // Those funds need to be added to withdrawal queue liquidity\n _addWithdrawalQueueLiquidity();\n }\n\n // Scale amount to asset decimals\n amount = _claimWithdrawal(_requestId);\n\n // transfer asset from the vault to the withdrawer\n IERC20(asset).safeTransfer(msg.sender, amount);\n\n // Prevent insolvency\n _postRedeem();\n }\n\n // slither-disable-end reentrancy-no-eth\n /**\n * @notice Claim a previously requested withdrawals once they are claimable.\n * This requests can be claimed once the withdrawal queue's `claimable` amount\n * is greater than or equal each request's `queued` amount and 10 minutes has passed.\n * If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`.\n * If one of the requests is not older than 10 minutes,\n * the whole transaction will revert with `Claim delay not met`.\n * @param _requestIds Unique ID of each withdrawal request\n * @return amounts Amount of asset received for each request\n * @return totalAmount Total amount of asset transferred to the withdrawer\n */\n function claimWithdrawals(uint256[] calldata _requestIds)\n external\n virtual\n whenNotCapitalPaused\n nonReentrant\n returns (uint256[] memory amounts, uint256 totalAmount)\n {\n // Add any asset to the withdrawal queue\n // this needs to remain here as:\n // - Vault can be funded and `addWithdrawalQueueLiquidity` is not externally called\n // - funds can be withdrawn from a strategy\n //\n // Those funds need to be added to withdrawal queue liquidity\n _addWithdrawalQueueLiquidity();\n\n amounts = new uint256[](_requestIds.length);\n for (uint256 i; i < _requestIds.length; ++i) {\n // Scale all amounts to asset decimals, thus totalAmount is also in asset decimals\n amounts[i] = _claimWithdrawal(_requestIds[i]);\n totalAmount += amounts[i];\n }\n\n // transfer all the claimed asset from the vault to the withdrawer\n IERC20(asset).safeTransfer(msg.sender, totalAmount);\n\n // Prevent insolvency\n _postRedeem();\n\n return (amounts, totalAmount);\n }\n\n function _claimWithdrawal(uint256 requestId)\n internal\n returns (uint256 amount)\n {\n require(withdrawalClaimDelay > 0, \"Async withdrawals not enabled\");\n\n // Load the structs from storage into memory\n WithdrawalRequest memory request = withdrawalRequests[requestId];\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n require(\n request.timestamp + withdrawalClaimDelay <= block.timestamp,\n \"Claim delay not met\"\n );\n // If there isn't enough reserved liquidity in the queue to claim\n require(request.queued <= queue.claimable, \"Queue pending liquidity\");\n require(request.withdrawer == msg.sender, \"Not requester\");\n require(request.claimed == false, \"Already claimed\");\n\n // Store the request as claimed\n withdrawalRequests[requestId].claimed = true;\n // Store the updated claimed amount\n withdrawalQueueMetadata.claimed =\n queue.claimed +\n SafeCast.toUint128(\n StableMath.scaleBy(request.amount, assetDecimals, 18)\n );\n\n emit WithdrawalClaimed(msg.sender, requestId, request.amount);\n\n return StableMath.scaleBy(request.amount, assetDecimals, 18);\n }\n\n function _postRedeem() internal view {\n // Until we can prove that we won't affect the prices of our asset\n // by withdrawing them, this should be here.\n // It's possible that a strategy was off on its asset total, perhaps\n // a reward token sold for more or for less than anticipated.\n uint256 totalUnits = _totalValue();\n\n // Check that the OTokens are backed by enough asset\n if (maxSupplyDiff > 0) {\n // If there are more outstanding withdrawal requests than asset in the vault and strategies\n // then the available asset will be negative and totalUnits will be rounded up to zero.\n // As we don't know the exact shortfall amount, we will reject all redeem and withdrawals\n require(totalUnits > 0, \"Too many outstanding requests\");\n\n // Allow a max difference of maxSupplyDiff% between\n // asset value and OUSD total supply\n uint256 diff = oToken.totalSupply().divPrecisely(totalUnits);\n require(\n (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,\n \"Backing supply liquidity error\"\n );\n }\n }\n\n /**\n * @notice Allocate unallocated funds on Vault to strategies.\n */\n function allocate() external virtual whenNotCapitalPaused nonReentrant {\n // Add any unallocated asset to the withdrawal queue first\n _addWithdrawalQueueLiquidity();\n\n _allocate();\n }\n\n /**\n * @dev Allocate asset (eg. WETH or USDC) to the default asset strategy\n * if there is excess to the Vault buffer.\n * This is called from either `mint` or `allocate` and assumes `_addWithdrawalQueueLiquidity`\n * has been called before this function.\n */\n function _allocate() internal virtual {\n // No need to do anything if no default strategy for asset\n address depositStrategyAddr = defaultStrategy;\n if (depositStrategyAddr == address(0)) return;\n\n uint256 assetAvailableInVault = _assetAvailable();\n // No need to do anything if there isn't any asset in the vault to allocate\n if (assetAvailableInVault == 0) return;\n\n // Calculate the target buffer for the vault using the total supply\n uint256 totalSupply = oToken.totalSupply();\n // Scaled to asset decimals\n uint256 targetBuffer = totalSupply.mulTruncate(vaultBuffer).scaleBy(\n assetDecimals,\n 18\n );\n\n // If available asset in the Vault is below or equal the target buffer then there's nothing to allocate\n if (assetAvailableInVault <= targetBuffer) return;\n\n // The amount of asset to allocate to the default strategy\n uint256 allocateAmount = assetAvailableInVault - targetBuffer;\n\n IStrategy strategy = IStrategy(depositStrategyAddr);\n // Transfer asset to the strategy and call the strategy's deposit function\n IERC20(asset).safeTransfer(address(strategy), allocateAmount);\n strategy.deposit(asset, allocateAmount);\n\n emit AssetAllocated(asset, depositStrategyAddr, allocateAmount);\n }\n\n /**\n * @notice Calculate the total value of asset held by the Vault and all\n * strategies and update the supply of OTokens.\n * @dev Restricted to the Operator, Strategist or Governor.\n */\n function rebase() external virtual nonReentrant {\n require(\n msg.sender == operatorAddr ||\n msg.sender == strategistAddr ||\n isGovernor(),\n \"Caller not authorized\"\n );\n _rebase();\n }\n\n /**\n * @dev Calculate the total value of asset held by the Vault and all\n * strategies and update the supply of OTokens, optionally sending a\n * portion of the yield to the trustee.\n * @return totalUnits Total balance of Vault in units\n */\n function _rebase() internal whenNotRebasePaused returns (uint256) {\n uint256 supply = oToken.totalSupply();\n uint256 vaultValue = _totalValue();\n // If no supply yet, do not rebase\n if (supply == 0) {\n return vaultValue;\n }\n\n // Calculate yield and new supply\n (uint256 yield, uint256 targetRate) = _nextYield(supply, vaultValue);\n uint256 newSupply = supply + yield;\n // Only rebase upwards and if we have enough backing funds\n if (newSupply <= supply || newSupply > vaultValue) {\n return vaultValue;\n }\n\n rebasePerSecondTarget = uint64(_min(targetRate, type(uint64).max));\n lastRebase = uint64(block.timestamp); // Intentional cast\n\n // Fee collection on yield\n address _trusteeAddress = trusteeAddress; // gas savings\n uint256 fee = 0;\n if (_trusteeAddress != address(0)) {\n fee = (yield * trusteeFeeBps) / 1e4;\n if (fee > 0) {\n require(fee < yield, \"Fee must not be greater than yield\");\n oToken.mint(_trusteeAddress, fee);\n }\n }\n emit YieldDistribution(_trusteeAddress, yield, fee);\n\n // Only ratchet OToken supply upwards\n // Final check uses latest totalSupply\n if (newSupply > oToken.totalSupply()) {\n oToken.changeSupply(newSupply);\n }\n return vaultValue;\n }\n\n /**\n * @notice Calculates the amount that would rebase at next rebase.\n * This is before any fees.\n * @return yield amount of expected yield\n */\n function previewYield() external view returns (uint256 yield) {\n (yield, ) = _nextYield(oToken.totalSupply(), _totalValue());\n return yield;\n }\n\n /**\n * @dev Calculates the amount that would rebase at next rebase.\n * See this Readme for detailed explanation:\n * contracts/contracts/vault/README - Yield Limits.md\n */\n function _nextYield(uint256 supply, uint256 vaultValue)\n internal\n view\n virtual\n returns (uint256 yield, uint256 targetRate)\n {\n uint256 nonRebasing = oToken.nonRebasingSupply();\n uint256 rebasing = supply - nonRebasing;\n uint256 elapsed = block.timestamp - lastRebase;\n targetRate = rebasePerSecondTarget;\n\n if (\n elapsed == 0 || // Yield only once per block.\n rebasing == 0 || // No yield if there are no rebasing tokens to give it to.\n supply > vaultValue || // No yield if we do not have yield to give.\n block.timestamp >= type(uint64).max // No yield if we are too far in the future to calculate it correctly.\n ) {\n return (0, targetRate);\n }\n\n // Start with the full difference available\n yield = vaultValue - supply;\n\n // Cap via optional automatic duration smoothing\n uint256 _dripDuration = dripDuration;\n if (_dripDuration > 1) {\n // If we are able to sustain an increased drip rate for\n // double the duration, then increase the target drip rate\n targetRate = _max(targetRate, yield / (_dripDuration * 2));\n // If we cannot sustain the target rate any more,\n // then rebase what we can, and reduce the target\n targetRate = _min(targetRate, yield / _dripDuration);\n // drip at the new target rate\n yield = _min(yield, targetRate * elapsed);\n }\n\n // Cap per second. elapsed is not 1e18 denominated\n yield = _min(yield, (rebasing * elapsed * rebasePerSecondMax) / 1e18);\n\n // Cap at a hard max per rebase, to avoid long durations resulting in huge rebases\n yield = _min(yield, (rebasing * MAX_REBASE) / 1e18);\n\n return (yield, targetRate);\n }\n\n /**\n * @notice Determine the total value of asset held by the vault and its\n * strategies.\n * @return value Total value in USD/ETH (1e18)\n */\n function totalValue() external view virtual returns (uint256 value) {\n value = _totalValue();\n }\n\n /**\n * @dev Internal Calculate the total value of the asset held by the\n * vault and its strategies.\n * @dev The total value of all WETH held by the vault and all its strategies\n * less any WETH that is reserved for the withdrawal queue.\n * If there is not enough WETH in the vault and all strategies to cover\n * all outstanding withdrawal requests then return a total value of 0.\n * @return value Total value in USD/ETH (1e18)\n */\n function _totalValue() internal view virtual returns (uint256 value) {\n // As asset is the only asset, just return the asset balance\n value = _checkBalance(asset).scaleBy(18, assetDecimals);\n }\n\n /**\n * @notice Get the balance of an asset held in Vault and all strategies.\n * @param _asset Address of asset\n * @return uint256 Balance of asset in decimals of asset\n */\n function checkBalance(address _asset) external view returns (uint256) {\n return _checkBalance(_asset);\n }\n\n /**\n * @notice Get the balance of an asset held in Vault and all strategies.\n * @dev Get the balance of an asset held in Vault and all strategies\n * less any asset that is reserved for the withdrawal queue.\n * BaseAsset is the only asset that can return a non-zero balance.\n * All other asset will return 0 even if there is some dust amounts left in the Vault.\n * For example, there is 1 wei left of stETH (or USDC) in the OETH (or OUSD) Vault but\n * will return 0 in this function.\n *\n * If there is not enough asset in the vault and all strategies to cover all outstanding\n * withdrawal requests then return a asset balance of 0\n * @param _asset Address of asset\n * @return balance Balance of asset in decimals of asset\n */\n function _checkBalance(address _asset)\n internal\n view\n virtual\n returns (uint256 balance)\n {\n if (_asset != asset) return 0;\n\n // Get the asset in the vault and the strategies\n IERC20 asset = IERC20(_asset);\n balance = asset.balanceOf(address(this));\n uint256 stratCount = allStrategies.length;\n for (uint256 i = 0; i < stratCount; ++i) {\n IStrategy strategy = IStrategy(allStrategies[i]);\n if (strategy.supportsAsset(_asset)) {\n balance = balance + strategy.checkBalance(_asset);\n }\n }\n\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // If the vault becomes insolvent enough that the total value in the vault and all strategies\n // is less than the outstanding withdrawals.\n // For example, there was a mass slashing event and most users request a withdrawal.\n if (balance + queue.claimed < queue.queued) {\n return 0;\n }\n\n // Need to remove asset that is reserved for the withdrawal queue\n return balance + queue.claimed - queue.queued;\n }\n\n /**\n * @notice Adds WETH to the withdrawal queue if there is a funding shortfall.\n * @dev is called from the Native Staking strategy when validator withdrawals are processed.\n * It also called before any WETH is allocated to a strategy.\n */\n function addWithdrawalQueueLiquidity() external {\n _addWithdrawalQueueLiquidity();\n }\n\n /**\n * @dev Adds asset (eg. WETH or USDC) to the withdrawal queue if there is a funding shortfall.\n * This assumes 1 asset equal 1 corresponding OToken.\n */\n function _addWithdrawalQueueLiquidity()\n internal\n returns (uint256 addedClaimable)\n {\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // Check if the claimable asset is less than the queued amount\n uint256 queueShortfall = queue.queued - queue.claimable;\n\n // No need to do anything is the withdrawal queue is full funded\n if (queueShortfall == 0) {\n return 0;\n }\n\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\n\n // Of the claimable withdrawal requests, how much is unclaimed?\n // That is, the amount of asset that is currently allocated for the withdrawal queue\n uint256 allocatedBaseAsset = queue.claimable - queue.claimed;\n\n // If there is no unallocated asset then there is nothing to add to the queue\n if (assetBalance <= allocatedBaseAsset) {\n return 0;\n }\n\n uint256 unallocatedBaseAsset = assetBalance - allocatedBaseAsset;\n // the new claimable amount is the smaller of the queue shortfall or unallocated asset\n addedClaimable = queueShortfall < unallocatedBaseAsset\n ? queueShortfall\n : unallocatedBaseAsset;\n uint256 newClaimable = queue.claimable + addedClaimable;\n\n // Store the new claimable amount back to storage\n withdrawalQueueMetadata.claimable = SafeCast.toUint128(newClaimable);\n\n // emit a WithdrawalClaimable event\n emit WithdrawalClaimable(newClaimable, addedClaimable);\n }\n\n /**\n * @dev Calculate how much asset (eg. WETH or USDC) in the vault is not reserved for the withdrawal queue.\n * That is, it is available to be redeemed or deposited into a strategy.\n */\n function _assetAvailable() internal view returns (uint256 assetAvailable) {\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // The amount of asset that is still to be claimed in the withdrawal queue\n uint256 outstandingWithdrawals = queue.queued - queue.claimed;\n\n // The amount of sitting in asset in the vault\n uint256 assetBalance = IERC20(asset).balanceOf(address(this));\n // If there is not enough asset in the vault to cover the outstanding withdrawals\n if (assetBalance <= outstandingWithdrawals) return 0;\n\n return assetBalance - outstandingWithdrawals;\n }\n\n /***************************************\n Utils\n ****************************************/\n\n /**\n * @notice Return the number of asset supported by the Vault.\n */\n function getAssetCount() public view returns (uint256) {\n return 1;\n }\n\n /**\n * @notice Return all vault asset addresses in order\n */\n function getAllAssets() external view returns (address[] memory) {\n address[] memory a = new address[](1);\n a[0] = asset;\n return a;\n }\n\n /**\n * @notice Return the number of strategies active on the Vault.\n */\n function getStrategyCount() external view returns (uint256) {\n return allStrategies.length;\n }\n\n /**\n * @notice Return the array of all strategies\n */\n function getAllStrategies() external view returns (address[] memory) {\n return allStrategies;\n }\n\n /**\n * @notice Returns whether the vault supports the asset\n * @param _asset address of the asset\n * @return true if supported\n */\n function isSupportedAsset(address _asset) external view returns (bool) {\n return asset == _asset;\n }\n\n function _min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n function _max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n}\n" + }, + "contracts/vault/VaultInitializer.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultInitializer contract\n * @notice The Vault contract initializes the vault.\n * @author Origin Protocol Inc\n */\n\nimport \"./VaultStorage.sol\";\n\nabstract contract VaultInitializer is VaultStorage {\n constructor(address _asset) VaultStorage(_asset) {}\n\n function initialize(address _oToken) external onlyGovernor initializer {\n require(_oToken != address(0), \"oToken address is zero\");\n\n oToken = OUSD(_oToken);\n\n rebasePaused = false;\n capitalPaused = true;\n\n // Initial Vault buffer of 0%\n vaultBuffer = 0;\n // Initial allocate threshold of 25,000 OUSD\n autoAllocateThreshold = 25000e18;\n // Initialize all strategies\n allStrategies = new address[](0);\n // Start with drip duration: 7 days\n dripDuration = 604800;\n }\n}\n" + }, + "contracts/vault/VaultStorage.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultStorage contract\n * @notice The VaultStorage contract defines the storage for the Vault contracts\n * @author Origin Protocol Inc\n */\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { OUSD } from \"../token/OUSD.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport \"../utils/Helpers.sol\";\n\nabstract contract VaultStorage is Initializable, Governable {\n using SafeERC20 for IERC20;\n\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\n event StrategyApproved(address _addr);\n event StrategyRemoved(address _addr);\n event Mint(address _addr, uint256 _value);\n event Redeem(address _addr, uint256 _value);\n event CapitalPaused();\n event CapitalUnpaused();\n event DefaultStrategyUpdated(address _strategy);\n event RebasePaused();\n event RebaseUnpaused();\n event VaultBufferUpdated(uint256 _vaultBuffer);\n event AllocateThresholdUpdated(uint256 _threshold);\n event StrategistUpdated(address _address);\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\n event TrusteeFeeBpsChanged(uint256 _basis);\n event TrusteeAddressChanged(address _address);\n event StrategyAddedToMintWhitelist(address indexed strategy);\n event StrategyRemovedFromMintWhitelist(address indexed strategy);\n event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\n event DripDurationChanged(uint256 dripDuration);\n event OperatorUpdated(address newOperator);\n event WithdrawalRequested(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount,\n uint256 _queued\n );\n event WithdrawalClaimed(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount\n );\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\n event WithdrawalClaimDelayUpdated(uint256 _newDelay);\n\n // Since we are proxy, all state should be uninitalized.\n // Since this storage contract does not have logic directly on it\n // we should not be checking for to see if these variables can be constant.\n // slither-disable-start uninitialized-state\n // slither-disable-start constable-states\n\n /// @dev mapping of supported vault assets to their configuration\n uint256 private _deprecated_assets;\n /// @dev list of all assets supported by the vault.\n address[] private _deprecated_allAssets;\n\n // Strategies approved for use by the Vault\n struct Strategy {\n bool isSupported;\n uint256 _deprecated; // Deprecated storage slot\n }\n /// @dev mapping of strategy contracts to their configuration\n mapping(address => Strategy) public strategies;\n /// @dev list of all vault strategies\n address[] internal allStrategies;\n\n /// @notice Address of the Oracle price provider contract\n address private _deprecated_priceProvider;\n /// @notice pause rebasing if true\n bool public rebasePaused;\n /// @notice pause operations that change the OToken supply.\n /// eg mint, redeem, allocate, mint/burn for strategy\n bool public capitalPaused;\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\n uint256 private _deprecated_redeemFeeBps;\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\n uint256 public vaultBuffer;\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\n uint256 public autoAllocateThreshold;\n /// @dev Deprecated. Was the auto-rebase trigger threshold for mint/redeem.\n /// Storage slot retained for proxy compatibility; no longer read or written.\n uint256 internal __deprecatedRebaseThreshold;\n\n /// @dev Address of the OToken token. eg OUSD or OETH.\n OUSD public oToken;\n\n /// @dev Address of the contract responsible for post rebase syncs with AMMs\n address private _deprecated_rebaseHooksAddr = address(0);\n\n /// @dev Deprecated: Address of Uniswap\n address private _deprecated_uniswapAddr = address(0);\n\n /// @notice Address of the Strategist\n address public strategistAddr = address(0);\n\n /// @notice Mapping of asset address to the Strategy that they should automatically\n // be allocated to\n uint256 private _deprecated_assetDefaultStrategies;\n\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\n uint256 public maxSupplyDiff;\n\n /// @notice Trustee contract that can collect a percentage of yield\n address public trusteeAddress;\n\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\n uint256 public trusteeFeeBps;\n\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\n address[] private _deprecated_swapTokens;\n\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\n\n address private _deprecated_ousdMetaStrategy;\n\n /// @notice How much OTokens are currently minted by the strategy\n int256 private _deprecated_netOusdMintedForStrategy;\n\n /// @notice How much net total OTokens are allowed to be minted by all strategies\n uint256 private _deprecated_netOusdMintForStrategyThreshold;\n\n uint256 private _deprecated_swapConfig;\n\n // List of strategies that can mint oTokens directly\n // Used in OETHBaseVaultCore\n mapping(address => bool) public isMintWhitelistedStrategy;\n\n /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\n /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\n address private _deprecated_dripper;\n\n /// Withdrawal Queue Storage /////\n\n struct WithdrawalQueueMetadata {\n // cumulative total of all withdrawal requests included the ones that have already been claimed\n uint128 queued;\n // cumulative total of all the requests that can be claimed including the ones that have already been claimed\n uint128 claimable;\n // total of all the requests that have been claimed\n uint128 claimed;\n // index of the next withdrawal request starting at 0\n uint128 nextWithdrawalIndex;\n }\n\n /// @notice Global metadata for the withdrawal queue including:\n /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed\n /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed\n /// claimed - total of all the requests that have been claimed\n /// nextWithdrawalIndex - index of the next withdrawal request starting at 0\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\n\n struct WithdrawalRequest {\n address withdrawer;\n bool claimed;\n uint40 timestamp; // timestamp of the withdrawal request\n // Amount of oTokens to redeem. eg OETH\n uint128 amount;\n // cumulative total of all withdrawal requests including this one.\n // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\n uint128 queued;\n }\n\n /// @notice Mapping of withdrawal request indices to the user withdrawal request data\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\n\n /// @notice Sets a minimum delay that is required to elapse between\n /// requesting async withdrawals and claiming the request.\n /// When set to 0 async withdrawals are disabled.\n uint256 public withdrawalClaimDelay;\n\n /// @notice Time in seconds that the vault last rebased yield.\n uint64 public lastRebase;\n\n /// @notice Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\n uint64 public dripDuration;\n\n /// @notice max rebase percentage per second\n /// Can be used to set maximum yield of the protocol,\n /// spreading out yield over time\n uint64 public rebasePerSecondMax;\n\n /// @notice target rebase rate limit, based on past rates and funds available.\n uint64 public rebasePerSecondTarget;\n\n uint256 internal constant MAX_REBASE = 0.02 ether;\n uint256 internal constant MAX_REBASE_PER_SECOND =\n uint256(0.05 ether) / 1 days;\n\n /// @notice Default strategy for asset\n address public defaultStrategy;\n\n /// @notice Address authorized to call `rebase()` directly. The Governor\n /// and Strategist are always allowed in addition to this address.\n address public operatorAddr;\n\n // For future use\n uint256[41] private __gap;\n\n /// @notice Index of WETH asset in allAssets array\n /// Legacy OETHVaultCore code, relocated here for vault consistency.\n uint256 private _deprecated_wethAssetIndex;\n\n /// @dev Address of the asset (eg. WETH or USDC)\n address public immutable asset;\n uint8 internal immutable assetDecimals;\n\n // slither-disable-end constable-states\n // slither-disable-end uninitialized-state\n\n constructor(address _asset) {\n uint8 _decimals = IERC20Metadata(_asset).decimals();\n require(_decimals <= 18, \"invalid asset decimals\");\n asset = _asset;\n assetDecimals = _decimals;\n }\n\n /// @notice Deprecated: use `oToken()` instead.\n function oUSD() external view returns (OUSD) {\n return oToken;\n }\n}\n" + }, + "contracts/zapper/AbstractOTokenZapper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\n\nabstract contract AbstractOTokenZapper {\n IERC20 public immutable oToken;\n IERC4626 public immutable wOToken;\n IVault public immutable vault;\n\n IWETH9 public immutable weth;\n\n address private constant ETH_MARKER =\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n event Zap(address indexed minter, address indexed asset, uint256 amount);\n\n constructor(\n address _oToken,\n address _wOToken,\n address _vault,\n address _weth\n ) {\n oToken = IERC20(_oToken);\n wOToken = IERC4626(_wOToken);\n vault = IVault(_vault);\n weth = IWETH9(_weth);\n\n IWETH9(_weth).approve(address(_vault), type(uint256).max);\n IERC20(_oToken).approve(_wOToken, type(uint256).max);\n }\n\n /**\n * @dev Deposit ETH and receive OToken in return.\n * Will verify that the user is sent 1:1 for ETH.\n */\n receive() external payable {\n deposit();\n }\n\n /**\n * @dev Deposit ETH and receive OToken in return\n * Will verify that the user is sent 1:1 for ETH.\n * @return Amount of OETH sent to user\n */\n function deposit() public payable returns (uint256) {\n uint256 balance = address(this).balance;\n\n emit Zap(msg.sender, ETH_MARKER, balance);\n\n // Wrap ETH\n weth.deposit{ value: balance }();\n\n // Mint with WETH\n return _mint(balance, msg.sender);\n }\n\n /**\n * @dev Deposit ETH and receive superOETHb in return\n * @param minReceived min amount of wsuperOETHb to receive\n * @return Amount of wsuperOETHb sent to user\n */\n function depositETHForWrappedTokens(uint256 minReceived)\n external\n payable\n returns (uint256)\n {\n // slither-disable-start reentrancy-balance\n uint256 balance = address(this).balance;\n\n emit Zap(msg.sender, ETH_MARKER, balance);\n\n // Wrap ETH\n weth.deposit{ value: balance }();\n\n // Mint with WETH\n uint256 mintedOToken = _mint(balance, address(this));\n\n // Wrap OToken into wOToken\n uint256 mintedWOToken = wOToken.deposit(mintedOToken, msg.sender);\n\n require(mintedWOToken >= minReceived, \"Zapper: not enough minted\");\n\n // slither-disable-end reentrancy-balance\n return mintedWOToken;\n }\n\n /**\n * @dev Deposit WETH and receive OToken in return\n * @param wethAmount Amount of WETH to deposit\n * @param minReceived min amount of wsuperOETHb to receive\n * @return Amount of wsuperOETHb sent to user\n */\n function depositWETHForWrappedTokens(\n uint256 wethAmount,\n uint256 minReceived\n ) external returns (uint256) {\n // slither-disable-start reentrancy-balance\n // slither-disable-next-line unchecked-transfer unused-return\n weth.transferFrom(msg.sender, address(this), wethAmount);\n\n emit Zap(msg.sender, address(weth), wethAmount);\n\n // Mint with WETH\n uint256 mintedOToken = _mint(wethAmount, address(this));\n\n // Wrap OToken into wOToken\n uint256 mintedWOToken = wOToken.deposit(mintedOToken, msg.sender);\n\n require(mintedWOToken >= minReceived, \"Zapper: not enough minted\");\n\n // slither-disable-end reentrancy-balance\n return mintedWOToken;\n }\n\n /**\n * @dev Internal function to mint superOETHb with WETH\n * @param minOToken Minimum amount of OToken to for user to receive\n * @param recipient Address that receives the tokens\n * @return Amount of OToken sent to user\n */\n function _mint(uint256 minOToken, address recipient)\n internal\n returns (uint256)\n {\n uint256 toMint = weth.balanceOf(address(this));\n vault.mint(toMint);\n uint256 mintedAmount = oToken.balanceOf(address(this));\n require(mintedAmount >= minOToken, \"Zapper: not enough minted\");\n\n if (recipient != address(this)) {\n require(oToken.transfer(recipient, mintedAmount));\n }\n\n return mintedAmount;\n }\n}\n" + }, + "contracts/zapper/OETHBaseZapper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractOTokenZapper } from \"./AbstractOTokenZapper.sol\";\n\ncontract OETHBaseZapper is AbstractOTokenZapper {\n constructor(\n address _oethb,\n address _woethb,\n address _vault\n )\n AbstractOTokenZapper(\n _oethb,\n _woethb,\n _vault,\n 0x4200000000000000000000000000000000000006\n )\n {}\n}\n" + }, + "contracts/zapper/OETHZapper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { AbstractOTokenZapper } from \"./AbstractOTokenZapper.sol\";\n\ncontract OETHZapper is AbstractOTokenZapper {\n constructor(\n address _oeth,\n address _woeth,\n address _vault,\n address _weth\n ) AbstractOTokenZapper(_oeth, _woeth, _vault, _weth) {}\n}\n" + }, + "contracts/zapper/OSonicZapper.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IWrappedSonic } from \"../interfaces/sonic/IWrappedSonic.sol\";\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\n\n/**\n * @title Zapper for Origin Sonic (OS) tokens\n * @author Origin Protocol Inc\n */\ncontract OSonicZapper {\n IERC20 public immutable OS;\n IERC4626 public immutable wOS;\n IVault public immutable vault;\n\n IWrappedSonic public constant wS =\n IWrappedSonic(0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38);\n address private constant ETH_MARKER =\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n event Zap(address indexed minter, address indexed asset, uint256 amount);\n\n constructor(\n address _OS,\n address _wOS,\n address _vault\n ) {\n OS = IERC20(_OS);\n wOS = IERC4626(_wOS);\n vault = IVault(_vault);\n\n wS.approve(address(_vault), type(uint256).max);\n IERC20(_OS).approve(_wOS, type(uint256).max);\n }\n\n /**\n * @dev Deposit native S currency and receive Origin Sonic (OS) tokens in return.\n * Will verify that the user is sent 1:1 for S.\n */\n receive() external payable {\n deposit();\n }\n\n /**\n * @dev Deposit native S currency and receive Origin Sonic (OS) tokens in return.\n * Will verify that the user is sent 1:1 for S.\n * @return Amount of Origin Sonic (OS) tokens sent to user\n */\n function deposit() public payable returns (uint256) {\n uint256 balance = address(this).balance;\n\n emit Zap(msg.sender, ETH_MARKER, balance);\n\n // Wrap native S\n wS.deposit{ value: balance }();\n\n // Mint Origin Sonic (OS) with Wrapped Sonic (wS)\n return _mint(balance, msg.sender);\n }\n\n /**\n * @dev Deposit S and receive Wrapped Origin Sonic (wOS) in return\n * @param minReceived min amount of Wrapped Origin Sonic (wOS) to receive\n * @return Amount of Wrapped Origin Sonic (wOS) tokens sent to user\n */\n function depositSForWrappedTokens(uint256 minReceived)\n external\n payable\n returns (uint256)\n {\n // slither-disable-start reentrancy-balance\n uint256 balance = address(this).balance;\n\n emit Zap(msg.sender, ETH_MARKER, balance);\n\n // Wrap S\n wS.deposit{ value: balance }();\n\n // Mint with Wrapped Sonic\n uint256 mintOS = _mint(balance, address(this));\n\n // Wrap Origin Sonic (OS) into Wrapped Origin Sonic (wOS)\n uint256 mintedWOS = wOS.deposit(mintOS, msg.sender);\n\n require(mintedWOS >= minReceived, \"Zapper: not enough minted\");\n\n // slither-disable-end reentrancy-balance\n return mintedWOS;\n }\n\n /**\n * @dev Deposit Wrapped Sonic (wS) tokens and receive Wrapped Origin Sonic (wOS) tokens in return\n * @param wSAmount Amount of Wrapped Sonic (wS) to deposit\n * @param minReceived min amount of Wrapped Origin Sonic (wOS) token to receive\n * @return Amount of Wrapped Origin Sonic (wOS) tokens sent to user\n */\n function depositWSForWrappedTokens(uint256 wSAmount, uint256 minReceived)\n external\n returns (uint256)\n {\n // slither-disable-start reentrancy-balance\n // slither-disable-next-line unchecked-transfer unused-return\n wS.transferFrom(msg.sender, address(this), wSAmount);\n\n emit Zap(msg.sender, address(wS), wSAmount);\n\n // Mint with Wrapped Sonic (wS)\n uint256 mintedOS = _mint(wSAmount, address(this));\n\n // Wrap Origin Sonic (OS) tokens into Wrapped Origin Sonic (wOS) tokens\n uint256 mintedWOS = wOS.deposit(mintedOS, msg.sender);\n\n require(mintedWOS >= minReceived, \"Zapper: not enough minted\");\n\n // slither-disable-end reentrancy-balance\n return mintedWOS;\n }\n\n /**\n * @dev Internal function to mint Origin Sonic (OS) with Wrapped S (wS)\n * @param minOS Minimum amount of Origin Sonic (OS) tokens the user can receive\n * @param recipient Address that receives the tokens\n * @return Amount of Origin Sonic (OS) tokens sent to the recipient\n */\n function _mint(uint256 minOS, address recipient)\n internal\n returns (uint256)\n {\n uint256 toMint = wS.balanceOf(address(this));\n vault.mint(toMint);\n uint256 mintedAmount = OS.balanceOf(address(this));\n require(mintedAmount >= minOS, \"Zapper: not enough minted\");\n\n if (recipient != address(this)) {\n require(OS.transfer(recipient, mintedAmount));\n }\n\n return mintedAmount;\n }\n}\n" + }, + "hardhat/console.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.22 <0.9.0;\n\nlibrary console {\n address constant CONSOLE_ADDRESS =\n 0x000000000000000000636F6e736F6c652e6c6f67;\n\n function _sendLogPayloadImplementation(bytes memory payload) internal view {\n address consoleAddress = CONSOLE_ADDRESS;\n /// @solidity memory-safe-assembly\n assembly {\n pop(\n staticcall(\n gas(),\n consoleAddress,\n add(payload, 32),\n mload(payload),\n 0,\n 0\n )\n )\n }\n }\n\n function _castToPure(\n function(bytes memory) internal view fnIn\n ) internal pure returns (function(bytes memory) pure fnOut) {\n assembly {\n fnOut := fnIn\n }\n }\n\n function _sendLogPayload(bytes memory payload) internal pure {\n _castToPure(_sendLogPayloadImplementation)(payload);\n }\n\n function log() internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log()\"));\n }\n\n function logInt(int256 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(int256)\", p0));\n }\n\n function logUint(uint256 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256)\", p0));\n }\n\n function logString(string memory p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n }\n\n function logBool(bool p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n }\n\n function logAddress(address p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n }\n\n function logBytes(bytes memory p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes)\", p0));\n }\n\n function logBytes1(bytes1 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes1)\", p0));\n }\n\n function logBytes2(bytes2 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes2)\", p0));\n }\n\n function logBytes3(bytes3 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes3)\", p0));\n }\n\n function logBytes4(bytes4 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes4)\", p0));\n }\n\n function logBytes5(bytes5 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes5)\", p0));\n }\n\n function logBytes6(bytes6 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes6)\", p0));\n }\n\n function logBytes7(bytes7 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes7)\", p0));\n }\n\n function logBytes8(bytes8 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes8)\", p0));\n }\n\n function logBytes9(bytes9 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes9)\", p0));\n }\n\n function logBytes10(bytes10 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes10)\", p0));\n }\n\n function logBytes11(bytes11 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes11)\", p0));\n }\n\n function logBytes12(bytes12 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes12)\", p0));\n }\n\n function logBytes13(bytes13 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes13)\", p0));\n }\n\n function logBytes14(bytes14 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes14)\", p0));\n }\n\n function logBytes15(bytes15 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes15)\", p0));\n }\n\n function logBytes16(bytes16 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes16)\", p0));\n }\n\n function logBytes17(bytes17 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes17)\", p0));\n }\n\n function logBytes18(bytes18 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes18)\", p0));\n }\n\n function logBytes19(bytes19 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes19)\", p0));\n }\n\n function logBytes20(bytes20 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes20)\", p0));\n }\n\n function logBytes21(bytes21 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes21)\", p0));\n }\n\n function logBytes22(bytes22 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes22)\", p0));\n }\n\n function logBytes23(bytes23 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes23)\", p0));\n }\n\n function logBytes24(bytes24 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes24)\", p0));\n }\n\n function logBytes25(bytes25 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes25)\", p0));\n }\n\n function logBytes26(bytes26 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes26)\", p0));\n }\n\n function logBytes27(bytes27 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes27)\", p0));\n }\n\n function logBytes28(bytes28 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes28)\", p0));\n }\n\n function logBytes29(bytes29 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes29)\", p0));\n }\n\n function logBytes30(bytes30 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes30)\", p0));\n }\n\n function logBytes31(bytes31 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes31)\", p0));\n }\n\n function logBytes32(bytes32 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes32)\", p0));\n }\n\n function log(uint256 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256)\", p0));\n }\n\n function log(string memory p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n }\n\n function log(bool p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n }\n\n function log(address p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n }\n\n function log(uint256 p0, uint256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256)\", p0, p1));\n }\n\n function log(uint256 p0, string memory p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string)\", p0, p1));\n }\n\n function log(uint256 p0, bool p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool)\", p0, p1));\n }\n\n function log(uint256 p0, address p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address)\", p0, p1));\n }\n\n function log(string memory p0, uint256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256)\", p0, p1));\n }\n\n function log(string memory p0, string memory p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string)\", p0, p1));\n }\n\n function log(string memory p0, bool p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool)\", p0, p1));\n }\n\n function log(string memory p0, address p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address)\", p0, p1));\n }\n\n function log(bool p0, uint256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256)\", p0, p1));\n }\n\n function log(bool p0, string memory p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string)\", p0, p1));\n }\n\n function log(bool p0, bool p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool)\", p0, p1));\n }\n\n function log(bool p0, address p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address)\", p0, p1));\n }\n\n function log(address p0, uint256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256)\", p0, p1));\n }\n\n function log(address p0, string memory p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string)\", p0, p1));\n }\n\n function log(address p0, bool p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool)\", p0, p1));\n }\n\n function log(address p0, address p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address)\", p0, p1));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256)\", p0, p1, p2));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string)\", p0, p1, p2));\n }\n\n function log(uint256 p0, uint256 p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool)\", p0, p1, p2));\n }\n\n function log(uint256 p0, uint256 p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address)\", p0, p1, p2));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256)\", p0, p1, p2));\n }\n\n function log(uint256 p0, string memory p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string)\", p0, p1, p2));\n }\n\n function log(uint256 p0, string memory p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool)\", p0, p1, p2));\n }\n\n function log(uint256 p0, string memory p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address)\", p0, p1, p2));\n }\n\n function log(uint256 p0, bool p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256)\", p0, p1, p2));\n }\n\n function log(uint256 p0, bool p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string)\", p0, p1, p2));\n }\n\n function log(uint256 p0, bool p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool)\", p0, p1, p2));\n }\n\n function log(uint256 p0, bool p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address)\", p0, p1, p2));\n }\n\n function log(uint256 p0, address p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256)\", p0, p1, p2));\n }\n\n function log(uint256 p0, address p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string)\", p0, p1, p2));\n }\n\n function log(uint256 p0, address p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool)\", p0, p1, p2));\n }\n\n function log(uint256 p0, address p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address)\", p0, p1, p2));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256)\", p0, p1, p2));\n }\n\n function log(string memory p0, uint256 p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string)\", p0, p1, p2));\n }\n\n function log(string memory p0, uint256 p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool)\", p0, p1, p2));\n }\n\n function log(string memory p0, uint256 p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address)\", p0, p1, p2));\n }\n\n function log(string memory p0, string memory p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256)\", p0, p1, p2));\n }\n\n function log(string memory p0, string memory p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string)\", p0, p1, p2));\n }\n\n function log(string memory p0, string memory p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool)\", p0, p1, p2));\n }\n\n function log(string memory p0, string memory p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address)\", p0, p1, p2));\n }\n\n function log(string memory p0, bool p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256)\", p0, p1, p2));\n }\n\n function log(string memory p0, bool p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string)\", p0, p1, p2));\n }\n\n function log(string memory p0, bool p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool)\", p0, p1, p2));\n }\n\n function log(string memory p0, bool p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address)\", p0, p1, p2));\n }\n\n function log(string memory p0, address p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256)\", p0, p1, p2));\n }\n\n function log(string memory p0, address p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string)\", p0, p1, p2));\n }\n\n function log(string memory p0, address p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool)\", p0, p1, p2));\n }\n\n function log(string memory p0, address p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address)\", p0, p1, p2));\n }\n\n function log(bool p0, uint256 p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256)\", p0, p1, p2));\n }\n\n function log(bool p0, uint256 p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string)\", p0, p1, p2));\n }\n\n function log(bool p0, uint256 p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool)\", p0, p1, p2));\n }\n\n function log(bool p0, uint256 p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address)\", p0, p1, p2));\n }\n\n function log(bool p0, string memory p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256)\", p0, p1, p2));\n }\n\n function log(bool p0, string memory p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string)\", p0, p1, p2));\n }\n\n function log(bool p0, string memory p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool)\", p0, p1, p2));\n }\n\n function log(bool p0, string memory p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address)\", p0, p1, p2));\n }\n\n function log(bool p0, bool p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256)\", p0, p1, p2));\n }\n\n function log(bool p0, bool p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string)\", p0, p1, p2));\n }\n\n function log(bool p0, bool p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool)\", p0, p1, p2));\n }\n\n function log(bool p0, bool p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address)\", p0, p1, p2));\n }\n\n function log(bool p0, address p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256)\", p0, p1, p2));\n }\n\n function log(bool p0, address p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string)\", p0, p1, p2));\n }\n\n function log(bool p0, address p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool)\", p0, p1, p2));\n }\n\n function log(bool p0, address p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address)\", p0, p1, p2));\n }\n\n function log(address p0, uint256 p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256)\", p0, p1, p2));\n }\n\n function log(address p0, uint256 p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string)\", p0, p1, p2));\n }\n\n function log(address p0, uint256 p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool)\", p0, p1, p2));\n }\n\n function log(address p0, uint256 p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address)\", p0, p1, p2));\n }\n\n function log(address p0, string memory p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256)\", p0, p1, p2));\n }\n\n function log(address p0, string memory p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string)\", p0, p1, p2));\n }\n\n function log(address p0, string memory p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool)\", p0, p1, p2));\n }\n\n function log(address p0, string memory p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address)\", p0, p1, p2));\n }\n\n function log(address p0, bool p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256)\", p0, p1, p2));\n }\n\n function log(address p0, bool p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string)\", p0, p1, p2));\n }\n\n function log(address p0, bool p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool)\", p0, p1, p2));\n }\n\n function log(address p0, bool p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address)\", p0, p1, p2));\n }\n\n function log(address p0, address p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256)\", p0, p1, p2));\n }\n\n function log(address p0, address p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string)\", p0, p1, p2));\n }\n\n function log(address p0, address p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool)\", p0, p1, p2));\n }\n\n function log(address p0, address p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address)\", p0, p1, p2));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,address)\", p0, p1, p2, p3));\n }\n}\n" + }, + "lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IERC4626 } from \"../../../../interfaces/IERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n// From Open Zeppelin draft PR commit:\n// fac43034dca85ff539db3fc8aa2a7084b843d454\n// https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171\n\nabstract contract ERC4626 is ERC20, IERC4626 {\n IERC20Metadata private immutable _asset;\n\n constructor(IERC20Metadata __asset) {\n _asset = __asset;\n }\n\n /** @dev See {IERC4262-asset} */\n function asset() public view virtual override returns (address) {\n return address(_asset);\n }\n\n /** @dev See {IERC4262-totalAssets} */\n function totalAssets() public view virtual override returns (uint256) {\n return _asset.balanceOf(address(this));\n }\n\n /**\n * @dev See {IERC4262-convertToShares}\n *\n * Will revert if asserts > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset\n * would represent an infinite amout of shares.\n */\n function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) {\n uint256 supply = totalSupply();\n\n return\n (assets == 0 || supply == 0)\n ? (assets * 10**decimals()) / 10**_asset.decimals()\n : (assets * supply) / totalAssets();\n }\n\n /** @dev See {IERC4262-convertToAssets} */\n function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) {\n uint256 supply = totalSupply();\n\n return (supply == 0) ? (shares * 10**_asset.decimals()) / 10**decimals() : (shares * totalAssets()) / supply;\n }\n\n /** @dev See {IERC4262-maxDeposit} */\n function maxDeposit(address) public view virtual override returns (uint256) {\n return type(uint256).max;\n }\n\n /** @dev See {IERC4262-maxMint} */\n function maxMint(address) public view virtual override returns (uint256) {\n return type(uint256).max;\n }\n\n /** @dev See {IERC4262-maxWithdraw} */\n function maxWithdraw(address owner) public view virtual override returns (uint256) {\n return convertToAssets(balanceOf(owner));\n }\n\n /** @dev See {IERC4262-maxRedeem} */\n function maxRedeem(address owner) public view virtual override returns (uint256) {\n return balanceOf(owner);\n }\n\n /** @dev See {IERC4262-previewDeposit} */\n function previewDeposit(uint256 assets) public view virtual override returns (uint256) {\n return convertToShares(assets);\n }\n\n /** @dev See {IERC4262-previewMint} */\n function previewMint(uint256 shares) public view virtual override returns (uint256) {\n uint256 assets = convertToAssets(shares);\n return assets + (convertToShares(assets) < shares ? 1 : 0);\n }\n\n /** @dev See {IERC4262-previewWithdraw} */\n function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {\n uint256 shares = convertToShares(assets);\n return shares + (convertToAssets(shares) < assets ? 1 : 0);\n }\n\n /** @dev See {IERC4262-previewRedeem} */\n function previewRedeem(uint256 shares) public view virtual override returns (uint256) {\n return convertToAssets(shares);\n }\n\n /** @dev See {IERC4262-deposit} */\n function deposit(uint256 assets, address receiver) public virtual override returns (uint256) {\n require(assets <= maxDeposit(receiver), \"ERC4626: deposit more then max\");\n\n address caller = _msgSender();\n uint256 shares = previewDeposit(assets);\n\n // if _asset is ERC777, transferFrom can call reenter BEFORE the transfer happens through\n // the tokensToSend hook, so we need to transfer before we mint to keep the invariants.\n SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n _mint(receiver, shares);\n\n emit Deposit(caller, receiver, assets, shares);\n\n return shares;\n }\n\n /** @dev See {IERC4262-mint} */\n function mint(uint256 shares, address receiver) public virtual override returns (uint256) {\n require(shares <= maxMint(receiver), \"ERC4626: mint more then max\");\n\n address caller = _msgSender();\n uint256 assets = previewMint(shares);\n\n // if _asset is ERC777, transferFrom can call reenter BEFORE the transfer happens through\n // the tokensToSend hook, so we need to transfer before we mint to keep the invariants.\n SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n _mint(receiver, shares);\n\n emit Deposit(caller, receiver, assets, shares);\n\n return assets;\n }\n\n /** @dev See {IERC4262-withdraw} */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) public virtual override returns (uint256) {\n require(assets <= maxWithdraw(owner), \"ERC4626: withdraw more then max\");\n\n address caller = _msgSender();\n uint256 shares = previewWithdraw(assets);\n\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n\n // if _asset is ERC777, transfer can call reenter AFTER the transfer happens through\n // the tokensReceived hook, so we need to transfer after we burn to keep the invariants.\n _burn(owner, shares);\n SafeERC20.safeTransfer(_asset, receiver, assets);\n\n emit Withdraw(caller, receiver, owner, assets, shares);\n\n return shares;\n }\n\n /** @dev See {IERC4262-redeem} */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) public virtual override returns (uint256) {\n require(shares <= maxRedeem(owner), \"ERC4626: redeem more then max\");\n\n address caller = _msgSender();\n uint256 assets = previewRedeem(shares);\n\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n\n // if _asset is ERC777, transfer can call reenter AFTER the transfer happens through\n // the tokensReceived hook, so we need to transfer after we burn to keep the invariants.\n _burn(owner, shares);\n SafeERC20.safeTransfer(_asset, receiver, assets);\n\n emit Withdraw(caller, receiver, owner, assets, shares);\n\n return assets;\n }\n\n // Included here, since this method was not yet present in\n // the version of Open Zeppelin ERC20 code we use.\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n}" + }, + "lib/openzeppelin/interfaces/IERC4626.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IERC4626 is IERC20, IERC20Metadata {\n event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);\n\n event Withdraw(\n address indexed caller,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) external returns (uint256 assets);\n}" + }, + "solidity-bytes-utils/contracts/BytesLib.sol": { + "content": "// SPDX-License-Identifier: Unlicense\n/*\n * @title Solidity Bytes Arrays Utils\n * @author Gonçalo Sá \n *\n * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.\n * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.\n */\npragma solidity >=0.8.0 <0.9.0;\n\n\nlibrary BytesLib {\n function concat(\n bytes memory _preBytes,\n bytes memory _postBytes\n )\n internal\n pure\n returns (bytes memory)\n {\n bytes memory tempBytes;\n\n assembly {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // Store the length of the first bytes array at the beginning of\n // the memory for tempBytes.\n let length := mload(_preBytes)\n mstore(tempBytes, length)\n\n // Maintain a memory counter for the current write location in the\n // temp bytes array by adding the 32 bytes for the array length to\n // the starting location.\n let mc := add(tempBytes, 0x20)\n // Stop copying when the memory counter reaches the length of the\n // first bytes array.\n let end := add(mc, length)\n\n for {\n // Initialize a copy counter to the start of the _preBytes data,\n // 32 bytes into its memory.\n let cc := add(_preBytes, 0x20)\n } lt(mc, end) {\n // Increase both counters by 32 bytes each iteration.\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // Write the _preBytes data into the tempBytes memory 32 bytes\n // at a time.\n mstore(mc, mload(cc))\n }\n\n // Add the length of _postBytes to the current length of tempBytes\n // and store it as the new length in the first 32 bytes of the\n // tempBytes memory.\n length := mload(_postBytes)\n mstore(tempBytes, add(length, mload(tempBytes)))\n\n // Move the memory counter back from a multiple of 0x20 to the\n // actual end of the _preBytes data.\n mc := end\n // Stop copying when the memory counter reaches the new combined\n // length of the arrays.\n end := add(mc, length)\n\n for {\n let cc := add(_postBytes, 0x20)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n mstore(mc, mload(cc))\n }\n\n // Update the free-memory pointer by padding our last write location\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\n // next 32 byte block, then round down to the nearest multiple of\n // 32. If the sum of the length of the two arrays is zero then add\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\n mstore(0x40, and(\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\n not(31) // Round down to the nearest 32 bytes.\n ))\n }\n\n return tempBytes;\n }\n\n function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {\n assembly {\n // Read the first 32 bytes of _preBytes storage, which is the length\n // of the array. (We don't need to use the offset into the slot\n // because arrays use the entire slot.)\n let fslot := sload(_preBytes.slot)\n // Arrays of 31 bytes or less have an even value in their slot,\n // while longer arrays have an odd value. The actual length is\n // the slot divided by two for odd values, and the lowest order\n // byte divided by two for even values.\n // If the slot is even, bitwise and the slot with 255 and divide by\n // two to get the length. If the slot is odd, bitwise and the slot\n // with -1 and divide by two.\n let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n let mlength := mload(_postBytes)\n let newlength := add(slength, mlength)\n // slength can contain both the length and contents of the array\n // if length < 32 bytes so let's prepare for that\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n switch add(lt(slength, 32), lt(newlength, 32))\n case 2 {\n // Since the new array still fits in the slot, we just need to\n // update the contents of the slot.\n // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\n sstore(\n _preBytes.slot,\n // all the modifications to the slot are inside this\n // next block\n add(\n // we can just add to the slot contents because the\n // bytes we want to change are the LSBs\n fslot,\n add(\n mul(\n div(\n // load the bytes from memory\n mload(add(_postBytes, 0x20)),\n // zero all bytes to the right\n exp(0x100, sub(32, mlength))\n ),\n // and now shift left the number of bytes to\n // leave space for the length in the slot\n exp(0x100, sub(32, newlength))\n ),\n // increase length by the double of the memory\n // bytes length\n mul(mlength, 2)\n )\n )\n )\n }\n case 1 {\n // The stored value fits in the slot, but the combined value\n // will exceed it.\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n // save new length\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n // The contents of the _postBytes array start 32 bytes into\n // the structure. Our first read should obtain the `submod`\n // bytes that can fit into the unused space in the last word\n // of the stored array. To get this, we read 32 bytes starting\n // from `submod`, so the data we read overlaps with the array\n // contents by `submod` bytes. Masking the lowest-order\n // `submod` bytes allows us to add that value directly to the\n // stored value.\n\n let submod := sub(32, slength)\n let mc := add(_postBytes, submod)\n let end := add(_postBytes, mlength)\n let mask := sub(exp(0x100, submod), 1)\n\n sstore(\n sc,\n add(\n and(\n fslot,\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00\n ),\n and(mload(mc), mask)\n )\n )\n\n for {\n mc := add(mc, 0x20)\n sc := add(sc, 1)\n } lt(mc, end) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n sstore(sc, mload(mc))\n }\n\n mask := exp(0x100, sub(mc, end))\n\n sstore(sc, mul(div(mload(mc), mask), mask))\n }\n default {\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n // Start copying to the last used word of the stored array.\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n // save new length\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n // Copy over the first `submod` bytes of the new data as in\n // case 1 above.\n let slengthmod := mod(slength, 32)\n let mlengthmod := mod(mlength, 32)\n let submod := sub(32, slengthmod)\n let mc := add(_postBytes, submod)\n let end := add(_postBytes, mlength)\n let mask := sub(exp(0x100, submod), 1)\n\n sstore(sc, add(sload(sc), and(mload(mc), mask)))\n\n for {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } lt(mc, end) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n sstore(sc, mload(mc))\n }\n\n mask := exp(0x100, sub(mc, end))\n\n sstore(sc, mul(div(mload(mc), mask), mask))\n }\n }\n }\n\n function slice(\n bytes memory _bytes,\n uint256 _start,\n uint256 _length\n )\n internal\n pure\n returns (bytes memory)\n {\n // We're using the unchecked block below because otherwise execution ends \n // with the native overflow error code.\n unchecked {\n require(_length + 31 >= _length, \"slice_overflow\");\n }\n require(_bytes.length >= _start + _length, \"slice_outOfBounds\");\n\n bytes memory tempBytes;\n\n assembly {\n switch iszero(_length)\n case 0 {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // The first word of the slice result is potentially a partial\n // word read from the original array. To read it, we calculate\n // the length of that partial word and start copying that many\n // bytes into the array. The first word we copy will start with\n // data we don't care about, but the last `lengthmod` bytes will\n // land at the beginning of the contents of the new array. When\n // we're done copying, we overwrite the full first word with\n // the actual length of the slice.\n let lengthmod := and(_length, 31)\n\n // The multiplication in the next line is necessary\n // because when slicing multiples of 32 bytes (lengthmod == 0)\n // the following copy loop was copying the origin's length\n // and then ending prematurely not copying everything it should.\n let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n let end := add(mc, _length)\n\n for {\n // The multiplication in the next line has the same exact purpose\n // as the one above.\n let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n mstore(mc, mload(cc))\n }\n\n mstore(tempBytes, _length)\n\n //update free-memory pointer\n //allocating the array padded to 32 bytes like the compiler does now\n mstore(0x40, and(add(mc, 31), not(31)))\n }\n //if we want a zero-length slice let's just return a zero-length array\n default {\n tempBytes := mload(0x40)\n //zero out the 32 bytes slice we are about to return\n //we need to do it because Solidity does not garbage collect\n mstore(tempBytes, 0)\n\n mstore(0x40, add(tempBytes, 0x20))\n }\n }\n\n return tempBytes;\n }\n\n function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {\n require(_bytes.length >= _start + 20, \"toAddress_outOfBounds\");\n address tempAddress;\n\n assembly {\n tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)\n }\n\n return tempAddress;\n }\n\n function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {\n require(_bytes.length >= _start + 1 , \"toUint8_outOfBounds\");\n uint8 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x1), _start))\n }\n\n return tempUint;\n }\n\n function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {\n require(_bytes.length >= _start + 2, \"toUint16_outOfBounds\");\n uint16 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x2), _start))\n }\n\n return tempUint;\n }\n\n function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {\n require(_bytes.length >= _start + 4, \"toUint32_outOfBounds\");\n uint32 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x4), _start))\n }\n\n return tempUint;\n }\n\n function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {\n require(_bytes.length >= _start + 8, \"toUint64_outOfBounds\");\n uint64 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x8), _start))\n }\n\n return tempUint;\n }\n\n function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {\n require(_bytes.length >= _start + 12, \"toUint96_outOfBounds\");\n uint96 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0xc), _start))\n }\n\n return tempUint;\n }\n\n function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {\n require(_bytes.length >= _start + 16, \"toUint128_outOfBounds\");\n uint128 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x10), _start))\n }\n\n return tempUint;\n }\n\n function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {\n require(_bytes.length >= _start + 32, \"toUint256_outOfBounds\");\n uint256 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempUint;\n }\n\n function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {\n require(_bytes.length >= _start + 32, \"toBytes32_outOfBounds\");\n bytes32 tempBytes32;\n\n assembly {\n tempBytes32 := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempBytes32;\n }\n\n function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {\n bool success = true;\n\n assembly {\n let length := mload(_preBytes)\n\n // if lengths don't match the arrays are not equal\n switch eq(length, mload(_postBytes))\n case 1 {\n // cb is a circuit breaker in the for loop since there's\n // no said feature for inline assembly loops\n // cb = 1 - don't breaker\n // cb = 0 - break\n let cb := 1\n\n let mc := add(_preBytes, 0x20)\n let end := add(mc, length)\n\n for {\n let cc := add(_postBytes, 0x20)\n // the next line is the loop condition:\n // while(uint256(mc < end) + cb == 2)\n } eq(add(lt(mc, end), cb), 2) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // if any of these checks fails then arrays are not equal\n if iszero(eq(mload(mc), mload(cc))) {\n // unsuccess:\n success := 0\n cb := 0\n }\n }\n }\n default {\n // unsuccess:\n success := 0\n }\n }\n\n return success;\n }\n\n function equalStorage(\n bytes storage _preBytes,\n bytes memory _postBytes\n )\n internal\n view\n returns (bool)\n {\n bool success = true;\n\n assembly {\n // we know _preBytes_offset is 0\n let fslot := sload(_preBytes.slot)\n // Decode the length of the stored array like in concatStorage().\n let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n let mlength := mload(_postBytes)\n\n // if lengths don't match the arrays are not equal\n switch eq(slength, mlength)\n case 1 {\n // slength can contain both the length and contents of the array\n // if length < 32 bytes so let's prepare for that\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n if iszero(iszero(slength)) {\n switch lt(slength, 32)\n case 1 {\n // blank the last byte which is the length\n fslot := mul(div(fslot, 0x100), 0x100)\n\n if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\n // unsuccess:\n success := 0\n }\n }\n default {\n // cb is a circuit breaker in the for loop since there's\n // no said feature for inline assembly loops\n // cb = 1 - don't breaker\n // cb = 0 - break\n let cb := 1\n\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n let sc := keccak256(0x0, 0x20)\n\n let mc := add(_postBytes, 0x20)\n let end := add(mc, mlength)\n\n // the next line is the loop condition:\n // while(uint256(mc < end) + cb == 2)\n for {} eq(add(lt(mc, end), cb), 2) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n if iszero(eq(sload(sc), mload(mc))) {\n // unsuccess:\n success := 0\n cb := 0\n }\n }\n }\n }\n }\n default {\n // unsuccess:\n success := 0\n }\n }\n\n return success;\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "evmVersion": "paris", + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/contracts/storageLayout/base/OETHBaseVault.json b/contracts/storageLayout/base/OETHBaseVault.json index 3eb551ee7b..cc72e76194 100644 --- a/contracts/storageLayout/base/OETHBaseVault.json +++ b/contracts/storageLayout/base/OETHBaseVault.json @@ -45,7 +45,7 @@ "label": "strategies", "offset": 0, "slot": "53", - "type": "t_mapping(t_address,t_struct(Strategy)42986_storage)", + "type": "t_mapping(t_address,t_struct(Strategy)45786_storage)", "contract": "VaultStorage", "src": "contracts/vault/VaultStorage.sol:77" }, @@ -106,20 +106,20 @@ "src": "contracts/vault/VaultStorage.sol:93" }, { - "label": "rebaseThreshold", + "label": "__deprecatedRebaseThreshold", "offset": 0, "slot": "59", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:95" + "src": "contracts/vault/VaultStorage.sol:96" }, { "label": "oToken", "offset": 0, "slot": "60", - "type": "t_contract(OUSD)38551", + "type": "t_contract(OUSD)41354", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:98" + "src": "contracts/vault/VaultStorage.sol:99" }, { "label": "_deprecated_rebaseHooksAddr", @@ -127,7 +127,7 @@ "slot": "61", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:101" + "src": "contracts/vault/VaultStorage.sol:102" }, { "label": "_deprecated_uniswapAddr", @@ -135,7 +135,7 @@ "slot": "62", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:104" + "src": "contracts/vault/VaultStorage.sol:105" }, { "label": "strategistAddr", @@ -143,7 +143,7 @@ "slot": "63", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:107" + "src": "contracts/vault/VaultStorage.sol:108" }, { "label": "_deprecated_assetDefaultStrategies", @@ -151,7 +151,7 @@ "slot": "64", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:111" + "src": "contracts/vault/VaultStorage.sol:112" }, { "label": "maxSupplyDiff", @@ -159,7 +159,7 @@ "slot": "65", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:114" + "src": "contracts/vault/VaultStorage.sol:115" }, { "label": "trusteeAddress", @@ -167,7 +167,7 @@ "slot": "66", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:117" + "src": "contracts/vault/VaultStorage.sol:118" }, { "label": "trusteeFeeBps", @@ -175,7 +175,7 @@ "slot": "67", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:120" + "src": "contracts/vault/VaultStorage.sol:121" }, { "label": "_deprecated_swapTokens", @@ -183,7 +183,7 @@ "slot": "68", "type": "t_array(t_address)dyn_storage", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:123" + "src": "contracts/vault/VaultStorage.sol:124" }, { "label": "_deprecated_ousdMetaStrategy", @@ -191,7 +191,7 @@ "slot": "69", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:127" + "src": "contracts/vault/VaultStorage.sol:128" }, { "label": "_deprecated_netOusdMintedForStrategy", @@ -199,7 +199,7 @@ "slot": "70", "type": "t_int256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:130" + "src": "contracts/vault/VaultStorage.sol:131" }, { "label": "_deprecated_netOusdMintForStrategyThreshold", @@ -207,7 +207,7 @@ "slot": "71", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:133" + "src": "contracts/vault/VaultStorage.sol:134" }, { "label": "_deprecated_swapConfig", @@ -215,7 +215,7 @@ "slot": "72", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:135" + "src": "contracts/vault/VaultStorage.sol:136" }, { "label": "isMintWhitelistedStrategy", @@ -223,7 +223,7 @@ "slot": "73", "type": "t_mapping(t_address,t_bool)", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:139" + "src": "contracts/vault/VaultStorage.sol:140" }, { "label": "_deprecated_dripper", @@ -231,23 +231,23 @@ "slot": "74", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:143" + "src": "contracts/vault/VaultStorage.sol:144" }, { "label": "withdrawalQueueMetadata", "offset": 0, "slot": "75", - "type": "t_struct(WithdrawalQueueMetadata)43086_storage", + "type": "t_struct(WithdrawalQueueMetadata)45886_storage", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:163" + "src": "contracts/vault/VaultStorage.sol:164" }, { "label": "withdrawalRequests", "offset": 0, "slot": "77", - "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)43101_storage)", + "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)45901_storage)", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:177" + "src": "contracts/vault/VaultStorage.sol:178" }, { "label": "withdrawalClaimDelay", @@ -255,7 +255,7 @@ "slot": "78", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:182" + "src": "contracts/vault/VaultStorage.sol:183" }, { "label": "lastRebase", @@ -263,7 +263,7 @@ "slot": "79", "type": "t_uint64", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:185" + "src": "contracts/vault/VaultStorage.sol:186" }, { "label": "dripDuration", @@ -271,7 +271,7 @@ "slot": "79", "type": "t_uint64", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:188" + "src": "contracts/vault/VaultStorage.sol:189" }, { "label": "rebasePerSecondMax", @@ -279,7 +279,7 @@ "slot": "79", "type": "t_uint64", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:193" + "src": "contracts/vault/VaultStorage.sol:194" }, { "label": "rebasePerSecondTarget", @@ -287,7 +287,7 @@ "slot": "79", "type": "t_uint64", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:196" + "src": "contracts/vault/VaultStorage.sol:197" }, { "label": "defaultStrategy", @@ -295,15 +295,23 @@ "slot": "80", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:203" + "src": "contracts/vault/VaultStorage.sol:204" }, { - "label": "__gap", + "label": "operatorAddr", "offset": 0, "slot": "81", - "type": "t_array(t_uint256)42_storage", + "type": "t_address", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:208" + }, + { + "label": "__gap", + "offset": 0, + "slot": "82", + "type": "t_array(t_uint256)41_storage", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:206" + "src": "contracts/vault/VaultStorage.sol:211" }, { "label": "_deprecated_wethAssetIndex", @@ -311,7 +319,7 @@ "slot": "123", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:210" + "src": "contracts/vault/VaultStorage.sol:215" } ], "types": { @@ -323,9 +331,9 @@ "label": "address[]", "numberOfBytes": "32" }, - "t_array(t_uint256)42_storage": { - "label": "uint256[42]", - "numberOfBytes": "1344" + "t_array(t_uint256)41_storage": { + "label": "uint256[41]", + "numberOfBytes": "1312" }, "t_array(t_uint256)50_storage": { "label": "uint256[50]", @@ -335,7 +343,7 @@ "label": "bool", "numberOfBytes": "1" }, - "t_contract(OUSD)38551": { + "t_contract(OUSD)41354": { "label": "contract OUSD", "numberOfBytes": "20" }, @@ -347,15 +355,15 @@ "label": "mapping(address => bool)", "numberOfBytes": "32" }, - "t_mapping(t_address,t_struct(Strategy)42986_storage)": { + "t_mapping(t_address,t_struct(Strategy)45786_storage)": { "label": "mapping(address => struct VaultStorage.Strategy)", "numberOfBytes": "32" }, - "t_mapping(t_uint256,t_struct(WithdrawalRequest)43101_storage)": { + "t_mapping(t_uint256,t_struct(WithdrawalRequest)45901_storage)": { "label": "mapping(uint256 => struct VaultStorage.WithdrawalRequest)", "numberOfBytes": "32" }, - "t_struct(Strategy)42986_storage": { + "t_struct(Strategy)45786_storage": { "label": "struct VaultStorage.Strategy", "members": [ { @@ -373,7 +381,7 @@ ], "numberOfBytes": "64" }, - "t_struct(WithdrawalQueueMetadata)43086_storage": { + "t_struct(WithdrawalQueueMetadata)45886_storage": { "label": "struct VaultStorage.WithdrawalQueueMetadata", "members": [ { @@ -403,7 +411,7 @@ ], "numberOfBytes": "64" }, - "t_struct(WithdrawalRequest)43101_storage": { + "t_struct(WithdrawalRequest)45901_storage": { "label": "struct VaultStorage.WithdrawalRequest", "members": [ { diff --git a/contracts/storageLayout/mainnet/OETHVault.json b/contracts/storageLayout/mainnet/OETHVault.json index 81124ee98c..cc72e76194 100644 --- a/contracts/storageLayout/mainnet/OETHVault.json +++ b/contracts/storageLayout/mainnet/OETHVault.json @@ -45,7 +45,7 @@ "label": "strategies", "offset": 0, "slot": "53", - "type": "t_mapping(t_address,t_struct(Strategy)44293_storage)", + "type": "t_mapping(t_address,t_struct(Strategy)45786_storage)", "contract": "VaultStorage", "src": "contracts/vault/VaultStorage.sol:77" }, @@ -106,20 +106,20 @@ "src": "contracts/vault/VaultStorage.sol:93" }, { - "label": "rebaseThreshold", + "label": "__deprecatedRebaseThreshold", "offset": 0, "slot": "59", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:95" + "src": "contracts/vault/VaultStorage.sol:96" }, { "label": "oToken", "offset": 0, "slot": "60", - "type": "t_contract(OUSD)39858", + "type": "t_contract(OUSD)41354", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:98" + "src": "contracts/vault/VaultStorage.sol:99" }, { "label": "_deprecated_rebaseHooksAddr", @@ -127,7 +127,7 @@ "slot": "61", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:101" + "src": "contracts/vault/VaultStorage.sol:102" }, { "label": "_deprecated_uniswapAddr", @@ -135,7 +135,7 @@ "slot": "62", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:104" + "src": "contracts/vault/VaultStorage.sol:105" }, { "label": "strategistAddr", @@ -143,7 +143,7 @@ "slot": "63", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:107" + "src": "contracts/vault/VaultStorage.sol:108" }, { "label": "_deprecated_assetDefaultStrategies", @@ -151,7 +151,7 @@ "slot": "64", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:111" + "src": "contracts/vault/VaultStorage.sol:112" }, { "label": "maxSupplyDiff", @@ -159,7 +159,7 @@ "slot": "65", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:114" + "src": "contracts/vault/VaultStorage.sol:115" }, { "label": "trusteeAddress", @@ -167,7 +167,7 @@ "slot": "66", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:117" + "src": "contracts/vault/VaultStorage.sol:118" }, { "label": "trusteeFeeBps", @@ -175,7 +175,7 @@ "slot": "67", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:120" + "src": "contracts/vault/VaultStorage.sol:121" }, { "label": "_deprecated_swapTokens", @@ -183,7 +183,7 @@ "slot": "68", "type": "t_array(t_address)dyn_storage", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:123" + "src": "contracts/vault/VaultStorage.sol:124" }, { "label": "_deprecated_ousdMetaStrategy", @@ -191,7 +191,7 @@ "slot": "69", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:127" + "src": "contracts/vault/VaultStorage.sol:128" }, { "label": "_deprecated_netOusdMintedForStrategy", @@ -199,7 +199,7 @@ "slot": "70", "type": "t_int256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:130" + "src": "contracts/vault/VaultStorage.sol:131" }, { "label": "_deprecated_netOusdMintForStrategyThreshold", @@ -207,7 +207,7 @@ "slot": "71", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:133" + "src": "contracts/vault/VaultStorage.sol:134" }, { "label": "_deprecated_swapConfig", @@ -215,7 +215,7 @@ "slot": "72", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:135" + "src": "contracts/vault/VaultStorage.sol:136" }, { "label": "isMintWhitelistedStrategy", @@ -223,7 +223,7 @@ "slot": "73", "type": "t_mapping(t_address,t_bool)", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:139" + "src": "contracts/vault/VaultStorage.sol:140" }, { "label": "_deprecated_dripper", @@ -231,23 +231,23 @@ "slot": "74", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:143" + "src": "contracts/vault/VaultStorage.sol:144" }, { "label": "withdrawalQueueMetadata", "offset": 0, "slot": "75", - "type": "t_struct(WithdrawalQueueMetadata)44393_storage", + "type": "t_struct(WithdrawalQueueMetadata)45886_storage", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:163" + "src": "contracts/vault/VaultStorage.sol:164" }, { "label": "withdrawalRequests", "offset": 0, "slot": "77", - "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)44408_storage)", + "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)45901_storage)", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:177" + "src": "contracts/vault/VaultStorage.sol:178" }, { "label": "withdrawalClaimDelay", @@ -255,7 +255,7 @@ "slot": "78", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:182" + "src": "contracts/vault/VaultStorage.sol:183" }, { "label": "lastRebase", @@ -263,7 +263,7 @@ "slot": "79", "type": "t_uint64", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:185" + "src": "contracts/vault/VaultStorage.sol:186" }, { "label": "dripDuration", @@ -271,7 +271,7 @@ "slot": "79", "type": "t_uint64", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:188" + "src": "contracts/vault/VaultStorage.sol:189" }, { "label": "rebasePerSecondMax", @@ -279,7 +279,7 @@ "slot": "79", "type": "t_uint64", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:193" + "src": "contracts/vault/VaultStorage.sol:194" }, { "label": "rebasePerSecondTarget", @@ -287,7 +287,7 @@ "slot": "79", "type": "t_uint64", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:196" + "src": "contracts/vault/VaultStorage.sol:197" }, { "label": "defaultStrategy", @@ -295,15 +295,23 @@ "slot": "80", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:203" + "src": "contracts/vault/VaultStorage.sol:204" }, { - "label": "__gap", + "label": "operatorAddr", "offset": 0, "slot": "81", - "type": "t_array(t_uint256)42_storage", + "type": "t_address", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:208" + }, + { + "label": "__gap", + "offset": 0, + "slot": "82", + "type": "t_array(t_uint256)41_storage", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:206" + "src": "contracts/vault/VaultStorage.sol:211" }, { "label": "_deprecated_wethAssetIndex", @@ -311,7 +319,7 @@ "slot": "123", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:210" + "src": "contracts/vault/VaultStorage.sol:215" } ], "types": { @@ -323,9 +331,9 @@ "label": "address[]", "numberOfBytes": "32" }, - "t_array(t_uint256)42_storage": { - "label": "uint256[42]", - "numberOfBytes": "1344" + "t_array(t_uint256)41_storage": { + "label": "uint256[41]", + "numberOfBytes": "1312" }, "t_array(t_uint256)50_storage": { "label": "uint256[50]", @@ -335,7 +343,7 @@ "label": "bool", "numberOfBytes": "1" }, - "t_contract(OUSD)39858": { + "t_contract(OUSD)41354": { "label": "contract OUSD", "numberOfBytes": "20" }, @@ -347,15 +355,15 @@ "label": "mapping(address => bool)", "numberOfBytes": "32" }, - "t_mapping(t_address,t_struct(Strategy)44293_storage)": { + "t_mapping(t_address,t_struct(Strategy)45786_storage)": { "label": "mapping(address => struct VaultStorage.Strategy)", "numberOfBytes": "32" }, - "t_mapping(t_uint256,t_struct(WithdrawalRequest)44408_storage)": { + "t_mapping(t_uint256,t_struct(WithdrawalRequest)45901_storage)": { "label": "mapping(uint256 => struct VaultStorage.WithdrawalRequest)", "numberOfBytes": "32" }, - "t_struct(Strategy)44293_storage": { + "t_struct(Strategy)45786_storage": { "label": "struct VaultStorage.Strategy", "members": [ { @@ -373,7 +381,7 @@ ], "numberOfBytes": "64" }, - "t_struct(WithdrawalQueueMetadata)44393_storage": { + "t_struct(WithdrawalQueueMetadata)45886_storage": { "label": "struct VaultStorage.WithdrawalQueueMetadata", "members": [ { @@ -403,7 +411,7 @@ ], "numberOfBytes": "64" }, - "t_struct(WithdrawalRequest)44408_storage": { + "t_struct(WithdrawalRequest)45901_storage": { "label": "struct VaultStorage.WithdrawalRequest", "members": [ { diff --git a/contracts/storageLayout/mainnet/OUSDVault.json b/contracts/storageLayout/mainnet/OUSDVault.json index 56c38a08b5..cc72e76194 100644 --- a/contracts/storageLayout/mainnet/OUSDVault.json +++ b/contracts/storageLayout/mainnet/OUSDVault.json @@ -45,7 +45,7 @@ "label": "strategies", "offset": 0, "slot": "53", - "type": "t_mapping(t_address,t_struct(Strategy)63574_storage)", + "type": "t_mapping(t_address,t_struct(Strategy)45786_storage)", "contract": "VaultStorage", "src": "contracts/vault/VaultStorage.sol:77" }, @@ -106,20 +106,20 @@ "src": "contracts/vault/VaultStorage.sol:93" }, { - "label": "rebaseThreshold", + "label": "__deprecatedRebaseThreshold", "offset": 0, "slot": "59", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:95" + "src": "contracts/vault/VaultStorage.sol:96" }, { "label": "oToken", "offset": 0, "slot": "60", - "type": "t_contract(OUSD)58565", + "type": "t_contract(OUSD)41354", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:98" + "src": "contracts/vault/VaultStorage.sol:99" }, { "label": "_deprecated_rebaseHooksAddr", @@ -127,7 +127,7 @@ "slot": "61", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:101" + "src": "contracts/vault/VaultStorage.sol:102" }, { "label": "_deprecated_uniswapAddr", @@ -135,7 +135,7 @@ "slot": "62", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:104" + "src": "contracts/vault/VaultStorage.sol:105" }, { "label": "strategistAddr", @@ -143,7 +143,7 @@ "slot": "63", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:107" + "src": "contracts/vault/VaultStorage.sol:108" }, { "label": "_deprecated_assetDefaultStrategies", @@ -151,7 +151,7 @@ "slot": "64", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:111" + "src": "contracts/vault/VaultStorage.sol:112" }, { "label": "maxSupplyDiff", @@ -159,7 +159,7 @@ "slot": "65", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:114" + "src": "contracts/vault/VaultStorage.sol:115" }, { "label": "trusteeAddress", @@ -167,7 +167,7 @@ "slot": "66", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:117" + "src": "contracts/vault/VaultStorage.sol:118" }, { "label": "trusteeFeeBps", @@ -175,7 +175,7 @@ "slot": "67", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:120" + "src": "contracts/vault/VaultStorage.sol:121" }, { "label": "_deprecated_swapTokens", @@ -183,7 +183,7 @@ "slot": "68", "type": "t_array(t_address)dyn_storage", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:123" + "src": "contracts/vault/VaultStorage.sol:124" }, { "label": "_deprecated_ousdMetaStrategy", @@ -191,7 +191,7 @@ "slot": "69", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:127" + "src": "contracts/vault/VaultStorage.sol:128" }, { "label": "_deprecated_netOusdMintedForStrategy", @@ -199,7 +199,7 @@ "slot": "70", "type": "t_int256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:130" + "src": "contracts/vault/VaultStorage.sol:131" }, { "label": "_deprecated_netOusdMintForStrategyThreshold", @@ -207,7 +207,7 @@ "slot": "71", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:133" + "src": "contracts/vault/VaultStorage.sol:134" }, { "label": "_deprecated_swapConfig", @@ -215,7 +215,7 @@ "slot": "72", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:135" + "src": "contracts/vault/VaultStorage.sol:136" }, { "label": "isMintWhitelistedStrategy", @@ -223,7 +223,7 @@ "slot": "73", "type": "t_mapping(t_address,t_bool)", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:139" + "src": "contracts/vault/VaultStorage.sol:140" }, { "label": "_deprecated_dripper", @@ -231,23 +231,23 @@ "slot": "74", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:143" + "src": "contracts/vault/VaultStorage.sol:144" }, { "label": "withdrawalQueueMetadata", "offset": 0, "slot": "75", - "type": "t_struct(WithdrawalQueueMetadata)63674_storage", + "type": "t_struct(WithdrawalQueueMetadata)45886_storage", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:163" + "src": "contracts/vault/VaultStorage.sol:164" }, { "label": "withdrawalRequests", "offset": 0, "slot": "77", - "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)63689_storage)", + "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)45901_storage)", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:177" + "src": "contracts/vault/VaultStorage.sol:178" }, { "label": "withdrawalClaimDelay", @@ -255,7 +255,7 @@ "slot": "78", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:182" + "src": "contracts/vault/VaultStorage.sol:183" }, { "label": "lastRebase", @@ -263,7 +263,7 @@ "slot": "79", "type": "t_uint64", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:185" + "src": "contracts/vault/VaultStorage.sol:186" }, { "label": "dripDuration", @@ -271,7 +271,7 @@ "slot": "79", "type": "t_uint64", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:188" + "src": "contracts/vault/VaultStorage.sol:189" }, { "label": "rebasePerSecondMax", @@ -279,7 +279,7 @@ "slot": "79", "type": "t_uint64", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:193" + "src": "contracts/vault/VaultStorage.sol:194" }, { "label": "rebasePerSecondTarget", @@ -287,7 +287,7 @@ "slot": "79", "type": "t_uint64", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:196" + "src": "contracts/vault/VaultStorage.sol:197" }, { "label": "defaultStrategy", @@ -295,15 +295,23 @@ "slot": "80", "type": "t_address", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:203" + "src": "contracts/vault/VaultStorage.sol:204" }, { - "label": "__gap", + "label": "operatorAddr", "offset": 0, "slot": "81", - "type": "t_array(t_uint256)42_storage", + "type": "t_address", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:208" + }, + { + "label": "__gap", + "offset": 0, + "slot": "82", + "type": "t_array(t_uint256)41_storage", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:206" + "src": "contracts/vault/VaultStorage.sol:211" }, { "label": "_deprecated_wethAssetIndex", @@ -311,7 +319,7 @@ "slot": "123", "type": "t_uint256", "contract": "VaultStorage", - "src": "contracts/vault/VaultStorage.sol:210" + "src": "contracts/vault/VaultStorage.sol:215" } ], "types": { @@ -323,9 +331,9 @@ "label": "address[]", "numberOfBytes": "32" }, - "t_array(t_uint256)42_storage": { - "label": "uint256[42]", - "numberOfBytes": "1344" + "t_array(t_uint256)41_storage": { + "label": "uint256[41]", + "numberOfBytes": "1312" }, "t_array(t_uint256)50_storage": { "label": "uint256[50]", @@ -335,7 +343,7 @@ "label": "bool", "numberOfBytes": "1" }, - "t_contract(OUSD)58565": { + "t_contract(OUSD)41354": { "label": "contract OUSD", "numberOfBytes": "20" }, @@ -347,15 +355,15 @@ "label": "mapping(address => bool)", "numberOfBytes": "32" }, - "t_mapping(t_address,t_struct(Strategy)63574_storage)": { + "t_mapping(t_address,t_struct(Strategy)45786_storage)": { "label": "mapping(address => struct VaultStorage.Strategy)", "numberOfBytes": "32" }, - "t_mapping(t_uint256,t_struct(WithdrawalRequest)63689_storage)": { + "t_mapping(t_uint256,t_struct(WithdrawalRequest)45901_storage)": { "label": "mapping(uint256 => struct VaultStorage.WithdrawalRequest)", "numberOfBytes": "32" }, - "t_struct(Strategy)63574_storage": { + "t_struct(Strategy)45786_storage": { "label": "struct VaultStorage.Strategy", "members": [ { @@ -373,7 +381,7 @@ ], "numberOfBytes": "64" }, - "t_struct(WithdrawalQueueMetadata)63674_storage": { + "t_struct(WithdrawalQueueMetadata)45886_storage": { "label": "struct VaultStorage.WithdrawalQueueMetadata", "members": [ { @@ -403,7 +411,7 @@ ], "numberOfBytes": "64" }, - "t_struct(WithdrawalRequest)63689_storage": { + "t_struct(WithdrawalRequest)45901_storage": { "label": "struct VaultStorage.WithdrawalRequest", "members": [ { diff --git a/contracts/storageLayout/sonic/OSVault.json b/contracts/storageLayout/sonic/OSVault.json new file mode 100644 index 0000000000..cc72e76194 --- /dev/null +++ b/contracts/storageLayout/sonic/OSVault.json @@ -0,0 +1,468 @@ +{ + "solcVersion": "0.8.28", + "storage": [ + { + "label": "initialized", + "offset": 0, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "contracts/utils/Initializable.sol:12" + }, + { + "label": "initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "contracts/utils/Initializable.sol:17" + }, + { + "label": "______gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "Initializable", + "src": "contracts/utils/Initializable.sol:41" + }, + { + "label": "_deprecated_assets", + "offset": 0, + "slot": "51", + "type": "t_uint256", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:67" + }, + { + "label": "_deprecated_allAssets", + "offset": 0, + "slot": "52", + "type": "t_array(t_address)dyn_storage", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:69" + }, + { + "label": "strategies", + "offset": 0, + "slot": "53", + "type": "t_mapping(t_address,t_struct(Strategy)45786_storage)", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:77" + }, + { + "label": "allStrategies", + "offset": 0, + "slot": "54", + "type": "t_array(t_address)dyn_storage", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:79" + }, + { + "label": "_deprecated_priceProvider", + "offset": 0, + "slot": "55", + "type": "t_address", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:82" + }, + { + "label": "rebasePaused", + "offset": 20, + "slot": "55", + "type": "t_bool", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:84" + }, + { + "label": "capitalPaused", + "offset": 21, + "slot": "55", + "type": "t_bool", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:87" + }, + { + "label": "_deprecated_redeemFeeBps", + "offset": 0, + "slot": "56", + "type": "t_uint256", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:89" + }, + { + "label": "vaultBuffer", + "offset": 0, + "slot": "57", + "type": "t_uint256", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:91" + }, + { + "label": "autoAllocateThreshold", + "offset": 0, + "slot": "58", + "type": "t_uint256", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:93" + }, + { + "label": "__deprecatedRebaseThreshold", + "offset": 0, + "slot": "59", + "type": "t_uint256", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:96" + }, + { + "label": "oToken", + "offset": 0, + "slot": "60", + "type": "t_contract(OUSD)41354", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:99" + }, + { + "label": "_deprecated_rebaseHooksAddr", + "offset": 0, + "slot": "61", + "type": "t_address", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:102" + }, + { + "label": "_deprecated_uniswapAddr", + "offset": 0, + "slot": "62", + "type": "t_address", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:105" + }, + { + "label": "strategistAddr", + "offset": 0, + "slot": "63", + "type": "t_address", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:108" + }, + { + "label": "_deprecated_assetDefaultStrategies", + "offset": 0, + "slot": "64", + "type": "t_uint256", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:112" + }, + { + "label": "maxSupplyDiff", + "offset": 0, + "slot": "65", + "type": "t_uint256", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:115" + }, + { + "label": "trusteeAddress", + "offset": 0, + "slot": "66", + "type": "t_address", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:118" + }, + { + "label": "trusteeFeeBps", + "offset": 0, + "slot": "67", + "type": "t_uint256", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:121" + }, + { + "label": "_deprecated_swapTokens", + "offset": 0, + "slot": "68", + "type": "t_array(t_address)dyn_storage", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:124" + }, + { + "label": "_deprecated_ousdMetaStrategy", + "offset": 0, + "slot": "69", + "type": "t_address", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:128" + }, + { + "label": "_deprecated_netOusdMintedForStrategy", + "offset": 0, + "slot": "70", + "type": "t_int256", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:131" + }, + { + "label": "_deprecated_netOusdMintForStrategyThreshold", + "offset": 0, + "slot": "71", + "type": "t_uint256", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:134" + }, + { + "label": "_deprecated_swapConfig", + "offset": 0, + "slot": "72", + "type": "t_uint256", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:136" + }, + { + "label": "isMintWhitelistedStrategy", + "offset": 0, + "slot": "73", + "type": "t_mapping(t_address,t_bool)", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:140" + }, + { + "label": "_deprecated_dripper", + "offset": 0, + "slot": "74", + "type": "t_address", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:144" + }, + { + "label": "withdrawalQueueMetadata", + "offset": 0, + "slot": "75", + "type": "t_struct(WithdrawalQueueMetadata)45886_storage", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:164" + }, + { + "label": "withdrawalRequests", + "offset": 0, + "slot": "77", + "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)45901_storage)", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:178" + }, + { + "label": "withdrawalClaimDelay", + "offset": 0, + "slot": "78", + "type": "t_uint256", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:183" + }, + { + "label": "lastRebase", + "offset": 0, + "slot": "79", + "type": "t_uint64", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:186" + }, + { + "label": "dripDuration", + "offset": 8, + "slot": "79", + "type": "t_uint64", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:189" + }, + { + "label": "rebasePerSecondMax", + "offset": 16, + "slot": "79", + "type": "t_uint64", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:194" + }, + { + "label": "rebasePerSecondTarget", + "offset": 24, + "slot": "79", + "type": "t_uint64", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:197" + }, + { + "label": "defaultStrategy", + "offset": 0, + "slot": "80", + "type": "t_address", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:204" + }, + { + "label": "operatorAddr", + "offset": 0, + "slot": "81", + "type": "t_address", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:208" + }, + { + "label": "__gap", + "offset": 0, + "slot": "82", + "type": "t_array(t_uint256)41_storage", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:211" + }, + { + "label": "_deprecated_wethAssetIndex", + "offset": 0, + "slot": "123", + "type": "t_uint256", + "contract": "VaultStorage", + "src": "contracts/vault/VaultStorage.sol:215" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_address)dyn_storage": { + "label": "address[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)41_storage": { + "label": "uint256[41]", + "numberOfBytes": "1312" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(OUSD)41354": { + "label": "contract OUSD", + "numberOfBytes": "20" + }, + "t_int256": { + "label": "int256", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(Strategy)45786_storage)": { + "label": "mapping(address => struct VaultStorage.Strategy)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_struct(WithdrawalRequest)45901_storage)": { + "label": "mapping(uint256 => struct VaultStorage.WithdrawalRequest)", + "numberOfBytes": "32" + }, + "t_struct(Strategy)45786_storage": { + "label": "struct VaultStorage.Strategy", + "members": [ + { + "label": "isSupported", + "type": "t_bool", + "offset": 0, + "slot": "0" + }, + { + "label": "_deprecated", + "type": "t_uint256", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_struct(WithdrawalQueueMetadata)45886_storage": { + "label": "struct VaultStorage.WithdrawalQueueMetadata", + "members": [ + { + "label": "queued", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "claimable", + "type": "t_uint128", + "offset": 16, + "slot": "0" + }, + { + "label": "claimed", + "type": "t_uint128", + "offset": 0, + "slot": "1" + }, + { + "label": "nextWithdrawalIndex", + "type": "t_uint128", + "offset": 16, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_struct(WithdrawalRequest)45901_storage": { + "label": "struct VaultStorage.WithdrawalRequest", + "members": [ + { + "label": "withdrawer", + "type": "t_address", + "offset": 0, + "slot": "0" + }, + { + "label": "claimed", + "type": "t_bool", + "offset": 20, + "slot": "0" + }, + { + "label": "timestamp", + "type": "t_uint40", + "offset": 21, + "slot": "0" + }, + { + "label": "amount", + "type": "t_uint128", + "offset": 0, + "slot": "1" + }, + { + "label": "queued", + "type": "t_uint128", + "offset": 16, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint40": { + "label": "uint40", + "numberOfBytes": "5" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + } + }, + "namespaces": {} +} \ No newline at end of file diff --git a/contracts/test/vault/permissioned-rebase.mainnet.fork-test.js b/contracts/test/vault/permissioned-rebase.mainnet.fork-test.js index 2048d8f53c..262d21f18f 100644 --- a/contracts/test/vault/permissioned-rebase.mainnet.fork-test.js +++ b/contracts/test/vault/permissioned-rebase.mainnet.fork-test.js @@ -25,9 +25,9 @@ describe("ForkTest: permissioned rebase", function () { const vault = await ethers.getContractAt("IVault", proxy.address); const operatorAddr = await vault.operatorAddr(); - // The deploy proposal sets the operator to the multichain strategist Safe. + // The deploy proposal sets the operator to the Talos relayer. expect(operatorAddr.toLowerCase()).to.equal( - addresses.multichainStrategist.toLowerCase() + addresses.talosRelayer.toLowerCase() ); const operator = await impersonateAndFund(operatorAddr); diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index de7348024d..a05685af3a 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -8,8 +8,7 @@ addresses.createX = "0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed"; addresses.multichainStrategist = "0x4FF1b9D9ba8558F5EAfCec096318eA0d8b541971"; addresses.multichainBuybackOperator = "0xBB077E716A5f1F1B63ed5244eBFf5214E50fec8c"; -addresses.permissionedRebaseRelayer = - "0x0aBCDa6Fa7d500cf69B0eA5de9a607Cd9941221C"; +addresses.talosRelayer = "0x0aBCDa6Fa7d500cf69B0eA5de9a607Cd9941221C"; addresses.votemarket = "0x8c2c5A295450DDFf4CB360cA73FCCC12243D14D9"; // CCTP contracts (uses same addresses on all chains)