From afd72f602015ee74b510350bad0488d9019aad38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment?= Date: Fri, 23 Jan 2026 14:04:30 +0100 Subject: [PATCH 1/4] Deploy 166 --- .../mainnet/166_curve_pool_booster_factory.js | 3 +- .../mainnet/PoolBoostCentralRegistry.json | 44 +++---- .../ccb211e9f959f709b1d7b46e0ef9348f.json | 114 ++++++++++++++++++ .../mainnet/PoolBoostCentralRegistry.json | 3 +- 4 files changed, 140 insertions(+), 24 deletions(-) create mode 100644 contracts/deployments/mainnet/solcInputs/ccb211e9f959f709b1d7b46e0ef9348f.json diff --git a/contracts/deploy/mainnet/166_curve_pool_booster_factory.js b/contracts/deploy/mainnet/166_curve_pool_booster_factory.js index bec2bea1f5..ddf097ea01 100644 --- a/contracts/deploy/mainnet/166_curve_pool_booster_factory.js +++ b/contracts/deploy/mainnet/166_curve_pool_booster_factory.js @@ -12,7 +12,8 @@ module.exports = deploymentWithGovernanceProposal( forceDeploy: false, reduceQueueTime: true, deployerIsProposer: false, - proposalId: "", + proposalId: + "29790621776707374612038589489449765339510021204675811254575721433417005437106", }, async ({ deployWithConfirmation, withConfirmation }) => { const { deployerAddr } = await getNamedAccounts(); diff --git a/contracts/deployments/mainnet/PoolBoostCentralRegistry.json b/contracts/deployments/mainnet/PoolBoostCentralRegistry.json index d688f2c224..268a291835 100644 --- a/contracts/deployments/mainnet/PoolBoostCentralRegistry.json +++ b/contracts/deployments/mainnet/PoolBoostCentralRegistry.json @@ -1,5 +1,5 @@ { - "address": "0x65d6977Da199143BfA467A100614e5cbf59711a6", + "address": "0xb929fD0C424B0c5e19DCF2E32abd18E65A50D0F1", "abi": [ { "inputs": [], @@ -274,43 +274,43 @@ "type": "function" } ], - "transactionHash": "0x42264952b5b91304f910415b9c1c688a762e3f43ec683db36a6024dd45fa0faf", + "transactionHash": "0xab93962bb25f0149f89c02a8d0fa3c1238bda16a56f1f4cb89100601e0d280de", "receipt": { "to": null, - "from": "0xDba474FeF81bc7475f70e28DFC12410f032A83Db", - "contractAddress": "0x65d6977Da199143BfA467A100614e5cbf59711a6", - "transactionIndex": 18, + "from": "0x074105fdD39e982B2ffE749A193c942db1046AB9", + "contractAddress": "0xb929fD0C424B0c5e19DCF2E32abd18E65A50D0F1", + "transactionIndex": 58, "gasUsed": "681282", - "logsBloom": "0x00000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000000000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xf8a3e7d6495c9633daf4ad36e2253997f4c745c0c046b99aeae6b0fadaa61f33", - "transactionHash": "0x42264952b5b91304f910415b9c1c688a762e3f43ec683db36a6024dd45fa0faf", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000008000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x64ecfbc6e8d031562acbe779f05e365b2e62cb242d96d7385995e065c29d33f8", + "transactionHash": "0xab93962bb25f0149f89c02a8d0fa3c1238bda16a56f1f4cb89100601e0d280de", "logs": [ { - "transactionIndex": 18, - "blockNumber": 23490275, - "transactionHash": "0x42264952b5b91304f910415b9c1c688a762e3f43ec683db36a6024dd45fa0faf", - "address": "0x65d6977Da199143BfA467A100614e5cbf59711a6", + "transactionIndex": 58, + "blockNumber": 24297416, + "transactionHash": "0xab93962bb25f0149f89c02a8d0fa3c1238bda16a56f1f4cb89100601e0d280de", + "address": "0xb929fD0C424B0c5e19DCF2E32abd18E65A50D0F1", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000" ], "data": "0x", - "logIndex": 193, - "blockHash": "0xf8a3e7d6495c9633daf4ad36e2253997f4c745c0c046b99aeae6b0fadaa61f33" + "logIndex": 237, + "blockHash": "0x64ecfbc6e8d031562acbe779f05e365b2e62cb242d96d7385995e065c29d33f8" } ], - "blockNumber": 23490275, - "cumulativeGasUsed": "5557012", + "blockNumber": 24297416, + "cumulativeGasUsed": "9172991", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 1, - "solcInputHash": "5615adc00107e532b1893058f61d1303", - "metadata": "{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"factoryAddress\",\"type\":\"address\"}],\"name\":\"FactoryApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"factoryAddress\",\"type\":\"address\"}],\"name\":\"FactoryRemoved\",\"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\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"poolBoosterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"ammPoolAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enum IPoolBoostCentralRegistry.PoolBoosterType\",\"name\":\"poolBoosterType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"factoryAddress\",\"type\":\"address\"}],\"name\":\"PoolBoosterCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"poolBoosterAddress\",\"type\":\"address\"}],\"name\":\"PoolBoosterRemoved\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_factoryAddress\",\"type\":\"address\"}],\"name\":\"approveFactory\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_poolBoosterAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ammPoolAddress\",\"type\":\"address\"},{\"internalType\":\"enum IPoolBoostCentralRegistry.PoolBoosterType\",\"name\":\"_boosterType\",\"type\":\"uint8\"}],\"name\":\"emitPoolBoosterCreated\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_poolBoosterAddress\",\"type\":\"address\"}],\"name\":\"emitPoolBoosterRemoved\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"factories\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllFactories\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_factoryAddress\",\"type\":\"address\"}],\"name\":\"isApprovedFactory\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_factoryAddress\",\"type\":\"address\"}],\"name\":\"removeFactory\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"approveFactory(address)\":{\"params\":{\"_factoryAddress\":\"address of the factory\"}},\"emitPoolBoosterCreated(address,address,uint8)\":{\"details\":\"This has been created as a convenience method for the monitoring to have an index of all of the created pool boosters by only listening to the events of this contract.\",\"params\":{\"_ammPoolAddress\":\"address of the AMM pool forwarding yield to the pool booster\",\"_boosterType\":\"PoolBoosterType the type of the pool booster\",\"_poolBoosterAddress\":\"address of the pool booster created\"}},\"emitPoolBoosterRemoved(address)\":{\"details\":\"This has been created as a convenience method for the monitoring to have an index of all of the removed pool boosters by only listening to the events of this contract.\",\"params\":{\"_poolBoosterAddress\":\"address of the pool booster to be removed\"}},\"isApprovedFactory(address)\":{\"params\":{\"_factoryAddress\":\"address of the factory\"}},\"removeFactory(address)\":{\"params\":{\"_factoryAddress\":\"address of the factory\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}}},\"title\":\"Contract that holds all governance approved pool booster Factory implementation deployments\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"approveFactory(address)\":{\"notice\":\"Adds a factory address to the approved factory addresses\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"emitPoolBoosterCreated(address,address,uint8)\":{\"notice\":\"Emits a pool booster created event\"},\"emitPoolBoosterRemoved(address)\":{\"notice\":\"Emits a pool booster removed event\"},\"getAllFactories()\":{\"notice\":\"Returns all supported factories\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isApprovedFactory(address)\":{\"notice\":\"Returns true if the factory is approved\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"removeFactory(address)\":{\"notice\":\"Removes the factory from approved factory addresses\"},\"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\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/poolBooster/PoolBoostCentralRegistry.sol\":\"PoolBoostCentralRegistry\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"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/poolBooster/IPoolBoostCentralRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface IPoolBoostCentralRegistry {\\n /**\\n * @dev all the supported pool booster types are listed here. It is possible\\n * to have multiple versions of the factory that supports the same type of\\n * pool booster. Factories are immutable and this can happen when a factory\\n * or related pool booster required code update.\\n * e.g. \\\"PoolBoosterSwapxDouble\\\" & \\\"PoolBoosterSwapxDouble_v2\\\"\\n */\\n enum PoolBoosterType {\\n // Supports bribing 2 contracts per pool. Appropriate for Ichi vault concentrated\\n // liquidity pools where (which is expected in most/all cases) both pool gauges\\n // require bribing.\\n SwapXDoubleBooster,\\n // Supports bribing a single contract per pool. Appropriate for Classic Stable &\\n // Classic Volatile pools and Ichi vaults where only 1 side (1 of the 2 gauges)\\n // needs bribing\\n SwapXSingleBooster,\\n // Supports bribing a single contract per pool. Appropriate for Metropolis pools\\n MetropolisBooster,\\n // Supports creating a Merkl campaign.\\n MerklBooster\\n }\\n\\n struct PoolBoosterEntry {\\n address boosterAddress;\\n address ammPoolAddress;\\n PoolBoosterType boosterType;\\n }\\n\\n event PoolBoosterCreated(\\n address poolBoosterAddress,\\n address ammPoolAddress,\\n PoolBoosterType poolBoosterType,\\n address factoryAddress\\n );\\n event PoolBoosterRemoved(address poolBoosterAddress);\\n\\n function emitPoolBoosterCreated(\\n address _poolBoosterAddress,\\n address _ammPoolAddress,\\n PoolBoosterType _boosterType\\n ) external;\\n\\n function emitPoolBoosterRemoved(address _poolBoosterAddress) external;\\n}\\n\",\"keccak256\":\"0xa217e46abc623abfb0b7924f86e5eca07c0a5b64a91a345b1f9fd4bb97d4d0cf\",\"license\":\"BUSL-1.1\"},\"contracts/poolBooster/PoolBoostCentralRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { IPoolBoostCentralRegistry } from \\\"../interfaces/poolBooster/IPoolBoostCentralRegistry.sol\\\";\\n\\n/**\\n * @title Contract that holds all governance approved pool booster Factory\\n * implementation deployments\\n * @author Origin Protocol Inc\\n */\\ncontract PoolBoostCentralRegistry is Governable, IPoolBoostCentralRegistry {\\n event FactoryApproved(address factoryAddress);\\n event FactoryRemoved(address factoryAddress);\\n\\n // @notice List of approved factories\\n address[] public factories;\\n\\n modifier onlyApprovedFactories() {\\n require(isApprovedFactory(msg.sender), \\\"Not an approved factory\\\");\\n _;\\n }\\n\\n constructor() {\\n // set the governor of the implementation contract to zero address\\n _setGovernor(address(0));\\n }\\n\\n /**\\n * @notice Adds a factory address to the approved factory addresses\\n * @param _factoryAddress address of the factory\\n */\\n function approveFactory(address _factoryAddress) external onlyGovernor {\\n require(_factoryAddress != address(0), \\\"Invalid address\\\");\\n require(\\n !isApprovedFactory(_factoryAddress),\\n \\\"Factory already approved\\\"\\n );\\n\\n factories.push(_factoryAddress);\\n emit FactoryApproved(_factoryAddress);\\n }\\n\\n /**\\n * @notice Removes the factory from approved factory addresses\\n * @param _factoryAddress address of the factory\\n */\\n function removeFactory(address _factoryAddress) external onlyGovernor {\\n require(_factoryAddress != address(0), \\\"Invalid address\\\");\\n\\n uint256 length = factories.length;\\n bool factoryRemoved = false;\\n for (uint256 i = 0; i < length; i++) {\\n if (factories[i] != _factoryAddress) {\\n continue;\\n }\\n\\n factories[i] = factories[length - 1];\\n factories.pop();\\n emit FactoryRemoved(_factoryAddress);\\n factoryRemoved = true;\\n break;\\n }\\n require(factoryRemoved, \\\"Not an approved factory\\\");\\n\\n emit FactoryRemoved(_factoryAddress);\\n }\\n\\n /**\\n * @notice Emits a pool booster created event\\n * @dev This has been created as a convenience method for the monitoring to have\\n * an index of all of the created pool boosters by only listening to the\\n * events of this contract.\\n * @param _poolBoosterAddress address of the pool booster created\\n * @param _ammPoolAddress address of the AMM pool forwarding yield to the pool booster\\n * @param _boosterType PoolBoosterType the type of the pool booster\\n */\\n function emitPoolBoosterCreated(\\n address _poolBoosterAddress,\\n address _ammPoolAddress,\\n PoolBoosterType _boosterType\\n ) external onlyApprovedFactories {\\n emit PoolBoosterCreated(\\n _poolBoosterAddress,\\n _ammPoolAddress,\\n _boosterType,\\n msg.sender // address of the factory\\n );\\n }\\n\\n /**\\n * @notice Emits a pool booster removed event\\n * @dev This has been created as a convenience method for the monitoring to have\\n * an index of all of the removed pool boosters by only listening to the\\n * events of this contract.\\n * @param _poolBoosterAddress address of the pool booster to be removed\\n */\\n function emitPoolBoosterRemoved(address _poolBoosterAddress)\\n external\\n onlyApprovedFactories\\n {\\n emit PoolBoosterRemoved(_poolBoosterAddress);\\n }\\n\\n /**\\n * @notice Returns true if the factory is approved\\n * @param _factoryAddress address of the factory\\n */\\n function isApprovedFactory(address _factoryAddress)\\n public\\n view\\n returns (bool)\\n {\\n uint256 length = factories.length;\\n for (uint256 i = 0; i < length; i++) {\\n if (factories[i] == _factoryAddress) {\\n return true;\\n }\\n }\\n return false;\\n }\\n\\n /**\\n * @notice Returns all supported factories\\n */\\n function getAllFactories() external view returns (address[] memory) {\\n return factories;\\n }\\n}\\n\",\"keccak256\":\"0x6a5b35a71a37b6df526d3272237d3196ac0ce377764450d7be711256694fa283\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x6080604052348015600f57600080fd5b5060186000601c565b6082565b6001600160a01b038116603b600080516020610bd18339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3600080516020610bd183398151915255565b610b40806100916000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80635d36b190116100715780635d36b19014610131578063672383c414610139578063a07505981461014c578063adda33c514610161578063c7af335214610174578063d38bfff41461017c57600080fd5b806307025229146100ae5780630c340a24146100c357806326cf3739146100e85780634b37c73f1461010b578063591290e81461011e575b600080fd5b6100c16100bc366004610901565b61018f565b005b6100cb6101fd565b6040516001600160a01b0390911681526020015b60405180910390f35b6100fb6100f6366004610901565b61021a565b60405190151581526020016100df565b6100c1610119366004610901565b61027b565b6100c161012c366004610923565b61047e565b6100c16104d8565b6100cb61014736600461096e565b61057e565b6101546105a8565b6040516100df9190610987565b6100c161016f366004610901565b61060a565b6100fb610747565b6100c161018a366004610901565b610778565b6101983361021a565b6101bd5760405162461bcd60e51b81526004016101b4906109d3565b60405180910390fd5b6040516001600160a01b03821681527fa6267ed4a9ecad83a4813a850e7214f9a7fdf6995314c1c5efa359123d99b67b906020015b60405180910390a150565b6000610215600080516020610aeb8339815191525490565b905090565b60008054815b8181101561027157836001600160a01b03166000828154811061024557610245610a0a565b6000918252602090912001546001600160a01b031603610269575060019392505050565b600101610220565b5060009392505050565b610283610747565b61029f5760405162461bcd60e51b81526004016101b490610a20565b6001600160a01b0381166102e75760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064016101b4565b6000805490805b8281101561041e57836001600160a01b03166000828154811061031357610313610a0a565b6000918252602090912001546001600160a01b03160361041657600061033a600185610a57565b8154811061034a5761034a610a0a565b600091825260208220015481546001600160a01b0390911691908390811061037457610374610a0a565b6000918252602082200180546001600160a01b0319166001600160a01b0393909316929092179091558054806103ac576103ac610a7e565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03861681527fafa2737b2090fa39c66b7348625f0c03726240f724defbc6216d679506f94441910160405180910390a16001915061041e565b6001016102ee565b508061043c5760405162461bcd60e51b81526004016101b4906109d3565b6040516001600160a01b03841681527fafa2737b2090fa39c66b7348625f0c03726240f724defbc6216d679506f94441906020015b60405180910390a1505050565b6104873361021a565b6104a35760405162461bcd60e51b81526004016101b4906109d3565b7f815a468ae1c240cd4e701cd11d7b89454db9d1c3e96c3ddda0b075e7612d5d68838383336040516104719493929190610a94565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146105735760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101b4565b61057c3361081c565b565b6000818154811061058e57600080fd5b6000918252602090912001546001600160a01b0316905081565b6060600080548060200260200160405190810160405280929190818152602001828054801561060057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116105e2575b5050505050905090565b610612610747565b61062e5760405162461bcd60e51b81526004016101b490610a20565b6001600160a01b0381166106765760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064016101b4565b61067f8161021a565b156106cc5760405162461bcd60e51b815260206004820152601860248201527f466163746f727920616c726561647920617070726f766564000000000000000060448201526064016101b4565b600080546001810182559080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5630180546001600160a01b0319166001600160a01b0383169081179091556040519081527f4378f1462a48772813c3eb384aaee78cca44eb9a24b228a0118c8f4a8e5e3fd5906020016101f2565b600061075f600080516020610aeb8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b610780610747565b61079c5760405162461bcd60e51b81526004016101b490610a20565b6107c4817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166107e4600080516020610aeb8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6001600160a01b0381166108725760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101b4565b61087b8161087e565b50565b806001600160a01b031661089e600080516020610aeb8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3600080516020610aeb83398151915255565b80356001600160a01b03811681146108fc57600080fd5b919050565b60006020828403121561091357600080fd5b61091c826108e5565b9392505050565b60008060006060848603121561093857600080fd5b610941846108e5565b925061094f602085016108e5565b915060408401356004811061096357600080fd5b809150509250925092565b60006020828403121561098057600080fd5b5035919050565b602080825282518282018190526000918401906040840190835b818110156109c85783516001600160a01b03168352602093840193909201916001016109a1565b509095945050505050565b60208082526017908201527f4e6f7420616e20617070726f76656420666163746f7279000000000000000000604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b81810381811115610a7857634e487b7160e01b600052601160045260246000fd5b92915050565b634e487b7160e01b600052603160045260246000fd5b6001600160a01b038581168252841660208201526080810160048410610aca57634e487b7160e01b600052602160045260246000fd5b60408201939093526001600160a01b03919091166060909101529291505056fe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220af91f6cee8e3e995189ed4e165ec2ce1025b2abe78e5572e7c1c64e69021584764736f6c634300081c00337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80635d36b190116100715780635d36b19014610131578063672383c414610139578063a07505981461014c578063adda33c514610161578063c7af335214610174578063d38bfff41461017c57600080fd5b806307025229146100ae5780630c340a24146100c357806326cf3739146100e85780634b37c73f1461010b578063591290e81461011e575b600080fd5b6100c16100bc366004610901565b61018f565b005b6100cb6101fd565b6040516001600160a01b0390911681526020015b60405180910390f35b6100fb6100f6366004610901565b61021a565b60405190151581526020016100df565b6100c1610119366004610901565b61027b565b6100c161012c366004610923565b61047e565b6100c16104d8565b6100cb61014736600461096e565b61057e565b6101546105a8565b6040516100df9190610987565b6100c161016f366004610901565b61060a565b6100fb610747565b6100c161018a366004610901565b610778565b6101983361021a565b6101bd5760405162461bcd60e51b81526004016101b4906109d3565b60405180910390fd5b6040516001600160a01b03821681527fa6267ed4a9ecad83a4813a850e7214f9a7fdf6995314c1c5efa359123d99b67b906020015b60405180910390a150565b6000610215600080516020610aeb8339815191525490565b905090565b60008054815b8181101561027157836001600160a01b03166000828154811061024557610245610a0a565b6000918252602090912001546001600160a01b031603610269575060019392505050565b600101610220565b5060009392505050565b610283610747565b61029f5760405162461bcd60e51b81526004016101b490610a20565b6001600160a01b0381166102e75760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064016101b4565b6000805490805b8281101561041e57836001600160a01b03166000828154811061031357610313610a0a565b6000918252602090912001546001600160a01b03160361041657600061033a600185610a57565b8154811061034a5761034a610a0a565b600091825260208220015481546001600160a01b0390911691908390811061037457610374610a0a565b6000918252602082200180546001600160a01b0319166001600160a01b0393909316929092179091558054806103ac576103ac610a7e565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03861681527fafa2737b2090fa39c66b7348625f0c03726240f724defbc6216d679506f94441910160405180910390a16001915061041e565b6001016102ee565b508061043c5760405162461bcd60e51b81526004016101b4906109d3565b6040516001600160a01b03841681527fafa2737b2090fa39c66b7348625f0c03726240f724defbc6216d679506f94441906020015b60405180910390a1505050565b6104873361021a565b6104a35760405162461bcd60e51b81526004016101b4906109d3565b7f815a468ae1c240cd4e701cd11d7b89454db9d1c3e96c3ddda0b075e7612d5d68838383336040516104719493929190610a94565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146105735760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101b4565b61057c3361081c565b565b6000818154811061058e57600080fd5b6000918252602090912001546001600160a01b0316905081565b6060600080548060200260200160405190810160405280929190818152602001828054801561060057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116105e2575b5050505050905090565b610612610747565b61062e5760405162461bcd60e51b81526004016101b490610a20565b6001600160a01b0381166106765760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064016101b4565b61067f8161021a565b156106cc5760405162461bcd60e51b815260206004820152601860248201527f466163746f727920616c726561647920617070726f766564000000000000000060448201526064016101b4565b600080546001810182559080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5630180546001600160a01b0319166001600160a01b0383169081179091556040519081527f4378f1462a48772813c3eb384aaee78cca44eb9a24b228a0118c8f4a8e5e3fd5906020016101f2565b600061075f600080516020610aeb8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b610780610747565b61079c5760405162461bcd60e51b81526004016101b490610a20565b6107c4817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166107e4600080516020610aeb8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6001600160a01b0381166108725760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101b4565b61087b8161087e565b50565b806001600160a01b031661089e600080516020610aeb8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3600080516020610aeb83398151915255565b80356001600160a01b03811681146108fc57600080fd5b919050565b60006020828403121561091357600080fd5b61091c826108e5565b9392505050565b60008060006060848603121561093857600080fd5b610941846108e5565b925061094f602085016108e5565b915060408401356004811061096357600080fd5b809150509250925092565b60006020828403121561098057600080fd5b5035919050565b602080825282518282018190526000918401906040840190835b818110156109c85783516001600160a01b03168352602093840193909201916001016109a1565b509095945050505050565b60208082526017908201527f4e6f7420616e20617070726f76656420666163746f7279000000000000000000604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b81810381811115610a7857634e487b7160e01b600052601160045260246000fd5b92915050565b634e487b7160e01b600052603160045260246000fd5b6001600160a01b038581168252841660208201526080810160048410610aca57634e487b7160e01b600052602160045260246000fd5b60408201939093526001600160a01b03919091166060909101529291505056fe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220af91f6cee8e3e995189ed4e165ec2ce1025b2abe78e5572e7c1c64e69021584764736f6c634300081c0033", + "numDeployments": 2, + "solcInputHash": "ccb211e9f959f709b1d7b46e0ef9348f", + "metadata": "{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"factoryAddress\",\"type\":\"address\"}],\"name\":\"FactoryApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"factoryAddress\",\"type\":\"address\"}],\"name\":\"FactoryRemoved\",\"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\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"poolBoosterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"ammPoolAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enum IPoolBoostCentralRegistry.PoolBoosterType\",\"name\":\"poolBoosterType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"factoryAddress\",\"type\":\"address\"}],\"name\":\"PoolBoosterCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"poolBoosterAddress\",\"type\":\"address\"}],\"name\":\"PoolBoosterRemoved\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_factoryAddress\",\"type\":\"address\"}],\"name\":\"approveFactory\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_poolBoosterAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ammPoolAddress\",\"type\":\"address\"},{\"internalType\":\"enum IPoolBoostCentralRegistry.PoolBoosterType\",\"name\":\"_boosterType\",\"type\":\"uint8\"}],\"name\":\"emitPoolBoosterCreated\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_poolBoosterAddress\",\"type\":\"address\"}],\"name\":\"emitPoolBoosterRemoved\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"factories\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllFactories\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_factoryAddress\",\"type\":\"address\"}],\"name\":\"isApprovedFactory\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_factoryAddress\",\"type\":\"address\"}],\"name\":\"removeFactory\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"approveFactory(address)\":{\"params\":{\"_factoryAddress\":\"address of the factory\"}},\"emitPoolBoosterCreated(address,address,uint8)\":{\"details\":\"This has been created as a convenience method for the monitoring to have an index of all of the created pool boosters by only listening to the events of this contract.\",\"params\":{\"_ammPoolAddress\":\"address of the AMM pool forwarding yield to the pool booster\",\"_boosterType\":\"PoolBoosterType the type of the pool booster\",\"_poolBoosterAddress\":\"address of the pool booster created\"}},\"emitPoolBoosterRemoved(address)\":{\"details\":\"This has been created as a convenience method for the monitoring to have an index of all of the removed pool boosters by only listening to the events of this contract.\",\"params\":{\"_poolBoosterAddress\":\"address of the pool booster to be removed\"}},\"isApprovedFactory(address)\":{\"params\":{\"_factoryAddress\":\"address of the factory\"}},\"removeFactory(address)\":{\"params\":{\"_factoryAddress\":\"address of the factory\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}}},\"title\":\"Contract that holds all governance approved pool booster Factory implementation deployments\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"approveFactory(address)\":{\"notice\":\"Adds a factory address to the approved factory addresses\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"emitPoolBoosterCreated(address,address,uint8)\":{\"notice\":\"Emits a pool booster created event\"},\"emitPoolBoosterRemoved(address)\":{\"notice\":\"Emits a pool booster removed event\"},\"getAllFactories()\":{\"notice\":\"Returns all supported factories\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isApprovedFactory(address)\":{\"notice\":\"Returns true if the factory is approved\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"removeFactory(address)\":{\"notice\":\"Removes the factory from approved factory addresses\"},\"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\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/poolBooster/PoolBoostCentralRegistry.sol\":\"PoolBoostCentralRegistry\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"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/poolBooster/IPoolBoostCentralRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface IPoolBoostCentralRegistry {\\n /**\\n * @dev all the supported pool booster types are listed here. It is possible\\n * to have multiple versions of the factory that supports the same type of\\n * pool booster. Factories are immutable and this can happen when a factory\\n * or related pool booster required code update.\\n * e.g. \\\"PoolBoosterSwapxDouble\\\" & \\\"PoolBoosterSwapxDouble_v2\\\"\\n */\\n enum PoolBoosterType {\\n // Supports bribing 2 contracts per pool. Appropriate for Ichi vault concentrated\\n // liquidity pools where (which is expected in most/all cases) both pool gauges\\n // require bribing.\\n SwapXDoubleBooster,\\n // Supports bribing a single contract per pool. Appropriate for Classic Stable &\\n // Classic Volatile pools and Ichi vaults where only 1 side (1 of the 2 gauges)\\n // needs bribing\\n SwapXSingleBooster,\\n // Supports bribing a single contract per pool. Appropriate for Metropolis pools\\n MetropolisBooster,\\n // Supports creating a Merkl campaign.\\n MerklBooster,\\n // Supports creating a plain Curve pool booster\\n CurvePoolBoosterPlain\\n }\\n\\n struct PoolBoosterEntry {\\n address boosterAddress;\\n address ammPoolAddress;\\n PoolBoosterType boosterType;\\n }\\n\\n event PoolBoosterCreated(\\n address poolBoosterAddress,\\n address ammPoolAddress,\\n PoolBoosterType poolBoosterType,\\n address factoryAddress\\n );\\n event PoolBoosterRemoved(address poolBoosterAddress);\\n\\n function emitPoolBoosterCreated(\\n address _poolBoosterAddress,\\n address _ammPoolAddress,\\n PoolBoosterType _boosterType\\n ) external;\\n\\n function emitPoolBoosterRemoved(address _poolBoosterAddress) external;\\n}\\n\",\"keccak256\":\"0x3f7d5370c5627b341b1612904d1730e8049f07fc11a242f6bd87602309a252ed\",\"license\":\"BUSL-1.1\"},\"contracts/poolBooster/PoolBoostCentralRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { IPoolBoostCentralRegistry } from \\\"../interfaces/poolBooster/IPoolBoostCentralRegistry.sol\\\";\\n\\n/**\\n * @title Contract that holds all governance approved pool booster Factory\\n * implementation deployments\\n * @author Origin Protocol Inc\\n */\\ncontract PoolBoostCentralRegistry is Governable, IPoolBoostCentralRegistry {\\n event FactoryApproved(address factoryAddress);\\n event FactoryRemoved(address factoryAddress);\\n\\n // @notice List of approved factories\\n address[] public factories;\\n\\n modifier onlyApprovedFactories() {\\n require(isApprovedFactory(msg.sender), \\\"Not an approved factory\\\");\\n _;\\n }\\n\\n constructor() {\\n // set the governor of the implementation contract to zero address\\n _setGovernor(address(0));\\n }\\n\\n /**\\n * @notice Adds a factory address to the approved factory addresses\\n * @param _factoryAddress address of the factory\\n */\\n function approveFactory(address _factoryAddress) external onlyGovernor {\\n require(_factoryAddress != address(0), \\\"Invalid address\\\");\\n require(\\n !isApprovedFactory(_factoryAddress),\\n \\\"Factory already approved\\\"\\n );\\n\\n factories.push(_factoryAddress);\\n emit FactoryApproved(_factoryAddress);\\n }\\n\\n /**\\n * @notice Removes the factory from approved factory addresses\\n * @param _factoryAddress address of the factory\\n */\\n function removeFactory(address _factoryAddress) external onlyGovernor {\\n require(_factoryAddress != address(0), \\\"Invalid address\\\");\\n\\n uint256 length = factories.length;\\n bool factoryRemoved = false;\\n for (uint256 i = 0; i < length; i++) {\\n if (factories[i] != _factoryAddress) {\\n continue;\\n }\\n\\n factories[i] = factories[length - 1];\\n factories.pop();\\n emit FactoryRemoved(_factoryAddress);\\n factoryRemoved = true;\\n break;\\n }\\n require(factoryRemoved, \\\"Not an approved factory\\\");\\n\\n emit FactoryRemoved(_factoryAddress);\\n }\\n\\n /**\\n * @notice Emits a pool booster created event\\n * @dev This has been created as a convenience method for the monitoring to have\\n * an index of all of the created pool boosters by only listening to the\\n * events of this contract.\\n * @param _poolBoosterAddress address of the pool booster created\\n * @param _ammPoolAddress address of the AMM pool forwarding yield to the pool booster\\n * @param _boosterType PoolBoosterType the type of the pool booster\\n */\\n function emitPoolBoosterCreated(\\n address _poolBoosterAddress,\\n address _ammPoolAddress,\\n PoolBoosterType _boosterType\\n ) external onlyApprovedFactories {\\n emit PoolBoosterCreated(\\n _poolBoosterAddress,\\n _ammPoolAddress,\\n _boosterType,\\n msg.sender // address of the factory\\n );\\n }\\n\\n /**\\n * @notice Emits a pool booster removed event\\n * @dev This has been created as a convenience method for the monitoring to have\\n * an index of all of the removed pool boosters by only listening to the\\n * events of this contract.\\n * @param _poolBoosterAddress address of the pool booster to be removed\\n */\\n function emitPoolBoosterRemoved(address _poolBoosterAddress)\\n external\\n onlyApprovedFactories\\n {\\n emit PoolBoosterRemoved(_poolBoosterAddress);\\n }\\n\\n /**\\n * @notice Returns true if the factory is approved\\n * @param _factoryAddress address of the factory\\n */\\n function isApprovedFactory(address _factoryAddress)\\n public\\n view\\n returns (bool)\\n {\\n uint256 length = factories.length;\\n for (uint256 i = 0; i < length; i++) {\\n if (factories[i] == _factoryAddress) {\\n return true;\\n }\\n }\\n return false;\\n }\\n\\n /**\\n * @notice Returns all supported factories\\n */\\n function getAllFactories() external view returns (address[] memory) {\\n return factories;\\n }\\n}\\n\",\"keccak256\":\"0x6a5b35a71a37b6df526d3272237d3196ac0ce377764450d7be711256694fa283\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x6080604052348015600f57600080fd5b5060186000601c565b6082565b6001600160a01b038116603b600080516020610bd18339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3600080516020610bd183398151915255565b610b40806100916000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80635d36b190116100715780635d36b19014610131578063672383c414610139578063a07505981461014c578063adda33c514610161578063c7af335214610174578063d38bfff41461017c57600080fd5b806307025229146100ae5780630c340a24146100c357806326cf3739146100e85780634b37c73f1461010b578063591290e81461011e575b600080fd5b6100c16100bc366004610901565b61018f565b005b6100cb6101fd565b6040516001600160a01b0390911681526020015b60405180910390f35b6100fb6100f6366004610901565b61021a565b60405190151581526020016100df565b6100c1610119366004610901565b61027b565b6100c161012c366004610923565b61047e565b6100c16104d8565b6100cb61014736600461096e565b61057e565b6101546105a8565b6040516100df9190610987565b6100c161016f366004610901565b61060a565b6100fb610747565b6100c161018a366004610901565b610778565b6101983361021a565b6101bd5760405162461bcd60e51b81526004016101b4906109d3565b60405180910390fd5b6040516001600160a01b03821681527fa6267ed4a9ecad83a4813a850e7214f9a7fdf6995314c1c5efa359123d99b67b906020015b60405180910390a150565b6000610215600080516020610aeb8339815191525490565b905090565b60008054815b8181101561027157836001600160a01b03166000828154811061024557610245610a0a565b6000918252602090912001546001600160a01b031603610269575060019392505050565b600101610220565b5060009392505050565b610283610747565b61029f5760405162461bcd60e51b81526004016101b490610a20565b6001600160a01b0381166102e75760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064016101b4565b6000805490805b8281101561041e57836001600160a01b03166000828154811061031357610313610a0a565b6000918252602090912001546001600160a01b03160361041657600061033a600185610a57565b8154811061034a5761034a610a0a565b600091825260208220015481546001600160a01b0390911691908390811061037457610374610a0a565b6000918252602082200180546001600160a01b0319166001600160a01b0393909316929092179091558054806103ac576103ac610a7e565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03861681527fafa2737b2090fa39c66b7348625f0c03726240f724defbc6216d679506f94441910160405180910390a16001915061041e565b6001016102ee565b508061043c5760405162461bcd60e51b81526004016101b4906109d3565b6040516001600160a01b03841681527fafa2737b2090fa39c66b7348625f0c03726240f724defbc6216d679506f94441906020015b60405180910390a1505050565b6104873361021a565b6104a35760405162461bcd60e51b81526004016101b4906109d3565b7f815a468ae1c240cd4e701cd11d7b89454db9d1c3e96c3ddda0b075e7612d5d68838383336040516104719493929190610a94565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146105735760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101b4565b61057c3361081c565b565b6000818154811061058e57600080fd5b6000918252602090912001546001600160a01b0316905081565b6060600080548060200260200160405190810160405280929190818152602001828054801561060057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116105e2575b5050505050905090565b610612610747565b61062e5760405162461bcd60e51b81526004016101b490610a20565b6001600160a01b0381166106765760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064016101b4565b61067f8161021a565b156106cc5760405162461bcd60e51b815260206004820152601860248201527f466163746f727920616c726561647920617070726f766564000000000000000060448201526064016101b4565b600080546001810182559080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5630180546001600160a01b0319166001600160a01b0383169081179091556040519081527f4378f1462a48772813c3eb384aaee78cca44eb9a24b228a0118c8f4a8e5e3fd5906020016101f2565b600061075f600080516020610aeb8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b610780610747565b61079c5760405162461bcd60e51b81526004016101b490610a20565b6107c4817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166107e4600080516020610aeb8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6001600160a01b0381166108725760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101b4565b61087b8161087e565b50565b806001600160a01b031661089e600080516020610aeb8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3600080516020610aeb83398151915255565b80356001600160a01b03811681146108fc57600080fd5b919050565b60006020828403121561091357600080fd5b61091c826108e5565b9392505050565b60008060006060848603121561093857600080fd5b610941846108e5565b925061094f602085016108e5565b915060408401356005811061096357600080fd5b809150509250925092565b60006020828403121561098057600080fd5b5035919050565b602080825282518282018190526000918401906040840190835b818110156109c85783516001600160a01b03168352602093840193909201916001016109a1565b509095945050505050565b60208082526017908201527f4e6f7420616e20617070726f76656420666163746f7279000000000000000000604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b81810381811115610a7857634e487b7160e01b600052601160045260246000fd5b92915050565b634e487b7160e01b600052603160045260246000fd5b6001600160a01b038581168252841660208201526080810160058410610aca57634e487b7160e01b600052602160045260246000fd5b60408201939093526001600160a01b03919091166060909101529291505056fe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220bf394ef6bf1dcdcd24b7a981f49c3bafae6f85d4d7de3024e00e725c1fe3e8e964736f6c634300081c00337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80635d36b190116100715780635d36b19014610131578063672383c414610139578063a07505981461014c578063adda33c514610161578063c7af335214610174578063d38bfff41461017c57600080fd5b806307025229146100ae5780630c340a24146100c357806326cf3739146100e85780634b37c73f1461010b578063591290e81461011e575b600080fd5b6100c16100bc366004610901565b61018f565b005b6100cb6101fd565b6040516001600160a01b0390911681526020015b60405180910390f35b6100fb6100f6366004610901565b61021a565b60405190151581526020016100df565b6100c1610119366004610901565b61027b565b6100c161012c366004610923565b61047e565b6100c16104d8565b6100cb61014736600461096e565b61057e565b6101546105a8565b6040516100df9190610987565b6100c161016f366004610901565b61060a565b6100fb610747565b6100c161018a366004610901565b610778565b6101983361021a565b6101bd5760405162461bcd60e51b81526004016101b4906109d3565b60405180910390fd5b6040516001600160a01b03821681527fa6267ed4a9ecad83a4813a850e7214f9a7fdf6995314c1c5efa359123d99b67b906020015b60405180910390a150565b6000610215600080516020610aeb8339815191525490565b905090565b60008054815b8181101561027157836001600160a01b03166000828154811061024557610245610a0a565b6000918252602090912001546001600160a01b031603610269575060019392505050565b600101610220565b5060009392505050565b610283610747565b61029f5760405162461bcd60e51b81526004016101b490610a20565b6001600160a01b0381166102e75760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064016101b4565b6000805490805b8281101561041e57836001600160a01b03166000828154811061031357610313610a0a565b6000918252602090912001546001600160a01b03160361041657600061033a600185610a57565b8154811061034a5761034a610a0a565b600091825260208220015481546001600160a01b0390911691908390811061037457610374610a0a565b6000918252602082200180546001600160a01b0319166001600160a01b0393909316929092179091558054806103ac576103ac610a7e565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03861681527fafa2737b2090fa39c66b7348625f0c03726240f724defbc6216d679506f94441910160405180910390a16001915061041e565b6001016102ee565b508061043c5760405162461bcd60e51b81526004016101b4906109d3565b6040516001600160a01b03841681527fafa2737b2090fa39c66b7348625f0c03726240f724defbc6216d679506f94441906020015b60405180910390a1505050565b6104873361021a565b6104a35760405162461bcd60e51b81526004016101b4906109d3565b7f815a468ae1c240cd4e701cd11d7b89454db9d1c3e96c3ddda0b075e7612d5d68838383336040516104719493929190610a94565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146105735760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101b4565b61057c3361081c565b565b6000818154811061058e57600080fd5b6000918252602090912001546001600160a01b0316905081565b6060600080548060200260200160405190810160405280929190818152602001828054801561060057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116105e2575b5050505050905090565b610612610747565b61062e5760405162461bcd60e51b81526004016101b490610a20565b6001600160a01b0381166106765760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064016101b4565b61067f8161021a565b156106cc5760405162461bcd60e51b815260206004820152601860248201527f466163746f727920616c726561647920617070726f766564000000000000000060448201526064016101b4565b600080546001810182559080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5630180546001600160a01b0319166001600160a01b0383169081179091556040519081527f4378f1462a48772813c3eb384aaee78cca44eb9a24b228a0118c8f4a8e5e3fd5906020016101f2565b600061075f600080516020610aeb8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b610780610747565b61079c5760405162461bcd60e51b81526004016101b490610a20565b6107c4817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166107e4600080516020610aeb8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6001600160a01b0381166108725760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101b4565b61087b8161087e565b50565b806001600160a01b031661089e600080516020610aeb8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3600080516020610aeb83398151915255565b80356001600160a01b03811681146108fc57600080fd5b919050565b60006020828403121561091357600080fd5b61091c826108e5565b9392505050565b60008060006060848603121561093857600080fd5b610941846108e5565b925061094f602085016108e5565b915060408401356005811061096357600080fd5b809150509250925092565b60006020828403121561098057600080fd5b5035919050565b602080825282518282018190526000918401906040840190835b818110156109c85783516001600160a01b03168352602093840193909201916001016109a1565b509095945050505050565b60208082526017908201527f4e6f7420616e20617070726f76656420666163746f7279000000000000000000604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b81810381811115610a7857634e487b7160e01b600052601160045260246000fd5b92915050565b634e487b7160e01b600052603160045260246000fd5b6001600160a01b038581168252841660208201526080810160058410610aca57634e487b7160e01b600052602160045260246000fd5b60408201939093526001600160a01b03919091166060909101529291505056fe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220bf394ef6bf1dcdcd24b7a981f49c3bafae6f85d4d7de3024e00e725c1fe3e8e964736f6c634300081c0033", "libraries": {}, "devdoc": { "author": "Origin Protocol Inc", @@ -393,7 +393,7 @@ "storageLayout": { "storage": [ { - "astId": 38273, + "astId": 3390, "contract": "contracts/poolBooster/PoolBoostCentralRegistry.sol:PoolBoostCentralRegistry", "label": "factories", "offset": 0, diff --git a/contracts/deployments/mainnet/solcInputs/ccb211e9f959f709b1d7b46e0ef9348f.json b/contracts/deployments/mainnet/solcInputs/ccb211e9f959f709b1d7b46e0ef9348f.json new file mode 100644 index 0000000000..8507a6d458 --- /dev/null +++ b/contracts/deployments/mainnet/solcInputs/ccb211e9f959f709b1d7b46e0ef9348f.json @@ -0,0 +1,114 @@ +{ + "language": "Solidity", + "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" + }, + "@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/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" + }, + "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() {\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/interfaces/ICampaignRemoteManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface ICampaignRemoteManager {\n function createCampaign(\n CampaignCreationParams memory params,\n uint256 destinationChainId,\n uint256 additionalGasLimit,\n address votemarket\n ) external payable;\n\n function manageCampaign(\n CampaignManagementParams memory params,\n uint256 destinationChainId,\n uint256 additionalGasLimit,\n address votemarket\n ) external payable;\n\n function closeCampaign(\n CampaignClosingParams memory params,\n uint256 destinationChainId,\n uint256 additionalGasLimit,\n address votemarket\n ) external payable;\n\n struct CampaignCreationParams {\n uint256 chainId;\n address gauge;\n address manager;\n address rewardToken;\n uint8 numberOfPeriods;\n uint256 maxRewardPerVote;\n uint256 totalRewardAmount;\n address[] addresses;\n address hook;\n bool isWhitelist;\n }\n\n struct CampaignManagementParams {\n uint256 campaignId;\n address rewardToken;\n uint8 numberOfPeriods;\n uint256 totalRewardAmount;\n uint256 maxRewardPerVote;\n }\n\n struct CampaignClosingParams {\n uint256 campaignId;\n }\n}\n" + }, + "contracts/interfaces/ICreateX.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.4;\n\n/**\n * @title CreateX Factory Interface Definition\n * @author pcaversaccio (https://web.archive.org/web/20230921103111/https://pcaversaccio.com/)\n * @custom:coauthor Matt Solomon (https://web.archive.org/web/20230921103335/https://mattsolomon.dev/)\n */\ninterface ICreateX {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* TYPES */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n struct Values {\n uint256 constructorAmount;\n uint256 initCallAmount;\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* EVENTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n event ContractCreation(address indexed newContract, bytes32 indexed salt);\n event ContractCreation(address indexed newContract);\n event Create3ProxyContractCreation(\n address indexed newContract,\n bytes32 indexed salt\n );\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n error FailedContractCreation(address emitter);\n error FailedContractInitialisation(address emitter, bytes revertData);\n error InvalidSalt(address emitter);\n error InvalidNonceValue(address emitter);\n error FailedEtherTransfer(address emitter, bytes revertData);\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CREATE */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n function deployCreate(bytes memory initCode)\n external\n payable\n returns (address newContract);\n\n function deployCreateAndInit(\n bytes memory initCode,\n bytes memory data,\n Values memory values,\n address refundAddress\n ) external payable returns (address newContract);\n\n function deployCreateAndInit(\n bytes memory initCode,\n bytes memory data,\n Values memory values\n ) external payable returns (address newContract);\n\n function deployCreateClone(address implementation, bytes memory data)\n external\n payable\n returns (address proxy);\n\n function computeCreateAddress(address deployer, uint256 nonce)\n external\n view\n returns (address computedAddress);\n\n function computeCreateAddress(uint256 nonce)\n external\n view\n returns (address computedAddress);\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CREATE2 */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n function deployCreate2(bytes32 salt, bytes memory initCode)\n external\n payable\n returns (address newContract);\n\n function deployCreate2(bytes memory initCode)\n external\n payable\n returns (address newContract);\n\n function deployCreate2AndInit(\n bytes32 salt,\n bytes memory initCode,\n bytes memory data,\n Values memory values,\n address refundAddress\n ) external payable returns (address newContract);\n\n function deployCreate2AndInit(\n bytes32 salt,\n bytes memory initCode,\n bytes memory data,\n Values memory values\n ) external payable returns (address newContract);\n\n function deployCreate2AndInit(\n bytes memory initCode,\n bytes memory data,\n Values memory values,\n address refundAddress\n ) external payable returns (address newContract);\n\n function deployCreate2AndInit(\n bytes memory initCode,\n bytes memory data,\n Values memory values\n ) external payable returns (address newContract);\n\n function deployCreate2Clone(\n bytes32 salt,\n address implementation,\n bytes memory data\n ) external payable returns (address proxy);\n\n function deployCreate2Clone(address implementation, bytes memory data)\n external\n payable\n returns (address proxy);\n\n function computeCreate2Address(\n bytes32 salt,\n bytes32 initCodeHash,\n address deployer\n ) external pure returns (address computedAddress);\n\n function computeCreate2Address(bytes32 salt, bytes32 initCodeHash)\n external\n view\n returns (address computedAddress);\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CREATE3 */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n function deployCreate3(bytes32 salt, bytes memory initCode)\n external\n payable\n returns (address newContract);\n\n function deployCreate3(bytes memory initCode)\n external\n payable\n returns (address newContract);\n\n function deployCreate3AndInit(\n bytes32 salt,\n bytes memory initCode,\n bytes memory data,\n Values memory values,\n address refundAddress\n ) external payable returns (address newContract);\n\n function deployCreate3AndInit(\n bytes32 salt,\n bytes memory initCode,\n bytes memory data,\n Values memory values\n ) external payable returns (address newContract);\n\n function deployCreate3AndInit(\n bytes memory initCode,\n bytes memory data,\n Values memory values,\n address refundAddress\n ) external payable returns (address newContract);\n\n function deployCreate3AndInit(\n bytes memory initCode,\n bytes memory data,\n Values memory values\n ) external payable returns (address newContract);\n\n function computeCreate3Address(bytes32 salt, address deployer)\n external\n pure\n returns (address computedAddress);\n\n function computeCreate3Address(bytes32 salt)\n external\n view\n returns (address computedAddress);\n}\n" + }, + "contracts/interfaces/poolBooster/IMerklDistributor.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IMerklDistributor {\n struct CampaignParameters {\n // POPULATED ONCE CREATED\n\n // ID of the campaign. This can be left as a null bytes32 when creating campaigns\n // on Merkl.\n bytes32 campaignId;\n // CHOSEN BY CAMPAIGN CREATOR\n\n // Address of the campaign creator, if marked as address(0), it will be overriden with the\n // address of the `msg.sender` creating the campaign\n address creator;\n // Address of the token used as a reward\n address rewardToken;\n // Amount of `rewardToken` to distribute across all the epochs\n // Amount distributed per epoch is `amount/numEpoch`\n uint256 amount;\n // Type of campaign\n uint32 campaignType;\n // Timestamp at which the campaign should start\n uint32 startTimestamp;\n // Duration of the campaign in seconds. Has to be a multiple of EPOCH = 3600\n uint32 duration;\n // Extra data to pass to specify the campaign\n bytes campaignData;\n }\n\n function createCampaign(CampaignParameters memory newCampaign)\n external\n returns (bytes32);\n\n function signAndCreateCampaign(\n CampaignParameters memory newCampaign,\n bytes memory _signature\n ) external returns (bytes32);\n\n function sign(bytes memory _signature) external;\n\n function rewardTokenMinAmounts(address _rewardToken)\n external\n view\n returns (uint256);\n}\n" + }, + "contracts/interfaces/poolBooster/IPoolBoostCentralRegistry.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IPoolBoostCentralRegistry {\n /**\n * @dev all the supported pool booster types are listed here. It is possible\n * to have multiple versions of the factory that supports the same type of\n * pool booster. Factories are immutable and this can happen when a factory\n * or related pool booster required code update.\n * e.g. \"PoolBoosterSwapxDouble\" & \"PoolBoosterSwapxDouble_v2\"\n */\n enum PoolBoosterType {\n // Supports bribing 2 contracts per pool. Appropriate for Ichi vault concentrated\n // liquidity pools where (which is expected in most/all cases) both pool gauges\n // require bribing.\n SwapXDoubleBooster,\n // Supports bribing a single contract per pool. Appropriate for Classic Stable &\n // Classic Volatile pools and Ichi vaults where only 1 side (1 of the 2 gauges)\n // needs bribing\n SwapXSingleBooster,\n // Supports bribing a single contract per pool. Appropriate for Metropolis pools\n MetropolisBooster,\n // Supports creating a Merkl campaign.\n MerklBooster,\n // Supports creating a plain Curve pool booster\n CurvePoolBoosterPlain\n }\n\n struct PoolBoosterEntry {\n address boosterAddress;\n address ammPoolAddress;\n PoolBoosterType boosterType;\n }\n\n event PoolBoosterCreated(\n address poolBoosterAddress,\n address ammPoolAddress,\n PoolBoosterType poolBoosterType,\n address factoryAddress\n );\n event PoolBoosterRemoved(address poolBoosterAddress);\n\n function emitPoolBoosterCreated(\n address _poolBoosterAddress,\n address _ammPoolAddress,\n PoolBoosterType _boosterType\n ) external;\n\n function emitPoolBoosterRemoved(address _poolBoosterAddress) external;\n}\n" + }, + "contracts/interfaces/poolBooster/IPoolBooster.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface IPoolBooster {\n event BribeExecuted(uint256 amount);\n\n /// @notice Execute the bribe action\n function bribe() external;\n}\n" + }, + "contracts/interfaces/poolBooster/ISwapXAlgebraBribe.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IBribe {\n /// @notice Notify a bribe amount\n /// @dev Rewards are saved into NEXT EPOCH mapping.\n function notifyRewardAmount(address _rewardsToken, uint256 reward) external;\n}\n" + }, + "contracts/poolBooster/AbstractPoolBoosterFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IPoolBooster } from \"../interfaces/poolBooster/IPoolBooster.sol\";\nimport { IPoolBoostCentralRegistry } from \"../interfaces/poolBooster/IPoolBoostCentralRegistry.sol\";\n\n/**\n * @title Abstract Pool booster factory\n * @author Origin Protocol Inc\n */\ncontract AbstractPoolBoosterFactory is Governable {\n struct PoolBoosterEntry {\n address boosterAddress;\n address ammPoolAddress;\n IPoolBoostCentralRegistry.PoolBoosterType boosterType;\n }\n\n // @notice address of Origin Token\n address public immutable oToken;\n // @notice Central registry contract\n IPoolBoostCentralRegistry public immutable centralRegistry;\n\n // @notice list of all the pool boosters created by this factory\n PoolBoosterEntry[] public poolBoosters;\n // @notice mapping of AMM pool to pool booster\n mapping(address => PoolBoosterEntry) public poolBoosterFromPool;\n\n // @param address _oToken address of the OToken token\n // @param address _governor address governor\n // @param address _centralRegistry address of the central registry\n constructor(\n address _oToken,\n address _governor,\n address _centralRegistry\n ) {\n require(_oToken != address(0), \"Invalid oToken address\");\n require(_governor != address(0), \"Invalid governor address\");\n require(\n _centralRegistry != address(0),\n \"Invalid central registry address\"\n );\n\n oToken = _oToken;\n centralRegistry = IPoolBoostCentralRegistry(_centralRegistry);\n _setGovernor(_governor);\n }\n\n /**\n * @notice Goes over all the pool boosters created by this factory and\n * calls bribe() on them.\n * @param _exclusionList A list of pool booster addresses to skip when\n * calling this function.\n */\n function bribeAll(address[] memory _exclusionList) external {\n uint256 lengthI = poolBoosters.length;\n for (uint256 i = 0; i < lengthI; i++) {\n address poolBoosterAddress = poolBoosters[i].boosterAddress;\n bool skipBribeCall = false;\n uint256 lengthJ = _exclusionList.length;\n for (uint256 j = 0; j < lengthJ; j++) {\n // pool booster in exclusion list\n if (_exclusionList[j] == poolBoosterAddress) {\n skipBribeCall = true;\n break;\n }\n }\n\n if (!skipBribeCall) {\n IPoolBooster(poolBoosterAddress).bribe();\n }\n }\n }\n\n /**\n * @notice Removes the pool booster from the internal list of pool boosters.\n * @dev This action does not destroy the pool booster contract nor does it\n * stop the yield delegation to it.\n * @param _poolBoosterAddress address of the pool booster\n */\n function removePoolBooster(address _poolBoosterAddress)\n external\n onlyGovernor\n {\n uint256 boostersLen = poolBoosters.length;\n for (uint256 i = 0; i < boostersLen; ++i) {\n if (poolBoosters[i].boosterAddress == _poolBoosterAddress) {\n // erase mapping\n delete poolBoosterFromPool[poolBoosters[i].ammPoolAddress];\n\n // overwrite current pool booster with the last entry in the list\n poolBoosters[i] = poolBoosters[boostersLen - 1];\n // drop the last entry\n poolBoosters.pop();\n\n centralRegistry.emitPoolBoosterRemoved(_poolBoosterAddress);\n break;\n }\n }\n }\n\n function _storePoolBoosterEntry(\n address _poolBoosterAddress,\n address _ammPoolAddress,\n IPoolBoostCentralRegistry.PoolBoosterType _boosterType\n ) internal {\n PoolBoosterEntry memory entry = PoolBoosterEntry(\n _poolBoosterAddress,\n _ammPoolAddress,\n _boosterType\n );\n\n poolBoosters.push(entry);\n poolBoosterFromPool[_ammPoolAddress] = entry;\n\n // emit the events of the pool booster created\n centralRegistry.emitPoolBoosterCreated(\n _poolBoosterAddress,\n _ammPoolAddress,\n _boosterType\n );\n }\n\n function _deployContract(bytes memory _bytecode, uint256 _salt)\n internal\n returns (address _address)\n {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n _address := create2(\n 0,\n add(_bytecode, 0x20),\n mload(_bytecode),\n _salt\n )\n }\n\n require(\n _address.code.length > 0 && _address != address(0),\n \"Failed creating a pool booster\"\n );\n }\n\n // pre-compute the address of the deployed contract that will be\n // created when create2 is called\n function _computeAddress(bytes memory _bytecode, uint256 _salt)\n internal\n view\n returns (address)\n {\n bytes32 hash = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n _salt,\n keccak256(_bytecode)\n )\n );\n\n // cast last 20 bytes of hash to address\n return address(uint160(uint256(hash)));\n }\n\n function poolBoosterLength() external view returns (uint256) {\n return poolBoosters.length;\n }\n}\n" + }, + "contracts/poolBooster/CurvePoolBooster.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 { Initializable } from \"../utils/Initializable.sol\";\nimport { Strategizable } from \"../governance/Strategizable.sol\";\nimport { ICampaignRemoteManager } from \"../interfaces/ICampaignRemoteManager.sol\";\n\n/// @title CurvePoolBooster\n/// @author Origin Protocol\n/// @notice Contract to manage interactions with VotemarketV2 for a dedicated Curve pool/gauge.\ncontract CurvePoolBooster is Initializable, Strategizable {\n using SafeERC20 for IERC20;\n\n ////////////////////////////////////////////////////\n /// --- CONSTANTS && IMMUTABLES\n ////////////////////////////////////////////////////\n /// @notice Base fee for the contract, 100%\n uint16 public constant FEE_BASE = 10_000;\n\n /// @notice Arbitrum where the votemarket is running\n uint256 public constant targetChainId = 42161;\n\n /// @notice Address of the gauge to manage\n address public immutable gauge;\n\n /// @notice Address of the reward token\n address public immutable rewardToken;\n\n ////////////////////////////////////////////////////\n /// --- STORAGE\n ////////////////////////////////////////////////////\n\n /// @notice Fee in FEE_BASE unit payed when managing campaign.\n uint16 public fee;\n\n /// @notice Address of the fee collector\n address public feeCollector;\n\n /// @notice Address of the campaignRemoteManager linked to VotemarketV2\n address public campaignRemoteManager;\n\n /// @notice Address of votemarket in L2\n address public votemarket;\n\n /// @notice Id of the campaign created\n uint256 public campaignId;\n\n ////////////////////////////////////////////////////\n /// --- EVENTS\n ////////////////////////////////////////////////////\n event FeeUpdated(uint16 newFee);\n event FeeCollected(address feeCollector, uint256 feeAmount);\n event FeeCollectorUpdated(address newFeeCollector);\n event VotemarketUpdated(address newVotemarket);\n event CampaignRemoteManagerUpdated(address newCampaignRemoteManager);\n event CampaignCreated(\n address gauge,\n address rewardToken,\n uint256 maxRewardPerVote,\n uint256 totalRewardAmount\n );\n event CampaignIdUpdated(uint256 newId);\n event CampaignClosed(uint256 campaignId);\n event TotalRewardAmountUpdated(uint256 extraTotalRewardAmount);\n event NumberOfPeriodsUpdated(uint8 extraNumberOfPeriods);\n event RewardPerVoteUpdated(uint256 newMaxRewardPerVote);\n event TokensRescued(address token, uint256 amount, address receiver);\n\n ////////////////////////////////////////////////////\n /// --- CONSTRUCTOR && INITIALIZATION\n ////////////////////////////////////////////////////\n constructor(address _rewardToken, address _gauge) {\n rewardToken = _rewardToken;\n gauge = _gauge;\n\n // Prevent implementation contract to be governed\n _setGovernor(address(0));\n }\n\n /// @notice initialize function, to set up initial internal state\n /// @param _strategist Address of the strategist\n /// @param _fee Fee in FEE_BASE unit payed when managing campaign\n /// @param _feeCollector Address of the fee collector\n function initialize(\n address _strategist,\n uint16 _fee,\n address _feeCollector,\n address _campaignRemoteManager,\n address _votemarket\n ) external onlyGovernor initializer {\n _setStrategistAddr(_strategist);\n _setFee(_fee);\n _setFeeCollector(_feeCollector);\n _setCampaignRemoteManager(_campaignRemoteManager);\n _setVotemarket(_votemarket);\n }\n\n ////////////////////////////////////////////////////\n /// --- MUTATIVE FUNCTIONS\n ////////////////////////////////////////////////////\n /// @notice Create a new campaign on VotemarketV2\n /// @dev This will use all token available in this contract\n /// @dev Caller must send ETH to pay for the bridge fee\n /// @param numberOfPeriods Duration of the campaign in weeks\n /// @param maxRewardPerVote Maximum reward per vote to distribute, to avoid overspending\n /// @param blacklist List of addresses to exclude from the campaign\n /// @param additionalGasLimit Additional gas limit for the bridge\n function createCampaign(\n uint8 numberOfPeriods,\n uint256 maxRewardPerVote,\n address[] calldata blacklist,\n uint256 additionalGasLimit\n ) external payable nonReentrant onlyGovernorOrStrategist {\n require(campaignId == 0, \"Campaign already created\");\n require(numberOfPeriods > 1, \"Invalid number of periods\");\n require(maxRewardPerVote > 0, \"Invalid reward per vote\");\n\n // Handle fee (if any)\n uint256 balanceSubFee = _handleFee();\n\n // Approve the balanceSubFee to the campaign manager\n IERC20(rewardToken).safeApprove(campaignRemoteManager, 0);\n IERC20(rewardToken).safeApprove(campaignRemoteManager, balanceSubFee);\n\n // Create a new campaign\n ICampaignRemoteManager(campaignRemoteManager).createCampaign{\n value: msg.value\n }(\n ICampaignRemoteManager.CampaignCreationParams({\n chainId: targetChainId,\n gauge: gauge,\n manager: address(this),\n rewardToken: rewardToken,\n numberOfPeriods: numberOfPeriods,\n maxRewardPerVote: maxRewardPerVote,\n totalRewardAmount: balanceSubFee,\n addresses: blacklist,\n hook: address(0),\n isWhitelist: false\n }),\n targetChainId,\n additionalGasLimit,\n votemarket\n );\n\n emit CampaignCreated(\n gauge,\n rewardToken,\n maxRewardPerVote,\n balanceSubFee\n );\n }\n\n /// @notice Manage campaign parameters in a single call\n /// @dev This function should be called after the campaign is created\n /// @dev Caller must send ETH to pay for the bridge fee\n /// @param totalRewardAmount Amount of reward tokens to add:\n /// - 0: no update\n /// - type(uint256).max: use all tokens in contract\n /// - other: use specific amount\n /// @param numberOfPeriods Number of additional periods (0 = no update)\n /// @param maxRewardPerVote New maximum reward per vote (0 = no update)\n /// @param additionalGasLimit Additional gas limit for the bridge\n function manageCampaign(\n uint256 totalRewardAmount,\n uint8 numberOfPeriods,\n uint256 maxRewardPerVote,\n uint256 additionalGasLimit\n ) external payable nonReentrant onlyGovernorOrStrategist {\n require(campaignId != 0, \"Campaign not created\");\n\n uint256 rewardAmount;\n\n if (totalRewardAmount != 0) {\n uint256 amount = min(\n IERC20(rewardToken).balanceOf(address(this)),\n totalRewardAmount\n );\n\n // Handle fee\n rewardAmount = _handleFee(amount);\n require(rewardAmount > 0, \"No reward to add\");\n\n // Approve the reward amount to the campaign manager\n IERC20(rewardToken).safeApprove(campaignRemoteManager, 0);\n IERC20(rewardToken).safeApprove(\n campaignRemoteManager,\n rewardAmount\n );\n }\n\n // Call remote manager\n ICampaignRemoteManager(campaignRemoteManager).manageCampaign{\n value: msg.value\n }(\n ICampaignRemoteManager.CampaignManagementParams({\n campaignId: campaignId,\n rewardToken: rewardToken,\n numberOfPeriods: numberOfPeriods,\n totalRewardAmount: rewardAmount,\n maxRewardPerVote: maxRewardPerVote\n }),\n targetChainId,\n additionalGasLimit,\n votemarket\n );\n\n // Emit relevant events\n if (rewardAmount > 0) {\n emit TotalRewardAmountUpdated(rewardAmount);\n }\n if (numberOfPeriods > 0) {\n emit NumberOfPeriodsUpdated(numberOfPeriods);\n }\n if (maxRewardPerVote > 0) {\n emit RewardPerVoteUpdated(maxRewardPerVote);\n }\n }\n\n /// @notice Close the campaign.\n /// @dev This function only work on the L2 chain. Not on mainnet.\n /// @dev Caller must send ETH to pay for the bridge fee\n /// @dev The _campaignId parameter is not related to the campaignId of this contract, allowing greater flexibility.\n /// @param _campaignId Id of the campaign to close\n /// @param additionalGasLimit Additional gas limit for the bridge\n // slither-disable-start reentrancy-eth\n function closeCampaign(uint256 _campaignId, uint256 additionalGasLimit)\n external\n payable\n nonReentrant\n onlyGovernorOrStrategist\n {\n ICampaignRemoteManager(campaignRemoteManager).closeCampaign{\n value: msg.value\n }(\n ICampaignRemoteManager.CampaignClosingParams({\n campaignId: campaignId\n }),\n targetChainId,\n additionalGasLimit,\n votemarket\n );\n campaignId = 0;\n emit CampaignClosed(_campaignId);\n }\n\n // slither-disable-end reentrancy-eth\n\n /// @notice Calculate the fee amount and transfer it to the feeCollector\n /// @dev Uses full contract balance\n /// @return Balance after fee\n function _handleFee() internal returns (uint256) {\n uint256 balance = IERC20(rewardToken).balanceOf(address(this));\n \n // This is not a problem if balance is 0, feeAmount will be 0 as well\n // We don't want to make the whole function revert just because of that.\n return _handleFee(balance);\n }\n\n /// @notice Calculate the fee amount and transfer it to the feeCollector\n /// @param amount Amount to take fee from\n /// @return Amount after fee\n function _handleFee(uint256 amount) internal returns (uint256) {\n uint256 feeAmount = (amount * fee) / FEE_BASE;\n\n // If there is a fee, transfer it to the feeCollector\n if (feeAmount > 0) {\n IERC20(rewardToken).safeTransfer(feeCollector, feeAmount);\n emit FeeCollected(feeCollector, feeAmount);\n }\n\n // Fetch balance again to avoid rounding issues\n return IERC20(rewardToken).balanceOf(address(this));\n }\n\n ////////////////////////////////////////////////////\n /// --- GOVERNANCE && OPERATION\n ////////////////////////////////////////////////////\n /// @notice Set the campaign id\n /// @dev Only callable by the governor or strategist\n /// @param _campaignId New campaign id\n function setCampaignId(uint256 _campaignId)\n external\n onlyGovernorOrStrategist\n {\n campaignId = _campaignId;\n emit CampaignIdUpdated(_campaignId);\n }\n\n /// @notice Rescue ETH from the contract\n /// @dev Only callable by the governor or strategist\n /// @param receiver Address to receive the ETH\n function rescueETH(address receiver)\n external\n nonReentrant\n onlyGovernorOrStrategist\n {\n require(receiver != address(0), \"Invalid receiver\");\n uint256 balance = address(this).balance;\n (bool success, ) = receiver.call{ value: balance }(\"\");\n require(success, \"Transfer failed\");\n emit TokensRescued(address(0), balance, receiver);\n }\n\n /// @notice Rescue ERC20 tokens from the contract\n /// @dev Only callable by the governor or strategist\n /// @param token Address of the token to rescue\n function rescueToken(address token, address receiver)\n external\n nonReentrant\n onlyGovernor\n {\n require(receiver != address(0), \"Invalid receiver\");\n uint256 balance = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransfer(receiver, balance);\n emit TokensRescued(token, balance, receiver);\n }\n\n /// @notice Set the fee\n /// @dev Only callable by the governor\n /// @param _fee New fee\n function setFee(uint16 _fee) external onlyGovernor {\n _setFee(_fee);\n }\n\n /// @notice Internal logic to set the fee\n function _setFee(uint16 _fee) internal {\n require(_fee <= FEE_BASE / 2, \"Fee too high\");\n fee = _fee;\n emit FeeUpdated(_fee);\n }\n\n /// @notice Set the fee collector\n /// @dev Only callable by the governor\n /// @param _feeCollector New fee collector\n function setFeeCollector(address _feeCollector) external onlyGovernor {\n _setFeeCollector(_feeCollector);\n }\n\n /// @notice Internal logic to set the fee collector\n function _setFeeCollector(address _feeCollector) internal {\n require(_feeCollector != address(0), \"Invalid fee collector\");\n feeCollector = _feeCollector;\n emit FeeCollectorUpdated(_feeCollector);\n }\n\n /// @notice Set the campaignRemoteManager\n /// @param _campaignRemoteManager New campaignRemoteManager address\n function setCampaignRemoteManager(address _campaignRemoteManager)\n external\n onlyGovernor\n {\n _setCampaignRemoteManager(_campaignRemoteManager);\n }\n\n /// @notice Internal logic to set the campaignRemoteManager\n /// @param _campaignRemoteManager New campaignRemoteManager address\n function _setCampaignRemoteManager(address _campaignRemoteManager)\n internal\n {\n require(\n _campaignRemoteManager != address(0),\n \"Invalid campaignRemoteManager\"\n );\n campaignRemoteManager = _campaignRemoteManager;\n emit CampaignRemoteManagerUpdated(_campaignRemoteManager);\n }\n\n /// @notice Set the votemarket address\n /// @param _votemarket New votemarket address\n function setVotemarket(address _votemarket) external onlyGovernor {\n _setVotemarket(_votemarket);\n }\n\n /// @notice Internal logic to set the votemarket address\n function _setVotemarket(address _votemarket) internal {\n require(_votemarket != address(0), \"Invalid votemarket\");\n votemarket = _votemarket;\n emit VotemarketUpdated(_votemarket);\n }\n\n /// @notice Return the minimum of two uint256 numbers\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n receive() external payable {}\n}\n" + }, + "contracts/poolBooster/CurvePoolBoosterFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport {ICreateX} from \"../interfaces/ICreateX.sol\";\nimport {Initializable} from \"../utils/Initializable.sol\";\nimport {Strategizable} from \"../governance/Strategizable.sol\";\nimport {CurvePoolBoosterPlain} from \"./CurvePoolBoosterPlain.sol\";\nimport {IPoolBoostCentralRegistry} from \"../interfaces/poolBooster/IPoolBoostCentralRegistry.sol\";\n\n/// @title CurvePoolBoosterFactory\n/// @author Origin Protocol\n/// @notice Factory contract to create CurvePoolBoosterPlain instances\ncontract CurvePoolBoosterFactory is Initializable, Strategizable {\n ////////////////////////////////////////////////////\n /// Structs\n ////////////////////////////////////////////////////\n struct PoolBoosterEntry {\n address boosterAddress;\n address ammPoolAddress;\n IPoolBoostCentralRegistry.PoolBoosterType boosterType;\n }\n\n ////////////////////////////////////////////////////\n /// Constants\n ////////////////////////////////////////////////////\n\n /// @notice Address of the CreateX contract\n ICreateX public constant CREATEX = ICreateX(0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed);\n\n ////////////////////////////////////////////////////\n /// Storage\n ////////////////////////////////////////////////////\n\n /// @notice list of all the pool boosters created by this factory\n PoolBoosterEntry[] public poolBoosters;\n /// @notice Central registry contract\n IPoolBoostCentralRegistry public centralRegistry;\n /// @notice mapping of AMM pool to pool booster\n mapping(address => PoolBoosterEntry) public poolBoosterFromPool;\n\n ////////////////////////////////////////////////////\n /// Initialize\n ////////////////////////////////////////////////////\n\n /// @notice Initialize the contract. Normally we'd rather have the governor and strategist set in the constructor,\n /// but since this contract is deployed by CreateX we need to set them in the initialize function because\n /// the constructor's parameters influence the address of the contract when deployed using CreateX.\n /// And having different governor and strategist on the same address on different chains would\n /// cause issues.\n /// @param _governor Address of the governor\n /// @param _strategist Address of the strategist\n /// @param _centralRegistry Address of the central registry\n function initialize(address _governor, address _strategist, address _centralRegistry) external initializer {\n _setGovernor(_governor);\n _setStrategistAddr(_strategist);\n centralRegistry = IPoolBoostCentralRegistry(_centralRegistry);\n }\n\n ////////////////////////////////////////////////////\n /// External Mutative Functions\n ////////////////////////////////////////////////////\n\n /// @notice Create a new CurvePoolBoosterPlain instance\n /// @param _rewardToken Address of the reward token (OETH or OUSD)\n /// @param _gauge Address of the gauge (e.g. Curve OETH/WETH Gauge)\n /// @param _feeCollector Address of the fee collector (e.g. MultichainStrategist)\n /// @param _fee Fee in FEE_BASE unit payed when managing campaign\n /// @param _campaignRemoteManager Address of the campaign remote manager\n /// @param _votemarket Address of the votemarket\n /// @param _salt A unique number that affects the address of the pool booster created. Note: this number\n /// should match the one from `computePoolBoosterAddress` in order for the final deployed address\n /// and pre-computed address to match\n /// @param _expectedAddress The expected address of the pool booster. This is used to verify that the pool booster\n /// was deployed at the expected address, otherwise the transaction batch will revert. If set to 0 then the\n /// address verification is skipped.\n function createCurvePoolBoosterPlain(\n address _rewardToken,\n address _gauge,\n address _feeCollector,\n uint16 _fee,\n address _campaignRemoteManager,\n address _votemarket,\n bytes32 _salt,\n address _expectedAddress\n ) external onlyGovernorOrStrategist returns (address) {\n require(governor() != address(0), \"Governor not set\");\n require(strategistAddr != address(0), \"Strategist not set\");\n // salt encoded sender\n address senderAddress = address(bytes20(_salt));\n // the contract that calls the CreateX should be encoded in the salt to protect against front-running\n require(senderAddress == address(this), \"Front-run protection failed\");\n\n address poolBoosterAddress = CREATEX.deployCreate2(_salt, _getInitCode(_rewardToken, _gauge));\n\n require(\n _expectedAddress == address(0) || poolBoosterAddress == _expectedAddress,\n \"Pool booster deployed at unexpected address\"\n );\n\n CurvePoolBoosterPlain(payable(poolBoosterAddress))\n .initialize(governor(), strategistAddr, _fee, _feeCollector, _campaignRemoteManager, _votemarket);\n\n _storePoolBoosterEntry(poolBoosterAddress, _gauge);\n return poolBoosterAddress;\n }\n\n /// @notice Removes the pool booster from the internal list of pool boosters.\n /// @dev This action does not destroy the pool booster contract nor does it\n /// stop the yield delegation to it.\n /// @param _poolBoosterAddress address of the pool booster\n function removePoolBooster(address _poolBoosterAddress) external onlyGovernor {\n uint256 boostersLen = poolBoosters.length;\n for (uint256 i = 0; i < boostersLen; ++i) {\n if (poolBoosters[i].boosterAddress == _poolBoosterAddress) {\n // erase mapping\n delete poolBoosterFromPool[poolBoosters[i].ammPoolAddress];\n\n // overwrite current pool booster with the last entry in the list\n poolBoosters[i] = poolBoosters[boostersLen - 1];\n // drop the last entry\n poolBoosters.pop();\n\n if (address(centralRegistry) != address(0)) {\n centralRegistry.emitPoolBoosterRemoved(_poolBoosterAddress);\n }\n break;\n }\n }\n }\n\n ////////////////////////////////////////////////////\n /// Internal Mutative Functions\n ////////////////////////////////////////////////////\n\n /// @notice Stores the pool booster entry in the internal list and mapping\n /// @param _poolBoosterAddress address of the pool booster\n /// @param _ammPoolAddress address of the AMM pool\n function _storePoolBoosterEntry(address _poolBoosterAddress, address _ammPoolAddress) internal {\n IPoolBoostCentralRegistry.PoolBoosterType _boosterType =\n IPoolBoostCentralRegistry.PoolBoosterType.CurvePoolBoosterPlain;\n PoolBoosterEntry memory entry = PoolBoosterEntry(_poolBoosterAddress, _ammPoolAddress, _boosterType);\n\n poolBoosters.push(entry);\n poolBoosterFromPool[_ammPoolAddress] = entry;\n\n // emit the events of the pool booster created\n if (address(centralRegistry) != address(0)) {\n centralRegistry.emitPoolBoosterCreated(_poolBoosterAddress, _ammPoolAddress, _boosterType);\n }\n }\n\n ////////////////////////////////////////////////////\n /// External View Functions\n ////////////////////////////////////////////////////\n\n /// @notice Create a new CurvePoolBoosterPlain instance (address computation version)\n /// @param _rewardToken Address of the reward token (OETH or OUSD)\n /// @param _gauge Address of the gauge (e.g. Curve OETH/WETH Gauge)\n /// @param _salt A unique number that affects the address of the pool booster created. Note: this number\n /// should match the one from `createCurvePoolBoosterPlain` in order for the final deployed address\n /// and pre-computed address to match\n function computePoolBoosterAddress(address _rewardToken, address _gauge, bytes32 _salt)\n external\n view\n returns (address)\n {\n bytes32 guardedSalt = _computeGuardedSalt(_salt);\n return\n CREATEX.computeCreate2Address(guardedSalt, keccak256(_getInitCode(_rewardToken, _gauge)), address(CREATEX));\n }\n\n /// @notice Encodes a salt for CreateX by concatenating deployer address (bytes20), cross-chain protection flag\n /// (bytes1), and the first 11 bytes of the provided salt (most significant bytes). This function is exposed\n /// for easier operations. For the salt value itself just use the epoch time when the operation is performed.\n /// @param salt The raw salt as uint256; converted to bytes32, then only the first 11 bytes (MSB) are used.\n /// @return encodedSalt The resulting 32-byte encoded salt.\n function encodeSaltForCreateX(uint256 salt) external view returns (bytes32 encodedSalt) {\n // only the right most 11 bytes are considered when encoding salt. Which is limited by the number in the below\n // require. If salt were higher, the higher bytes would need to be set to 0 to not affect the \"or\" way of\n // encoding the salt.\n require(salt <= 309485009821345068724781055, \"Invalid salt\");\n\n // prepare encoded salt guarded by this factory address. When the deployer part of the salt is the same as the\n // caller of CreateX the salt is re-hashed and thus guarded from front-running.\n address deployer = address(this);\n\n // Flag as uint8 (0)\n uint8 flag = 0;\n\n // Precompute parts\n uint256 deployerPart = uint256(uint160(deployer)) << 96; // 20 bytes shifted left 96 bits (12 bytes)\n uint256 flagPart = uint256(flag) << 88; // 1 byte shifted left 88 bits (11 bytes)\n\n // Concat via nested OR\n // solhint-disable-next-line no-inline-assembly\n assembly {\n encodedSalt := or(or(deployerPart, flagPart), salt)\n }\n }\n\n /// @notice Get the number of pool boosters created by this factory\n function poolBoosterLength() external view returns (uint256) {\n return poolBoosters.length;\n }\n\n /// @notice Get the list of all pool boosters created by this factory\n function getPoolBoosters() external view returns (PoolBoosterEntry[] memory) {\n return poolBoosters;\n }\n\n ////////////////////////////////////////////////////\n /// Internal View/Pure Functions\n ////////////////////////////////////////////////////\n\n /// @notice Get the init code for the CurvePoolBoosterPlain contract\n function _getInitCode(address _rewardToken, address _gauge) internal pure returns (bytes memory) {\n return abi.encodePacked(type(CurvePoolBoosterPlain).creationCode, abi.encode(_rewardToken, _gauge));\n }\n\n /// @notice Compute the guarded salt for CreateX protections. This version of guarded\n /// salt expects that this factory contract is the one doing calls to the CreateX contract.\n function _computeGuardedSalt(bytes32 _salt) internal view returns (bytes32) {\n return _efficientHash({a: bytes32(uint256(uint160(address(this)))), b: _salt});\n }\n\n /// @notice Efficiently hash two bytes32 values together\n function _efficientHash(bytes32 a, bytes32 b) internal pure returns (bytes32 hash) {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n hash := keccak256(0x00, 0x40)\n }\n }\n}\n" + }, + "contracts/poolBooster/CurvePoolBoosterPlain.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { CurvePoolBooster } from \"./CurvePoolBooster.sol\";\n\n/// @title CurvePoolBoosterPlain\n/// @author Origin Protocol\n/// @notice Contract to manage interactions with VotemarketV2 for a dedicated Curve pool/gauge. It differs from the\n/// CurvePoolBooster in that it is not proxied.\n/// @dev Governor is not set in the constructor so that the same contract can be deployed on the same address on\n/// multiple chains. Governor is set in the initialize function.\ncontract CurvePoolBoosterPlain is CurvePoolBooster {\n constructor(address _rewardToken, address _gauge)\n CurvePoolBooster(_rewardToken, _gauge)\n {\n rewardToken = _rewardToken;\n gauge = _gauge;\n }\n\n /// @notice initialize function, to set up initial internal state\n /// @param _strategist Address of the strategist\n /// @param _fee Fee in FEE_BASE unit payed when managing campaign\n /// @param _feeCollector Address of the fee collector\n /// @dev Since this function is initialized in the same transaction as it is created the initialize function\n /// doesn't need role protection.\n /// Because the governor is only set in the initialisation function the base class initialize can not be\n /// called as it is not the governor who is issueing this call.\n function initialize(\n address _govenor,\n address _strategist,\n uint16 _fee,\n address _feeCollector,\n address _campaignRemoteManager,\n address _votemarket\n ) external initializer {\n _setStrategistAddr(_strategist);\n _setFee(_fee);\n _setFeeCollector(_feeCollector);\n _setCampaignRemoteManager(_campaignRemoteManager);\n _setVotemarket(_votemarket);\n\n // Set the governor to the provided governor\n _setGovernor(_govenor);\n }\n}\n" + }, + "contracts/poolBooster/PoolBoostCentralRegistry.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IPoolBoostCentralRegistry } from \"../interfaces/poolBooster/IPoolBoostCentralRegistry.sol\";\n\n/**\n * @title Contract that holds all governance approved pool booster Factory\n * implementation deployments\n * @author Origin Protocol Inc\n */\ncontract PoolBoostCentralRegistry is Governable, IPoolBoostCentralRegistry {\n event FactoryApproved(address factoryAddress);\n event FactoryRemoved(address factoryAddress);\n\n // @notice List of approved factories\n address[] public factories;\n\n modifier onlyApprovedFactories() {\n require(isApprovedFactory(msg.sender), \"Not an approved factory\");\n _;\n }\n\n constructor() {\n // set the governor of the implementation contract to zero address\n _setGovernor(address(0));\n }\n\n /**\n * @notice Adds a factory address to the approved factory addresses\n * @param _factoryAddress address of the factory\n */\n function approveFactory(address _factoryAddress) external onlyGovernor {\n require(_factoryAddress != address(0), \"Invalid address\");\n require(\n !isApprovedFactory(_factoryAddress),\n \"Factory already approved\"\n );\n\n factories.push(_factoryAddress);\n emit FactoryApproved(_factoryAddress);\n }\n\n /**\n * @notice Removes the factory from approved factory addresses\n * @param _factoryAddress address of the factory\n */\n function removeFactory(address _factoryAddress) external onlyGovernor {\n require(_factoryAddress != address(0), \"Invalid address\");\n\n uint256 length = factories.length;\n bool factoryRemoved = false;\n for (uint256 i = 0; i < length; i++) {\n if (factories[i] != _factoryAddress) {\n continue;\n }\n\n factories[i] = factories[length - 1];\n factories.pop();\n emit FactoryRemoved(_factoryAddress);\n factoryRemoved = true;\n break;\n }\n require(factoryRemoved, \"Not an approved factory\");\n\n emit FactoryRemoved(_factoryAddress);\n }\n\n /**\n * @notice Emits a pool booster created event\n * @dev This has been created as a convenience method for the monitoring to have\n * an index of all of the created pool boosters by only listening to the\n * events of this contract.\n * @param _poolBoosterAddress address of the pool booster created\n * @param _ammPoolAddress address of the AMM pool forwarding yield to the pool booster\n * @param _boosterType PoolBoosterType the type of the pool booster\n */\n function emitPoolBoosterCreated(\n address _poolBoosterAddress,\n address _ammPoolAddress,\n PoolBoosterType _boosterType\n ) external onlyApprovedFactories {\n emit PoolBoosterCreated(\n _poolBoosterAddress,\n _ammPoolAddress,\n _boosterType,\n msg.sender // address of the factory\n );\n }\n\n /**\n * @notice Emits a pool booster removed event\n * @dev This has been created as a convenience method for the monitoring to have\n * an index of all of the removed pool boosters by only listening to the\n * events of this contract.\n * @param _poolBoosterAddress address of the pool booster to be removed\n */\n function emitPoolBoosterRemoved(address _poolBoosterAddress)\n external\n onlyApprovedFactories\n {\n emit PoolBoosterRemoved(_poolBoosterAddress);\n }\n\n /**\n * @notice Returns true if the factory is approved\n * @param _factoryAddress address of the factory\n */\n function isApprovedFactory(address _factoryAddress)\n public\n view\n returns (bool)\n {\n uint256 length = factories.length;\n for (uint256 i = 0; i < length; i++) {\n if (factories[i] == _factoryAddress) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @notice Returns all supported factories\n */\n function getAllFactories() external view returns (address[] memory) {\n return factories;\n }\n}\n" + }, + "contracts/poolBooster/PoolBoosterFactoryMerkl.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { PoolBoosterMerkl } from \"./PoolBoosterMerkl.sol\";\nimport { AbstractPoolBoosterFactory, IPoolBoostCentralRegistry } from \"./AbstractPoolBoosterFactory.sol\";\n\n/**\n * @title Pool booster factory for creating Merkl pool boosters.\n * @author Origin Protocol Inc\n */\ncontract PoolBoosterFactoryMerkl is AbstractPoolBoosterFactory {\n uint256 public constant version = 1;\n\n /// @notice address of the Merkl distributor\n address public merklDistributor;\n\n /// @notice event emitted when the Merkl distributor is updated\n event MerklDistributorUpdated(address newDistributor);\n\n /**\n * @param _oToken address of the OToken token\n * @param _governor address governor\n * @param _centralRegistry address of the central registry\n * @param _merklDistributor address of the Merkl distributor\n */\n constructor(\n address _oToken,\n address _governor,\n address _centralRegistry,\n address _merklDistributor\n ) AbstractPoolBoosterFactory(_oToken, _governor, _centralRegistry) {\n _setMerklDistributor(_merklDistributor);\n }\n\n /**\n * @dev Create a Pool Booster for Merkl.\n * @param _campaignType The type of campaign to create. This is used to determine the type of\n * bribe contract to create. The type is defined in the MerklDistributor contract.\n * @param _ammPoolAddress address of the AMM pool where the yield originates from\n * @param _campaignDuration The duration of the campaign in seconds\n * @param campaignData The data to be used for the campaign. This is used to determine the type of\n * bribe contract to create. The type is defined in the MerklDistributor contract.\n * This should be fetched from the Merkl UI.\n * @param _salt A unique number that affects the address of the pool booster created. Note: this number\n * should match the one from `computePoolBoosterAddress` in order for the final deployed address\n * and pre-computed address to match\n */\n function createPoolBoosterMerkl(\n uint32 _campaignType,\n address _ammPoolAddress,\n uint32 _campaignDuration,\n bytes calldata campaignData,\n uint256 _salt\n ) external onlyGovernor {\n require(\n _ammPoolAddress != address(0),\n \"Invalid ammPoolAddress address\"\n );\n require(_salt > 0, \"Invalid salt\");\n require(_campaignDuration > 1 hours, \"Invalid campaign duration\");\n require(campaignData.length > 0, \"Invalid campaign data\");\n\n address poolBoosterAddress = _deployContract(\n abi.encodePacked(\n type(PoolBoosterMerkl).creationCode,\n abi.encode(\n oToken,\n merklDistributor,\n _campaignDuration,\n _campaignType,\n governor(),\n campaignData\n )\n ),\n _salt\n );\n\n _storePoolBoosterEntry(\n poolBoosterAddress,\n _ammPoolAddress,\n IPoolBoostCentralRegistry.PoolBoosterType.MerklBooster\n );\n }\n\n /**\n * @dev Create a Pool Booster for Merkl.\n * @param _campaignType The type of campaign to create. This is used to determine the type of\n * bribe contract to create. The type is defined in the MerklDistributor contract.\n * @param _ammPoolAddress address of the AMM pool where the yield originates from\n * @param _salt A unique number that affects the address of the pool booster created. Note: this number\n * should match the one from `createPoolBoosterMerkl` in order for the final deployed address\n * and pre-computed address to match\n */\n function computePoolBoosterAddress(\n uint32 _campaignType,\n address _ammPoolAddress,\n uint32 _campaignDuration,\n bytes calldata campaignData,\n uint256 _salt\n ) external view returns (address) {\n require(\n _ammPoolAddress != address(0),\n \"Invalid ammPoolAddress address\"\n );\n require(_salt > 0, \"Invalid salt\");\n require(_campaignDuration > 1 hours, \"Invalid campaign duration\");\n require(campaignData.length > 0, \"Invalid campaign data\");\n\n return\n _computeAddress(\n abi.encodePacked(\n type(PoolBoosterMerkl).creationCode,\n abi.encode(\n oToken,\n merklDistributor,\n _campaignDuration,\n _campaignType,\n governor(),\n campaignData\n )\n ),\n _salt\n );\n }\n\n /**\n * @dev Set the address of the Merkl distributor\n * @param _merklDistributor The address of the Merkl distributor\n */\n function setMerklDistributor(address _merklDistributor)\n external\n onlyGovernor\n {\n _setMerklDistributor(_merklDistributor);\n }\n\n function _setMerklDistributor(address _merklDistributor) internal {\n require(\n _merklDistributor != address(0),\n \"Invalid merklDistributor address\"\n );\n merklDistributor = _merklDistributor;\n emit MerklDistributorUpdated(_merklDistributor);\n }\n}\n" + }, + "contracts/poolBooster/PoolBoosterFactoryMetropolis.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { PoolBoosterMetropolis } from \"./PoolBoosterMetropolis.sol\";\nimport { AbstractPoolBoosterFactory, IPoolBoostCentralRegistry } from \"./AbstractPoolBoosterFactory.sol\";\n\n/**\n * @title Pool booster factory for creating Metropolis pool boosters.\n * @author Origin Protocol Inc\n */\ncontract PoolBoosterFactoryMetropolis is AbstractPoolBoosterFactory {\n uint256 public constant version = 1;\n address public immutable rewardFactory;\n address public immutable voter;\n\n // @param address _oToken address of the OToken token\n // @param address _governor address governor\n // @param address _centralRegistry address of the central registry\n // @param address _rewardFactory address of the Metropolis reward factory\n // @param address _voter address of the Metropolis voter\n constructor(\n address _oToken,\n address _governor,\n address _centralRegistry,\n address _rewardFactory,\n address _voter\n ) AbstractPoolBoosterFactory(_oToken, _governor, _centralRegistry) {\n rewardFactory = _rewardFactory;\n voter = _voter;\n }\n\n /**\n * @dev Create a Pool Booster for Metropolis pool.\n * @param _ammPoolAddress address of the AMM pool where the yield originates from\n * @param _salt A unique number that affects the address of the pool booster created. Note: this number\n * should match the one from `computePoolBoosterAddress` in order for the final deployed address\n * and pre-computed address to match\n */\n function createPoolBoosterMetropolis(address _ammPoolAddress, uint256 _salt)\n external\n onlyGovernor\n {\n require(\n _ammPoolAddress != address(0),\n \"Invalid ammPoolAddress address\"\n );\n require(_salt > 0, \"Invalid salt\");\n\n address poolBoosterAddress = _deployContract(\n abi.encodePacked(\n type(PoolBoosterMetropolis).creationCode,\n abi.encode(oToken, rewardFactory, _ammPoolAddress, voter)\n ),\n _salt\n );\n\n _storePoolBoosterEntry(\n poolBoosterAddress,\n _ammPoolAddress,\n IPoolBoostCentralRegistry.PoolBoosterType.MetropolisBooster\n );\n }\n\n /**\n * @dev Create a Pool Booster for Metropolis pool.\n * @param _ammPoolAddress address of the AMM pool where the yield originates from\n * @param _salt A unique number that affects the address of the pool booster created. Note: this number\n * should match the one from `createPoolBoosterMetropolis` in order for the final deployed address\n * and pre-computed address to match\n */\n function computePoolBoosterAddress(address _ammPoolAddress, uint256 _salt)\n external\n view\n returns (address)\n {\n require(\n _ammPoolAddress != address(0),\n \"Invalid ammPoolAddress address\"\n );\n require(_salt > 0, \"Invalid salt\");\n\n return\n _computeAddress(\n abi.encodePacked(\n type(PoolBoosterMetropolis).creationCode,\n abi.encode(oToken, rewardFactory, _ammPoolAddress, voter)\n ),\n _salt\n );\n }\n}\n" + }, + "contracts/poolBooster/PoolBoosterFactorySwapxDouble.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { PoolBoosterSwapxDouble } from \"./PoolBoosterSwapxDouble.sol\";\nimport { AbstractPoolBoosterFactory, IPoolBoostCentralRegistry } from \"./AbstractPoolBoosterFactory.sol\";\n\n/**\n * @title Pool booster factory for creating Swapx Ichi pool boosters where both of the\n * gauges need incentivizing.\n * @author Origin Protocol Inc\n */\ncontract PoolBoosterFactorySwapxDouble is AbstractPoolBoosterFactory {\n uint256 public constant version = 1;\n\n // @param address _oToken address of the OToken token\n // @param address _governor address governor\n // @param address _centralRegistry address of the central registry\n constructor(\n address _oToken,\n address _governor,\n address _centralRegistry\n ) AbstractPoolBoosterFactory(_oToken, _governor, _centralRegistry) {}\n\n /**\n * @dev Create a Pool Booster for SwapX Ichi vault based pool where 2 Bribe contracts need to be\n * bribed\n * @param _bribeAddressOS address of the Bribes.sol(Bribe) contract for the OS token side\n * @param _bribeAddressOther address of the Bribes.sol(Bribe) contract for the other token in the pool\n * @param _ammPoolAddress address of the AMM pool where the yield originates from\n * @param _split 1e18 denominated split between OS and Other bribe. E.g. 0.4e17 means 40% to OS\n * bribe contract and 60% to other bribe contract\n * @param _salt A unique number that affects the address of the pool booster created. Note: this number\n * should match the one from `computePoolBoosterAddress` in order for the final deployed address\n * and pre-computed address to match\n */\n function createPoolBoosterSwapxDouble(\n address _bribeAddressOS,\n address _bribeAddressOther,\n address _ammPoolAddress,\n uint256 _split,\n uint256 _salt\n ) external onlyGovernor {\n require(\n _ammPoolAddress != address(0),\n \"Invalid ammPoolAddress address\"\n );\n require(_salt > 0, \"Invalid salt\");\n\n address poolBoosterAddress = _deployContract(\n abi.encodePacked(\n type(PoolBoosterSwapxDouble).creationCode,\n abi.encode(_bribeAddressOS, _bribeAddressOther, oToken, _split)\n ),\n _salt\n );\n\n _storePoolBoosterEntry(\n poolBoosterAddress,\n _ammPoolAddress,\n IPoolBoostCentralRegistry.PoolBoosterType.SwapXDoubleBooster\n );\n }\n\n /**\n * @dev Compute the address of the pool booster to be deployed.\n * @param _bribeAddressOS address of the Bribes.sol(Bribe) contract for the OS token side\n * @param _bribeAddressOther address of the Bribes.sol(Bribe) contract for the other token in the pool\n * @param _ammPoolAddress address of the AMM pool where the yield originates from\n * @param _split 1e18 denominated split between OS and Other bribe. E.g. 0.4e17 means 40% to OS\n * bribe contract and 60% to other bribe contract\n * @param _salt A unique number that affects the address of the pool booster created. Note: this number\n * should match the one from `createPoolBoosterSwapxDouble` in order for the final deployed address\n * and pre-computed address to match\n */\n function computePoolBoosterAddress(\n address _bribeAddressOS,\n address _bribeAddressOther,\n address _ammPoolAddress,\n uint256 _split,\n uint256 _salt\n ) external view returns (address) {\n require(\n _ammPoolAddress != address(0),\n \"Invalid ammPoolAddress address\"\n );\n require(_salt > 0, \"Invalid salt\");\n\n return\n _computeAddress(\n abi.encodePacked(\n type(PoolBoosterSwapxDouble).creationCode,\n abi.encode(\n _bribeAddressOS,\n _bribeAddressOther,\n oToken,\n _split\n )\n ),\n _salt\n );\n }\n}\n" + }, + "contracts/poolBooster/PoolBoosterFactorySwapxSingle.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { PoolBoosterSwapxSingle } from \"./PoolBoosterSwapxSingle.sol\";\nimport { AbstractPoolBoosterFactory, IPoolBoostCentralRegistry } from \"./AbstractPoolBoosterFactory.sol\";\n\n/**\n * @title Pool booster factory for creating Swapx Single pool boosters - where a single\n * gauge is created for a pool. this is appropriate for Classic Stable & Classic\n * Volatile SwapX pools.\n * @author Origin Protocol Inc\n */\ncontract PoolBoosterFactorySwapxSingle is AbstractPoolBoosterFactory {\n uint256 public constant version = 1;\n\n // @param address _oToken address of the OToken token\n // @param address _governor address governor\n // @param address _centralRegistry address of the central registry\n constructor(\n address _oToken,\n address _governor,\n address _centralRegistry\n ) AbstractPoolBoosterFactory(_oToken, _governor, _centralRegistry) {}\n\n /**\n * @dev Create a Pool Booster for SwapX classic volatile or classic stable pools where\n * a single Bribe contract is incentivized.\n * @param _bribeAddress address of the Bribes.sol contract\n * @param _ammPoolAddress address of the AMM pool where the yield originates from\n * @param _salt A unique number that affects the address of the pool booster created. Note: this number\n * should match the one from `computePoolBoosterAddress` in order for the final deployed address\n * and pre-computed address to match\n */\n function createPoolBoosterSwapxSingle(\n address _bribeAddress,\n address _ammPoolAddress,\n uint256 _salt\n ) external onlyGovernor {\n require(\n _ammPoolAddress != address(0),\n \"Invalid ammPoolAddress address\"\n );\n require(_salt > 0, \"Invalid salt\");\n\n address poolBoosterAddress = _deployContract(\n abi.encodePacked(\n type(PoolBoosterSwapxSingle).creationCode,\n abi.encode(_bribeAddress, oToken)\n ),\n _salt\n );\n\n _storePoolBoosterEntry(\n poolBoosterAddress,\n _ammPoolAddress,\n IPoolBoostCentralRegistry.PoolBoosterType.SwapXSingleBooster\n );\n }\n\n /**\n * @dev Create a Pool Booster for SwapX classic volatile or classic stable pools where\n * a single Bribe contract is incentivized.\n * @param _bribeAddress address of the Bribes.sol contract\n * @param _ammPoolAddress address of the AMM pool where the yield originates from\n * @param _salt A unique number that affects the address of the pool booster created. Note: this number\n * should match the one from `createPoolBoosterSwapxSingle` in order for the final deployed address\n * and pre-computed address to match\n */\n function computePoolBoosterAddress(\n address _bribeAddress,\n address _ammPoolAddress,\n uint256 _salt\n ) external view returns (address) {\n require(\n _ammPoolAddress != address(0),\n \"Invalid ammPoolAddress address\"\n );\n require(_salt > 0, \"Invalid salt\");\n\n return\n _computeAddress(\n abi.encodePacked(\n type(PoolBoosterSwapxSingle).creationCode,\n abi.encode(_bribeAddress, oToken)\n ),\n _salt\n );\n }\n}\n" + }, + "contracts/poolBooster/PoolBoosterMerkl.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IPoolBooster } from \"../interfaces/poolBooster/IPoolBooster.sol\";\nimport { IMerklDistributor } from \"../interfaces/poolBooster/IMerklDistributor.sol\";\n\ninterface IERC1271 {\n /**\n * @dev Should return whether the signature provided is valid for the provided data\n * @param hash Hash of the data to be signed\n * @param signature Signature byte array associated with _data\n */\n function isValidSignature(bytes32 hash, bytes memory signature)\n external\n view\n returns (bytes4 magicValue);\n}\n\n/**\n * @title Pool booster for Merkl distributor\n * @author Origin Protocol Inc\n */\ncontract PoolBoosterMerkl is IPoolBooster, IERC1271 {\n /// @notice address of merkl distributor\n IMerklDistributor public immutable merklDistributor;\n /// @notice address of the OS token\n IERC20 public immutable rewardToken;\n /// @notice if balance under this amount the bribe action is skipped\n uint256 public constant MIN_BRIBE_AMOUNT = 1e10;\n /// @notice Campaign duration in seconds\n uint32 public immutable duration; // -> should be immutable\n /// @notice Campaign type\n uint32 public immutable campaignType;\n /// @notice Owner of the campaign\n address public immutable creator;\n /// @notice Campaign data\n bytes public campaignData;\n\n constructor(\n address _rewardToken,\n address _merklDistributor,\n uint32 _duration,\n uint32 _campaignType,\n address _creator,\n bytes memory _campaignData\n ) {\n require(_rewardToken != address(0), \"Invalid rewardToken address\");\n require(\n _merklDistributor != address(0),\n \"Invalid merklDistributor address\"\n );\n require(_campaignData.length > 0, \"Invalid campaignData\");\n require(_duration > 1 hours, \"Invalid duration\");\n\n campaignType = _campaignType;\n duration = _duration;\n creator = _creator;\n\n merklDistributor = IMerklDistributor(_merklDistributor);\n rewardToken = IERC20(_rewardToken);\n campaignData = _campaignData;\n }\n\n /// @notice Create a campaign on the Merkl distributor\n function bribe() external override {\n // Ensure token is approved for the Merkl distributor\n uint256 minAmount = merklDistributor.rewardTokenMinAmounts(\n address(rewardToken)\n );\n require(minAmount > 0, \"Min reward amount must be > 0\");\n\n // if balance too small or below threshold, do no bribes\n uint256 balance = rewardToken.balanceOf(address(this));\n if (\n balance < MIN_BRIBE_AMOUNT ||\n (balance * 1 hours < minAmount * duration)\n ) {\n return;\n }\n\n // Approve the bribe contract to spend the reward token\n rewardToken.approve(address(merklDistributor), balance);\n\n // Notify the bribe contract of the reward amount\n merklDistributor.signAndCreateCampaign(\n IMerklDistributor.CampaignParameters({\n campaignId: bytes32(0),\n creator: creator,\n rewardToken: address(rewardToken),\n amount: balance,\n campaignType: campaignType,\n startTimestamp: getNextPeriodStartTime(),\n duration: duration,\n campaignData: campaignData\n }),\n bytes(\"\")\n );\n emit BribeExecuted(balance);\n }\n\n /// @notice Used to sign a campaign on the Merkl distributor\n function isValidSignature(bytes32, bytes memory)\n external\n view\n override\n returns (bytes4 magicValue)\n {\n require(msg.sender == address(merklDistributor), \"Invalid sender\");\n // bytes4(keccak256(\"isValidSignature(bytes32,bytes)\")) == 0x1626ba7e\n return bytes4(0x1626ba7e);\n }\n\n /// @notice Returns the timestamp for the start of the next period based on the configured duration\n function getNextPeriodStartTime() public view returns (uint32) {\n // Calculate the timestamp for the next period boundary\n return uint32((block.timestamp / duration + 1) * duration);\n }\n}\n" + }, + "contracts/poolBooster/PoolBoosterMetropolis.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IPoolBooster } from \"../interfaces/poolBooster/IPoolBooster.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Pool booster for Metropolis pools\n * @author Origin Protocol Inc\n */\ncontract PoolBoosterMetropolis is IPoolBooster {\n // @notice address of the OS token\n IERC20 public immutable osToken;\n // @notice address of the pool\n address public immutable pool;\n // @notice if balance under this amount the bribe action is skipped\n uint256 public constant MIN_BRIBE_AMOUNT = 1e10;\n\n IRewarderFactory public immutable rewardFactory;\n\n IVoter public immutable voter;\n\n constructor(\n address _osToken,\n address _rewardFactory,\n address _pool,\n address _voter\n ) {\n require(_pool != address(0), \"Invalid pool address\");\n pool = _pool;\n // Abstract factory already validates this is not a zero address\n osToken = IERC20(_osToken);\n\n rewardFactory = IRewarderFactory(_rewardFactory);\n\n voter = IVoter(_voter);\n }\n\n function bribe() external override {\n uint256 balance = osToken.balanceOf(address(this));\n // balance too small, do no bribes\n (, uint256 minBribeAmount) = rewardFactory.getWhitelistedTokenInfo(\n address(osToken)\n );\n if (balance < MIN_BRIBE_AMOUNT || balance < minBribeAmount) {\n return;\n }\n\n uint256 id = voter.getCurrentVotingPeriod() + 1;\n\n // Deploy a rewarder\n IRewarder rewarder = IRewarder(\n rewardFactory.createBribeRewarder(address(osToken), pool)\n );\n\n // Approve the rewarder to spend the balance\n osToken.approve(address(rewarder), balance);\n\n // Fund and bribe the rewarder\n rewarder.fundAndBribe(id, id, balance);\n\n emit BribeExecuted(balance);\n }\n}\n\ninterface IRewarderFactory {\n function createBribeRewarder(address token, address pool)\n external\n returns (address rewarder);\n\n function getWhitelistedTokenInfo(address token)\n external\n view\n returns (bool isWhitelisted, uint256 minBribeAmount);\n}\n\ninterface IRewarder {\n function fundAndBribe(\n uint256 startId,\n uint256 lastId,\n uint256 amountPerPeriod\n ) external payable;\n}\n\ninterface IVoter {\n function getCurrentVotingPeriod() external view returns (uint256);\n}\n" + }, + "contracts/poolBooster/PoolBoosterSwapxDouble.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IBribe } from \"../interfaces/poolBooster/ISwapXAlgebraBribe.sol\";\nimport { IPoolBooster } from \"../interfaces/poolBooster/IPoolBooster.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n/**\n * @title Pool booster for SwapX concentrated liquidity where 2 gauges are created for\n * every pool. Ichi vaults currently have such setup.\n * @author Origin Protocol Inc\n */\ncontract PoolBoosterSwapxDouble is IPoolBooster {\n using StableMath for uint256;\n\n // @notice address of the Bribes.sol(Bribe) contract for the OS token side\n IBribe public immutable bribeContractOS;\n // @notice address of the Bribes.sol(Bribe) contract for the other token in the pool\n IBribe public immutable bribeContractOther;\n // @notice address of the OS token\n IERC20 public immutable osToken;\n // @notice 1e18 denominated split between OS and Other bribe. E.g. 0.4e17 means 40% to OS\n // bribe contract and 60% to other bribe contract\n uint256 public immutable split;\n\n // @notice if balance under this amount the bribe action is skipped\n uint256 public constant MIN_BRIBE_AMOUNT = 1e10;\n\n constructor(\n address _bribeContractOS,\n address _bribeContractOther,\n address _osToken,\n uint256 _split\n ) {\n require(\n _bribeContractOS != address(0),\n \"Invalid bribeContractOS address\"\n );\n require(\n _bribeContractOther != address(0),\n \"Invalid bribeContractOther address\"\n );\n // expect it to be between 1% & 99%\n require(_split > 1e16 && _split < 99e16, \"Unexpected split amount\");\n\n bribeContractOS = IBribe(_bribeContractOS);\n bribeContractOther = IBribe(_bribeContractOther);\n // Abstract factory already validates this is not a zero address\n osToken = IERC20(_osToken);\n split = _split;\n }\n\n function bribe() external override {\n uint256 balance = osToken.balanceOf(address(this));\n // balance too small, do no bribes\n if (balance < MIN_BRIBE_AMOUNT) {\n return;\n }\n\n uint256 osBribeAmount = balance.mulTruncate(split);\n uint256 otherBribeAmount = balance - osBribeAmount;\n\n osToken.approve(address(bribeContractOS), osBribeAmount);\n osToken.approve(address(bribeContractOther), otherBribeAmount);\n\n bribeContractOS.notifyRewardAmount(address(osToken), osBribeAmount);\n bribeContractOther.notifyRewardAmount(\n address(osToken),\n otherBribeAmount\n );\n\n emit BribeExecuted(balance);\n }\n}\n" + }, + "contracts/poolBooster/PoolBoosterSwapxSingle.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IBribe } from \"../interfaces/poolBooster/ISwapXAlgebraBribe.sol\";\nimport { IPoolBooster } from \"../interfaces/poolBooster/IPoolBooster.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Pool booster for SwapX for Classic Stable Pools and Classic Volatile Pools\n * @author Origin Protocol Inc\n */\ncontract PoolBoosterSwapxSingle is IPoolBooster {\n // @notice address of the Bribes.sol(Bribe) contract\n IBribe public immutable bribeContract;\n // @notice address of the OS token\n IERC20 public immutable osToken;\n // @notice if balance under this amount the bribe action is skipped\n uint256 public constant MIN_BRIBE_AMOUNT = 1e10;\n\n constructor(address _bribeContract, address _osToken) {\n require(_bribeContract != address(0), \"Invalid bribeContract address\");\n bribeContract = IBribe(_bribeContract);\n // Abstract factory already validates this is not a zero address\n osToken = IERC20(_osToken);\n }\n\n function bribe() external override {\n uint256 balance = osToken.balanceOf(address(this));\n // balance too small, do no bribes\n if (balance < MIN_BRIBE_AMOUNT) {\n return;\n }\n\n osToken.approve(address(bribeContract), balance);\n\n bribeContract.notifyRewardAmount(address(osToken), balance);\n emit BribeExecuted(balance);\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/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" + } + }, + "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/mainnet/PoolBoostCentralRegistry.json b/contracts/storageLayout/mainnet/PoolBoostCentralRegistry.json index 8553b2f175..fe7a243d5b 100644 --- a/contracts/storageLayout/mainnet/PoolBoostCentralRegistry.json +++ b/contracts/storageLayout/mainnet/PoolBoostCentralRegistry.json @@ -19,5 +19,6 @@ "label": "address[]", "numberOfBytes": "32" } - } + }, + "namespaces": {} } \ No newline at end of file From a2f494af93909f237467e754a202817d320274ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment?= Date: Fri, 23 Jan 2026 14:14:39 +0100 Subject: [PATCH 2/4] Add deployment timestamp --- contracts/deployments/arbitrumOne/.migrations.json | 3 ++- contracts/deployments/mainnet/.migrations.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/contracts/deployments/arbitrumOne/.migrations.json b/contracts/deployments/arbitrumOne/.migrations.json index bab9c6c070..21dfa993cf 100644 --- a/contracts/deployments/arbitrumOne/.migrations.json +++ b/contracts/deployments/arbitrumOne/.migrations.json @@ -2,5 +2,6 @@ "001_deploy_woeth_on_arb": 1707820141, "002_upgrade_woeth_on_arb": 1710959437, "003_pool_booster_curve": 1737965774, - "004_curve_pool_booster_factory": 1764091943 + "004_curve_pool_booster_factory": 1764091943, + "005_curve_pool_booster_factory": 1769173716 } \ No newline at end of file diff --git a/contracts/deployments/mainnet/.migrations.json b/contracts/deployments/mainnet/.migrations.json index e86cf94aca..9676f8bd25 100644 --- a/contracts/deployments/mainnet/.migrations.json +++ b/contracts/deployments/mainnet/.migrations.json @@ -59,5 +59,6 @@ "162_remove_morpho_gauntlet_strat": 1767659015, "163_increase_oeth_redeem_fee": 1768182515, "164_fix_curve_pb_module": 1769002767, - "165_improve_curve_pb_module": 1769002768 + "165_improve_curve_pb_module": 1769002768, + "166_curve_pool_booster_factory": 1769174027 } \ No newline at end of file From 1c5a1b34981c4f883c328da52a384f61472aa8a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment?= Date: Fri, 23 Jan 2026 16:13:18 +0100 Subject: [PATCH 3/4] Implement CurvePoolBooster migration script for new version deployment --- .../deploy/mainnet/167_curve_pb_migration.js | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 contracts/deploy/mainnet/167_curve_pb_migration.js diff --git a/contracts/deploy/mainnet/167_curve_pb_migration.js b/contracts/deploy/mainnet/167_curve_pb_migration.js new file mode 100644 index 0000000000..360b760b0c --- /dev/null +++ b/contracts/deploy/mainnet/167_curve_pb_migration.js @@ -0,0 +1,112 @@ +const addresses = require("../../utils/addresses"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); + +const pools = [ + { + name: "TriOGN-OETH", + reward: "0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3", + gauge: "0x92d956C1F89a2c71efEEB4Bac45d02016bdD2408", + pool: "0xB8ac7ce449Ed72FF61dE8043d67B507f9F523Fa2", + salt: "0xB6073788e5302122F4DfB6C5aD53a1EAC9cb0289000000000000000000000004", + oldPB: "0x7B5e7aDEBC2da89912BffE55c86675CeCE59803E", + newPB: "0xFc87E0ABe3592945Ad7587F99161dBb340faa767", + }, + { + name: "TriOGN-OUSD", + reward: "0x2A8e1E676Ec238d8A992307B495b45B3fEAa5e86", + gauge: "0x92d956C1F89a2c71efEEB4Bac45d02016bdD2408", + pool: "0xB8ac7ce449Ed72FF61dE8043d67B507f9F523Fa2", + salt: "0xB6073788e5302122F4DfB6C5aD53a1EAC9cb0289000000000000000000000005", + oldPB: "0x514447A1Ef103f3cF4B0fE92A947F071239f2809", + newPB: "0x028C6f98C20094367F7b048F0aFA1E11ce0A8DBd", + }, + { + name: "OETH/LidoARM", + reward: "0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3", + gauge: "0xFcaDecfc207e3329a38821E5B04f88029cc4fa62", + pool: "0x95753095F15870ACC0cB0Ed224478ea61aeb0b8e", + salt: "0xB6073788e5302122F4DfB6C5aD53a1EAC9cb0289000000000000000000000006", + oldPB: "0xb61e201bd3c864431ec3d3df0ed1ecf38b63cc8b", + newPB: "0x1A43D2F1bb24aC262D1d7ac05D16823E526FcA32", + }, + { + name: "OUSD/frxUSD", + reward: "0x2A8e1E676Ec238d8A992307B495b45B3fEAa5e86", + gauge: "0x928961d0C4F6E8C683bd5695527D060f18d7d60b", + pool: "0x68d03Ed49800e92D7Aa8aB171424007e55Fd1F49", + salt: "0xB6073788e5302122F4DfB6C5aD53a1EAC9cb0289000000000000000000000007", + oldPB: "0x02260e04f7851FbF09dd9a4fFd1880568410F77e", + newPB: "0xc835BcA1378acb32C522f3831b8dba161a763FBE", + }, +]; + +module.exports = deploymentWithGovernanceProposal( + { + deployName: "167_curve_pb_migration", + forceDeploy: false, + reduceQueueTime: true, + deployerIsProposer: false, + proposalId: "", + }, + async () => { + const cCurvePoolBoosterFactory = await ethers.getContractAt( + "CurvePoolBoosterFactory", + "0xB6073788e5302122F4DfB6C5aD53a1EAC9cb0289" + ); + + const actions = []; + + for (const pool of pools) { + const cOldPoolBooster = await ethers.getContractAt( + "CurvePoolBoosterPlain", + pool.oldPB + ); + + const cRewardToken = await ethers.getContractAt("OUSD", pool.reward); + console.log("Reward token address:", cRewardToken.address); + + // Action 1: Create new CurvePoolBoosterPlain + actions.push({ + contract: cCurvePoolBoosterFactory, + signature: + "createCurvePoolBoosterPlain(address,address,address,uint16,address,address,bytes32,address)", + args: [ + pool.reward, + pool.gauge, + addresses.multichainStrategist, + 0, + addresses.mainnet.CampaignRemoteManager, + addresses.votemarket, + pool.salt, + pool.newPB, + ], + }); + + // Action 2: Undelegate yield from pool to old pool booster + actions.push({ + contract: cRewardToken, + signature: "undelegateYield(address)", + args: [pool.pool], + }); + + // Action 3: YieldForward to pool to new pool booster + actions.push({ + contract: cRewardToken, + signature: "delegateYield(address,address)", + args: [pool.pool, pool.newPB], + }); + + // Action 4: Rescue tokens from old pool booster to new one + actions.push({ + contract: cOldPoolBooster, + signature: "rescueToken(address,address)", + args: [pool.reward, pool.newPB], + }); + } + + return { + name: "Migrate token rewards from CurvePoolBooster to new version", + actions, + }; + } +); From 6138e069951002a3fb086838092a51cb40d87ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment?= Date: Mon, 26 Jan 2026 09:38:44 +0100 Subject: [PATCH 4/4] Update proposalId in CurvePoolBooster migration script --- contracts/deploy/mainnet/167_curve_pb_migration.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/deploy/mainnet/167_curve_pb_migration.js b/contracts/deploy/mainnet/167_curve_pb_migration.js index 360b760b0c..fc07a964e2 100644 --- a/contracts/deploy/mainnet/167_curve_pb_migration.js +++ b/contracts/deploy/mainnet/167_curve_pb_migration.js @@ -46,7 +46,8 @@ module.exports = deploymentWithGovernanceProposal( forceDeploy: false, reduceQueueTime: true, deployerIsProposer: false, - proposalId: "", + proposalId: + "70336422361048948609898488791231866822675120244859766659168608925215046418279", }, async () => { const cCurvePoolBoosterFactory = await ethers.getContractAt(