diff --git a/README.md b/README.md index d4d0f6d..34e14a5 100644 --- a/README.md +++ b/README.md @@ -635,6 +635,7 @@ If no direct liquidity pair exists between two tokens, the spot price aggregator * AaveV3 - [0x0c8fc7a71C28c768FDC1f7d75835229beBEB1573](https://basescan.org/address/0x0c8fc7a71C28c768FDC1f7d75835229beBEB1573) * StataTokens (AaveV3) - [0x1A75DF59f464a70Cc8f7383983852FF72e5F5167](https://basescan.org/address/0x1A75DF59f464a70Cc8f7383983852FF72e5F5167) * CompoundV3 - [0x3afA12cf9Ac1a96845973BD93dBEa183A94DD74F](https://basescan.org/address/0x3afA12cf9Ac1a96845973BD93dBEa183A94DD74F) + * wsuperOETHb - [0x82534c42D6F7C347503C6618170A9aA7d382D8Ec](https://basescan.org/address/0x82534c42D6F7C347503C6618170A9aA7d382D8Ec) diff --git a/contracts/wrappers/WsuperOETHbWrapper.sol b/contracts/wrappers/WsuperOETHbWrapper.sol new file mode 100644 index 0000000..5dbdabb --- /dev/null +++ b/contracts/wrappers/WsuperOETHbWrapper.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.23; + +import "./SDaiWrapper.sol"; + +contract WsuperOETHbWrapper is SDaiWrapper { + constructor(IERC20 base, IERC20 wBase) SDaiWrapper(base, wBase) {} // solhint-disable-line no-empty-blocks +} diff --git a/deployments/base/WsuperOETHbWrapper.json b/deployments/base/WsuperOETHbWrapper.json new file mode 100644 index 0000000..ab2fd99 --- /dev/null +++ b/deployments/base/WsuperOETHbWrapper.json @@ -0,0 +1,125 @@ +{ + "address": "0x82534c42D6F7C347503C6618170A9aA7d382D8Ec", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "base", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "wBase", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "NotAddedMarket", + "type": "error" + }, + { + "inputs": [], + "name": "NotRemovedMarket", + "type": "error" + }, + { + "inputs": [], + "name": "NotSupportedToken", + "type": "error" + }, + { + "inputs": [], + "name": "BASE", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WBASE", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "wrap", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "wrappedToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "rate", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0xb9710d5044075a6ffe8bb6884d9d7ad655c7914949380da125420035e663ee26", + "receipt": { + "to": null, + "from": "0x56E44874F624EbDE6efCc783eFD685f0FBDC6dcF", + "contractAddress": "0x82534c42D6F7C347503C6618170A9aA7d382D8Ec", + "transactionIndex": 35, + "gasUsed": "262302", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x9850ba8b7bed5e32ee32320bf63148635481a2f1d430cf00a0d72e7a6f579e19", + "transactionHash": "0xb9710d5044075a6ffe8bb6884d9d7ad655c7914949380da125420035e663ee26", + "logs": [], + "blockNumber": 21366967, + "cumulativeGasUsed": "8317252", + "status": 1, + "byzantium": true + }, + "args": [ + "0xDBFeFD2e8460a6Ee4955A68582F85708BAEA60A3", + "0x7FcD174E80f264448ebeE8c88a7C4476AAF58Ea6" + ], + "numDeployments": 1, + "solcInputHash": "1387c6738d41087a950f3910d50e1c1c", + "metadata": "{\"compiler\":{\"version\":\"0.8.23+commit.f704f362\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"base\",\"type\":\"address\"},{\"internalType\":\"contract IERC20\",\"name\":\"wBase\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"NotAddedMarket\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotRemovedMarket\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotSupportedToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BASE\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WBASE\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"wrap\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"wrappedToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"rate\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/wrappers/WsuperOETHbWrapper.sol\":\"WsuperOETHbWrapper\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\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 /**\\n * @dev Returns the value of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the value of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 value) 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 a `value` amount of tokens as the allowance of `spender` over the\\n * 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 value) external returns (bool);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\\n * allowance mechanism. `value` 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(address from, address to, uint256 value) external returns (bool);\\n}\\n\",\"keccak256\":\"0xc6a8ff0ea489379b61faa647490411b80102578440ab9d84e9a957cc12164e70\",\"license\":\"MIT\"},\"contracts/interfaces/ISDai.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.23;\\n\\ninterface ISDai {\\n function previewDeposit(uint256 assets) external view returns (uint256);\\n function previewRedeem(uint256 shares) external view returns (uint256);\\n}\\n\\n\",\"keccak256\":\"0xde76bb7c27b63bf450cf229901db7258fc9cc3aa72a8c590b1c885daa591487b\",\"license\":\"MIT\"},\"contracts/interfaces/IWrapper.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.23;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\ninterface IWrapper {\\n error NotSupportedToken();\\n error NotAddedMarket();\\n error NotRemovedMarket();\\n\\n function wrap(IERC20 token) external view returns (IERC20 wrappedToken, uint256 rate);\\n}\\n\",\"keccak256\":\"0x1d3cefe7c67b9f9750823be723dd0b00f9894ec4e0cd078eac321a2cff8f7da2\",\"license\":\"MIT\"},\"contracts/wrappers/SDaiWrapper.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.23;\\n\\nimport \\\"../interfaces/ISDai.sol\\\";\\nimport \\\"./Wrapper.sol\\\";\\n\\ncontract SDaiWrapper is Wrapper {\\n constructor(IERC20 base, IERC20 wBase) Wrapper(base, wBase) {} // solhint-disable-line no-empty-blocks\\n\\n function _wrap() internal view override returns (IERC20 wrappedToken, uint256 rate) {\\n return (WBASE, ISDai(address(WBASE)).previewDeposit(1e18));\\n }\\n\\n function _unwrap() internal view override returns (IERC20 unwrappedToken, uint256 rate) {\\n return (BASE, ISDai(address(WBASE)).previewRedeem(1e18));\\n }\\n}\\n\",\"keccak256\":\"0x32368fd49dee3f060feb7dbf737f6db2489b479bffc3be1422d00573cd93a0cd\",\"license\":\"MIT\"},\"contracts/wrappers/Wrapper.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.23;\\n\\nimport \\\"../interfaces/IWrapper.sol\\\";\\n\\nabstract contract Wrapper is IWrapper {\\n IERC20 public immutable BASE;\\n IERC20 public immutable WBASE;\\n\\n constructor(IERC20 base, IERC20 wBase) {\\n BASE = base;\\n WBASE = wBase;\\n }\\n\\n function wrap(IERC20 token) external view override returns (IERC20 wrappedToken, uint256 rate) {\\n if(token == BASE) {\\n return _wrap();\\n } else if (token == WBASE) {\\n return _unwrap();\\n } else {\\n revert NotSupportedToken();\\n }\\n }\\n\\n function _wrap() internal view virtual returns (IERC20 wrappedToken, uint256 rate) {} // solhint-disable-line no-empty-blocks\\n\\n function _unwrap() internal view virtual returns (IERC20 unwrappedToken, uint256 rate) {} // solhint-disable-line no-empty-blocks\\n}\\n\",\"keccak256\":\"0xfcd599a5fd47efb91353766756707072756da2f2682f6e54b2ae525a71fc1ffb\",\"license\":\"MIT\"},\"contracts/wrappers/WsuperOETHbWrapper.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.23;\\n\\nimport \\\"./SDaiWrapper.sol\\\";\\n\\ncontract WsuperOETHbWrapper is SDaiWrapper {\\n constructor(IERC20 base, IERC20 wBase) SDaiWrapper(base, wBase) {} // solhint-disable-line no-empty-blocks\\n}\\n\",\"keccak256\":\"0x56a5ae3fb03121e33d5a743dd67b674f9dec3ba9b6c1a027bfcfc38fbf12a36f\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60c03461008d57601f61047f38819003918201601f19168301916001600160401b0383118484101761009157808492604094855283398101031261008d57610052602061004b836100a5565b92016100a5565b9060805260a0526040516103c590816100ba8239608051818181608401526101a0015260a05181818160f6015281816101d1015261027d0152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b038216820361008d5756fe60806040526004361015610011575f80fd5b5f3560e01c8063023276f01461011a5780638e0b3bf2146100ac5763ec342ad01461003a575f80fd5b346100a8575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100a857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b5f80fd5b346100a8575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100a857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100a85760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100a85760043573ffffffffffffffffffffffffffffffffffffffff80821682036100a857610175604092610184565b90918351921682526020820152f35b73ffffffffffffffffffffffffffffffffffffffff90811691907f0000000000000000000000000000000000000000000000000000000000000000818116840361027a57506024925060207f000000000000000000000000000000000000000000000000000000000000000091604051948580927fef8b30f7000000000000000000000000000000000000000000000000000000008252670de0b6b3a7640000600483015285165afa92831561026f575f9361023f57509190565b9092506020813d602011610267575b8161025b60209383610321565b810103126100a8575190565b3d915061024e565b6040513d5f823e3d90fd5b907f0000000000000000000000000000000000000000000000000000000000000000168093145f146102f7576020602493604051948580927f4cdad506000000000000000000000000000000000000000000000000000000008252670de0b6b3a764000060048301525afa92831561026f575f9361023f57509190565b60046040517fc8a08d6f000000000000000000000000000000000000000000000000000000008152fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761036257604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffdfea2646970667358221220353917ab144254fdc3e34c7a94e63f3c45ec5c449d07034838eaf61d48131c4c64736f6c63430008170033", + "deployedBytecode": "0x60806040526004361015610011575f80fd5b5f3560e01c8063023276f01461011a5780638e0b3bf2146100ac5763ec342ad01461003a575f80fd5b346100a8575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100a857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b5f80fd5b346100a8575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100a857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100a85760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100a85760043573ffffffffffffffffffffffffffffffffffffffff80821682036100a857610175604092610184565b90918351921682526020820152f35b73ffffffffffffffffffffffffffffffffffffffff90811691907f0000000000000000000000000000000000000000000000000000000000000000818116840361027a57506024925060207f000000000000000000000000000000000000000000000000000000000000000091604051948580927fef8b30f7000000000000000000000000000000000000000000000000000000008252670de0b6b3a7640000600483015285165afa92831561026f575f9361023f57509190565b9092506020813d602011610267575b8161025b60209383610321565b810103126100a8575190565b3d915061024e565b6040513d5f823e3d90fd5b907f0000000000000000000000000000000000000000000000000000000000000000168093145f146102f7576020602493604051948580927f4cdad506000000000000000000000000000000000000000000000000000000008252670de0b6b3a764000060048301525afa92831561026f575f9361023f57509190565b60046040517fc8a08d6f000000000000000000000000000000000000000000000000000000008152fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761036257604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffdfea2646970667358221220353917ab144254fdc3e34c7a94e63f3c45ec5c449d07034838eaf61d48131c4c64736f6c63430008170033", + "devdoc": { + "kind": "dev", + "methods": {}, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} \ No newline at end of file diff --git a/test/helpers.js b/test/helpers.js index 999100a..3a9bb5a 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -64,6 +64,8 @@ const tokens = { DAI: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb', axlUSDC: '0xEB466342C4d449BC9f53A865D5Cb90586f405215', rETH: '0xb6fe221fe9eef5aba221c348ba20a1bf5e73624c', + superOETHb: '0xDBFeFD2e8460a6Ee4955A68582F85708BAEA60A3', + wsuperOETHb: '0x7FcD174E80f264448ebeE8c88a7C4476AAF58Ea6', }, optimistic: { WETH: '0x4200000000000000000000000000000000000006', diff --git a/test/wrappers/WsuperOETHbWrapper.js b/test/wrappers/WsuperOETHbWrapper.js new file mode 100644 index 0000000..180b91f --- /dev/null +++ b/test/wrappers/WsuperOETHbWrapper.js @@ -0,0 +1,35 @@ +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { ethers, network } = require('hardhat'); +const { expect, ether, deployContract } = require('@1inch/solidity-utils'); +const { resetHardhatNetworkFork } = require('@1inch/solidity-utils/hardhat-setup'); +const { tokens } = require('../helpers.js'); + +describe('WsuperOETHbWrapper', function () { + before(async function () { + await resetHardhatNetworkFork(network, 'base'); + }); + + after(async function () { + await resetHardhatNetworkFork(network, 'mainnet'); + }); + + async function initContracts () { + const wsuperOETHbWrapper = await deployContract('WsuperOETHbWrapper', [tokens.base.superOETHb, tokens.base.wsuperOETHb]); + const wsuperOETHb = await ethers.getContractAt('ISDai', tokens.base.wsuperOETHb); + return { wsuperOETHbWrapper, wsuperOETHb }; + } + + it('superOETHb -> wsuperOETHb', async function () { + const { wsuperOETHbWrapper, wsuperOETHb } = await loadFixture(initContracts); + const response = await wsuperOETHbWrapper.wrap(tokens.base.superOETHb); + expect(response.rate).to.equal(await wsuperOETHb.previewDeposit(ether('1'))); + expect(response.wrappedToken).to.equal(tokens.base.wsuperOETHb); + }); + + it('wsuperOETHb -> superOETHb', async function () { + const { wsuperOETHbWrapper, wsuperOETHb } = await loadFixture(initContracts); + const response = await wsuperOETHbWrapper.wrap(tokens.base.wsuperOETHb); + expect(response.rate).to.equal(await wsuperOETHb.previewRedeem(ether('1'))); + expect(response.wrappedToken).to.equal(tokens.base.superOETHb); + }); +});