From a39bc7310070001498ce5393f8e84cedde3f04f5 Mon Sep 17 00:00:00 2001 From: akashiceth Date: Wed, 9 Aug 2023 14:52:23 +0800 Subject: [PATCH 1/2] feat: Add buy with erc20 --- .gitignore | 1 - .openzeppelin/goerli.json | 437 ++++++++++++++++++- abis/BaseAdapter.json | 308 +++++++++++++ abis/BaseAdapterV2.json | 308 +++++++++++++ abis/BendExchangeAdapter.json | 365 ++++++++++++++++ abis/Downpayment.json | 482 +++++++++++++++++++++ abis/IAaveFlashLoanReceiver.json | 41 ++ abis/IAaveLendPool.json | 45 ++ abis/IAaveLendPoolAddressesProvider.json | 15 + abis/IAuthorizationManager.json | 67 +++ abis/IBToken.json | 204 +++++++++ abis/IBendCollector.json | 48 ++ abis/IBendExchange.json | 319 ++++++++++++++ abis/ICryptoPunksMarket.json | 152 +++++++ abis/IDebtToken.json | 222 ++++++++++ abis/IDownpayment.json | 274 ++++++++++++ abis/IENSReverseRegistrar.json | 21 + abis/ILendPool.json | 156 +++++++ abis/ILendPoolAddressesProvider.json | 15 + abis/ILooksRareExchange.json | 147 +++++++ abis/ILooksRareTransferSelectorNFT.json | 21 + abis/INFTOracle.json | 150 +++++++ abis/IOpenseaExchage.json | 110 +++++ abis/IOpenseaRegistry.json | 34 ++ abis/ISeaport.json | 236 ++++++++++ abis/IWETH.json | 142 ++++++ abis/IWrappedPunks.json | 352 +++++++++++++++ abis/IX2Y2.json | 245 +++++++++++ abis/LooksRareExchangeAdapter.json | 365 ++++++++++++++++ abis/PercentageMath.json | 80 ++++ abis/PunkAdapter.json | 396 +++++++++++++++++ abis/SeaportAdapter.json | 383 ++++++++++++++++ abis/X2Y2Adapter.json | 365 ++++++++++++++++ contracts/Downpayment.sol | 20 +- contracts/adapters/BaseAdapterV2.sol | 266 ++++++++++++ contracts/adapters/BendExchangeAdapter.sol | 25 +- contracts/interfaces/IBendExchange.sol | 2 + contracts/interfaces/IDownpayment.sol | 8 + contracts/test/MintableERC20.sol | 56 +++ contracts/test/MockAaveLendPool.sol | 1 + deployments/deployed-contracts-goerli.json | 2 +- hardhat.config.ts | 4 +- tasks/deploy.ts | 28 +- tasks/downpayment.ts | 12 +- test/_setup.ts | 22 +- test/adapters/BendExchangeAdapter.ts | 125 ++++-- test/config.ts | 7 + 47 files changed, 7006 insertions(+), 78 deletions(-) create mode 100644 abis/BaseAdapter.json create mode 100644 abis/BaseAdapterV2.json create mode 100644 abis/BendExchangeAdapter.json create mode 100644 abis/Downpayment.json create mode 100644 abis/IAaveFlashLoanReceiver.json create mode 100644 abis/IAaveLendPool.json create mode 100644 abis/IAaveLendPoolAddressesProvider.json create mode 100644 abis/IAuthorizationManager.json create mode 100644 abis/IBToken.json create mode 100644 abis/IBendCollector.json create mode 100644 abis/IBendExchange.json create mode 100644 abis/ICryptoPunksMarket.json create mode 100644 abis/IDebtToken.json create mode 100644 abis/IDownpayment.json create mode 100644 abis/IENSReverseRegistrar.json create mode 100644 abis/ILendPool.json create mode 100644 abis/ILendPoolAddressesProvider.json create mode 100644 abis/ILooksRareExchange.json create mode 100644 abis/ILooksRareTransferSelectorNFT.json create mode 100644 abis/INFTOracle.json create mode 100644 abis/IOpenseaExchage.json create mode 100644 abis/IOpenseaRegistry.json create mode 100644 abis/ISeaport.json create mode 100644 abis/IWETH.json create mode 100644 abis/IWrappedPunks.json create mode 100644 abis/IX2Y2.json create mode 100644 abis/LooksRareExchangeAdapter.json create mode 100644 abis/PercentageMath.json create mode 100644 abis/PunkAdapter.json create mode 100644 abis/SeaportAdapter.json create mode 100644 abis/X2Y2Adapter.json create mode 100644 contracts/adapters/BaseAdapterV2.sol create mode 100644 contracts/test/MintableERC20.sol diff --git a/.gitignore b/.gitignore index 031c958..9e04a7c 100644 --- a/.gitignore +++ b/.gitignore @@ -115,7 +115,6 @@ typechain-types # Hardhat files cache artifacts -abis/ # Others lib diff --git a/.openzeppelin/goerli.json b/.openzeppelin/goerli.json index 4b8ae32..8d49bde 100644 --- a/.openzeppelin/goerli.json +++ b/.openzeppelin/goerli.json @@ -59,6 +59,11 @@ "address": "0x09116000b14047873efa1BA3C2D70a3F5F23D9ab", "txHash": "0x04a5c68cf27cce14067f7d558ae9e04a20ed2515b0f743be5ca4db24124d7a1e", "kind": "transparent" + }, + { + "address": "0xE1A8858D1CBb17430Ebdf693cb3E035030c310Ba", + "txHash": "0x457caeb6eec61de93237c8156741b103c0eab03f620785944e48f7a08dfa20fa", + "kind": "transparent" } ], "impls": { @@ -136,7 +141,7 @@ "label": "aaveAddressesProvider", "offset": 0, "slot": "153", - "type": "t_contract(IAaveLendPoolAddressesProvider)8385", + "type": "t_contract(IAaveLendPoolAddressesProvider)8278", "contract": "Downpayment", "src": "contracts/Downpayment.sol:26" }, @@ -144,7 +149,7 @@ "label": "WETH", "offset": 0, "slot": "154", - "type": "t_contract(IWETH)9024", + "type": "t_contract(IWETH)8917", "contract": "Downpayment", "src": "contracts/Downpayment.sol:27" }, @@ -152,7 +157,7 @@ "label": "bendAddressesProvider", "offset": 0, "slot": "155", - "type": "t_contract(ILendPoolAddressesProvider)8770", + "type": "t_contract(ILendPoolAddressesProvider)8663", "contract": "Downpayment", "src": "contracts/Downpayment.sol:28" }, @@ -206,15 +211,15 @@ "label": "bytes32", "numberOfBytes": "32" }, - "t_contract(IAaveLendPoolAddressesProvider)8385": { + "t_contract(IAaveLendPoolAddressesProvider)8278": { "label": "contract IAaveLendPoolAddressesProvider", "numberOfBytes": "20" }, - "t_contract(ILendPoolAddressesProvider)8770": { + "t_contract(ILendPoolAddressesProvider)8663": { "label": "contract ILendPoolAddressesProvider", "numberOfBytes": "20" }, - "t_contract(IWETH)9024": { + "t_contract(IWETH)8917": { "label": "contract IWETH", "numberOfBytes": "20" }, @@ -1882,6 +1887,426 @@ } } } + }, + "422fa7d21c101e58fe59d2430044ceae3ded191981bb56f315c6e81534b53710": { + "address": "0xab576dAab2F1eB5417E1064EaBDe801af934D0e7", + "txHash": "0x0570f1ff0854d68ce54aa5e5f9349adb2a97677d4d7fb07f485c391301f659be", + "layout": { + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "label": "_owner", + "offset": 0, + "slot": "51", + "type": "t_address", + "contract": "OwnableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22" + }, + { + "label": "__gap", + "offset": 0, + "slot": "52", + "type": "t_array(t_uint256)49_storage", + "contract": "OwnableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:87" + }, + { + "label": "_status", + "offset": 0, + "slot": "101", + "type": "t_uint256", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)49_storage", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:74" + }, + { + "label": "_whitelistedAdapters", + "offset": 0, + "slot": "151", + "type": "t_struct(AddressSet)2455_storage", + "contract": "Downpayment", + "src": "contracts/Downpayment.sol:24" + }, + { + "label": "aaveAddressesProvider", + "offset": 0, + "slot": "153", + "type": "t_contract(IAaveLendPoolAddressesProvider)9916", + "contract": "Downpayment", + "src": "contracts/Downpayment.sol:26" + }, + { + "label": "WETH", + "offset": 0, + "slot": "154", + "type": "t_contract(IWETH)10578", + "contract": "Downpayment", + "src": "contracts/Downpayment.sol:27" + }, + { + "label": "bendAddressesProvider", + "offset": 0, + "slot": "155", + "type": "t_contract(ILendPoolAddressesProvider)10324", + "contract": "Downpayment", + "src": "contracts/Downpayment.sol:28" + }, + { + "label": "feeCollector", + "offset": 0, + "slot": "156", + "type": "t_address", + "contract": "Downpayment", + "src": "contracts/Downpayment.sol:29" + }, + { + "label": "_nonces", + "offset": 0, + "slot": "157", + "type": "t_mapping(t_address,t_struct(Counter)1223_storage)", + "contract": "Downpayment", + "src": "contracts/Downpayment.sol:36" + }, + { + "label": "fees", + "offset": 0, + "slot": "158", + "type": "t_mapping(t_address,t_uint256)", + "contract": "Downpayment", + "src": "contracts/Downpayment.sol:37" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_contract(IAaveLendPoolAddressesProvider)9916": { + "label": "contract IAaveLendPoolAddressesProvider", + "numberOfBytes": "20" + }, + "t_contract(ILendPoolAddressesProvider)10324": { + "label": "contract ILendPoolAddressesProvider", + "numberOfBytes": "20" + }, + "t_contract(IWETH)10578": { + "label": "contract IWETH", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_struct(Counter)1223_storage)": { + "label": "mapping(address => struct CountersUpgradeable.Counter)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(AddressSet)2455_storage": { + "label": "struct EnumerableSetUpgradeable.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)2154_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Counter)1223_storage": { + "label": "struct CountersUpgradeable.Counter", + "members": [ + { + "label": "_value", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Set)2154_storage": { + "label": "struct EnumerableSetUpgradeable.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage", + "offset": 0, + "slot": "0" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } + }, + "ad4e94de073643a10cfc3201a52d574224f52f7ec5c8634faea9f34d03b95995": { + "address": "0x2bB5CDe366aF194c35AA015e09B60454bd0a67dc", + "txHash": "0xabdae2fc4120cfcce6a9945780a3678a4ee91bad263d007f73aab0196bb3e2c2", + "layout": { + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "label": "_owner", + "offset": 0, + "slot": "51", + "type": "t_address", + "contract": "OwnableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22" + }, + { + "label": "__gap", + "offset": 0, + "slot": "52", + "type": "t_array(t_uint256)49_storage", + "contract": "OwnableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:87" + }, + { + "label": "_paused", + "offset": 0, + "slot": "101", + "type": "t_bool", + "contract": "PausableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)49_storage", + "contract": "PausableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:102" + }, + { + "label": "_status", + "offset": 0, + "slot": "151", + "type": "t_uint256", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "152", + "type": "t_array(t_uint256)49_storage", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:74" + }, + { + "label": "_HASHED_NAME", + "offset": 0, + "slot": "201", + "type": "t_bytes32", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol:32" + }, + { + "label": "_HASHED_VERSION", + "offset": 0, + "slot": "202", + "type": "t_bytes32", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol:33" + }, + { + "label": "__gap", + "offset": 0, + "slot": "203", + "type": "t_array(t_uint256)50_storage", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol:120" + }, + { + "label": "__gap", + "offset": 0, + "slot": "253", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC721HolderUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol:40" + }, + { + "label": "downpayment", + "offset": 0, + "slot": "303", + "type": "t_contract(IDownpayment)10235", + "contract": "BaseAdapterV2", + "src": "contracts/adapters/BaseAdapterV2.sol:41" + }, + { + "label": "WETH", + "offset": 0, + "slot": "304", + "type": "t_contract(IWETH)10578", + "contract": "BaseAdapterV2", + "src": "contracts/adapters/BaseAdapterV2.sol:42" + }, + { + "label": "__gap", + "offset": 0, + "slot": "305", + "type": "t_array(t_uint256)43_storage", + "contract": "BaseAdapterV2", + "src": "contracts/adapters/BaseAdapterV2.sol:43" + }, + { + "label": "bendExchange", + "offset": 0, + "slot": "348", + "type": "t_contract(IBendExchange)10038", + "contract": "BendExchangeAdapter", + "src": "contracts/adapters/BendExchangeAdapter.sol:17" + }, + { + "label": "proxy", + "offset": 0, + "slot": "349", + "type": "t_address", + "contract": "BendExchangeAdapter", + "src": "contracts/adapters/BendExchangeAdapter.sol:18" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)43_storage": { + "label": "uint256[43]", + "numberOfBytes": "1376" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_contract(IBendExchange)10038": { + "label": "contract IBendExchange", + "numberOfBytes": "20" + }, + "t_contract(IDownpayment)10235": { + "label": "contract IDownpayment", + "numberOfBytes": "20" + }, + "t_contract(IWETH)10578": { + "label": "contract IWETH", + "numberOfBytes": "20" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } } } } diff --git a/abis/BaseAdapter.json b/abis/BaseAdapter.json new file mode 100644 index 0000000..93c2a3a --- /dev/null +++ b/abis/BaseAdapter.json @@ -0,0 +1,308 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "buyer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "nftToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nftTokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "borrowedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "flashLoanFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "downpaymentFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "Purchased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "contract IWETH", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "downpayment", + "outputs": [ + { + "internalType": "contract IDownpayment", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_amounts", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_premiums", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "_initiator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_params", + "type": "bytes" + } + ], + "name": "executeOperation", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "registrar", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + } + ], + "name": "setENSName", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/abis/BaseAdapterV2.json b/abis/BaseAdapterV2.json new file mode 100644 index 0000000..93c2a3a --- /dev/null +++ b/abis/BaseAdapterV2.json @@ -0,0 +1,308 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "buyer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "nftToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nftTokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "borrowedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "flashLoanFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "downpaymentFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "Purchased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "contract IWETH", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "downpayment", + "outputs": [ + { + "internalType": "contract IDownpayment", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_amounts", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_premiums", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "_initiator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_params", + "type": "bytes" + } + ], + "name": "executeOperation", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "registrar", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + } + ], + "name": "setENSName", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/abis/BendExchangeAdapter.json b/abis/BendExchangeAdapter.json new file mode 100644 index 0000000..dd10ae6 --- /dev/null +++ b/abis/BendExchangeAdapter.json @@ -0,0 +1,365 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "buyer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "nftToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nftTokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "borrowedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "flashLoanFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "downpaymentFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "Purchased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "contract IWETH", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bendExchange", + "outputs": [ + { + "internalType": "contract IBendExchange", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "downpayment", + "outputs": [ + { + "internalType": "contract IDownpayment", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_amounts", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_premiums", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "_initiator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_params", + "type": "bytes" + } + ], + "name": "executeOperation", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_downpayment", + "type": "address" + }, + { + "internalType": "address", + "name": "_bendExchange", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "registrar", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + } + ], + "name": "setENSName", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/abis/Downpayment.json b/abis/Downpayment.json new file mode 100644 index 0000000..c61b347 --- /dev/null +++ b/abis/Downpayment.json @@ -0,0 +1,482 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "adapter", + "type": "address" + } + ], + "name": "AdapterRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "adapter", + "type": "address" + } + ], + "name": "AdapterWhitelisted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "adapter", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "newFee", + "type": "uint256" + } + ], + "name": "FeeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "contract IWETH", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "aaveAddressesProvider", + "outputs": [ + { + "internalType": "contract IAaveLendPoolAddressesProvider", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adapter", + "type": "address" + } + ], + "name": "addAdapter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "bendAddressesProvider", + "outputs": [ + { + "internalType": "contract ILendPoolAddressesProvider", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adapter", + "type": "address" + }, + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IDownpayment.Sig", + "name": "sig", + "type": "tuple" + } + ], + "name": "buy", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adapter", + "type": "address" + }, + { + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IDownpayment.Sig", + "name": "sig", + "type": "tuple" + } + ], + "name": "buyWithERC20", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "feeCollector", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAaveLendPool", + "outputs": [ + { + "internalType": "contract IAaveLendPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBendLendPool", + "outputs": [ + { + "internalType": "contract ILendPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adapter", + "type": "address" + } + ], + "name": "getFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getFeeCollector", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_aaveAddressesProvider", + "type": "address" + }, + { + "internalType": "address", + "name": "_bendAddressesProvider", + "type": "address" + }, + { + "internalType": "address", + "name": "_feeCollector", + "type": "address" + }, + { + "internalType": "address", + "name": "_weth", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adapter", + "type": "address" + } + ], + "name": "isAdapterWhitelisted", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adapter", + "type": "address" + } + ], + "name": "removeAdapter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_feeCollector", + "type": "address" + } + ], + "name": "setFeeCollector", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adapter", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_newFee", + "type": "uint256" + } + ], + "name": "updateFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "viewCountWhitelistedAdapters", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "cursor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "size", + "type": "uint256" + } + ], + "name": "viewWhitelistedAdapters", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/abis/IAaveFlashLoanReceiver.json b/abis/IAaveFlashLoanReceiver.json new file mode 100644 index 0000000..5b28521 --- /dev/null +++ b/abis/IAaveFlashLoanReceiver.json @@ -0,0 +1,41 @@ +[ + { + "inputs": [ + { + "internalType": "address[]", + "name": "assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "premiums", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "initiator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "params", + "type": "bytes" + } + ], + "name": "executeOperation", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abis/IAaveLendPool.json b/abis/IAaveLendPool.json new file mode 100644 index 0000000..a1dfa58 --- /dev/null +++ b/abis/IAaveLendPool.json @@ -0,0 +1,45 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "receiverAddress", + "type": "address" + }, + { + "internalType": "address[]", + "name": "assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "modes", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "onBehalfOf", + "type": "address" + }, + { + "internalType": "bytes", + "name": "params", + "type": "bytes" + }, + { + "internalType": "uint16", + "name": "referralCode", + "type": "uint16" + } + ], + "name": "flashLoan", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abis/IAaveLendPoolAddressesProvider.json b/abis/IAaveLendPoolAddressesProvider.json new file mode 100644 index 0000000..f16ddd3 --- /dev/null +++ b/abis/IAaveLendPoolAddressesProvider.json @@ -0,0 +1,15 @@ +[ + { + "inputs": [], + "name": "getLendingPool", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/abis/IAuthorizationManager.json b/abis/IAuthorizationManager.json new file mode 100644 index 0000000..bfbc678 --- /dev/null +++ b/abis/IAuthorizationManager.json @@ -0,0 +1,67 @@ +[ + { + "inputs": [], + "name": "authorizedAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "proxies", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "registerProxy", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "revoke", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "revoked", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/abis/IBToken.json b/abis/IBToken.json new file mode 100644 index 0000000..0c3dd62 --- /dev/null +++ b/abis/IBToken.json @@ -0,0 +1,204 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "scaledBalanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abis/IBendCollector.json b/abis/IBendCollector.json new file mode 100644 index 0000000..b0e38f4 --- /dev/null +++ b/abis/IBendCollector.json @@ -0,0 +1,48 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abis/IBendExchange.json b/abis/IBendExchange.json new file mode 100644 index 0000000..d470dfe --- /dev/null +++ b/abis/IBendExchange.json @@ -0,0 +1,319 @@ +[ + { + "inputs": [], + "name": "authorizationManager", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "isOrderAsk", + "type": "bool" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minPercentageToAsk", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "params", + "type": "bytes" + }, + { + "internalType": "address", + "name": "interceptor", + "type": "address" + }, + { + "internalType": "bytes", + "name": "interceptorExtra", + "type": "bytes" + } + ], + "internalType": "struct IBendExchange.TakerOrder", + "name": "takerBid", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bool", + "name": "isOrderAsk", + "type": "bool" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "collection", + "type": "address" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "strategy", + "type": "address" + }, + { + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minPercentageToAsk", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "params", + "type": "bytes" + }, + { + "internalType": "address", + "name": "interceptor", + "type": "address" + }, + { + "internalType": "bytes", + "name": "interceptorExtra", + "type": "bytes" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IBendExchange.MakerOrder", + "name": "makerAsk", + "type": "tuple" + } + ], + "name": "matchAskWithTakerBid", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "isOrderAsk", + "type": "bool" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minPercentageToAsk", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "params", + "type": "bytes" + }, + { + "internalType": "address", + "name": "interceptor", + "type": "address" + }, + { + "internalType": "bytes", + "name": "interceptorExtra", + "type": "bytes" + } + ], + "internalType": "struct IBendExchange.TakerOrder", + "name": "takerBid", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bool", + "name": "isOrderAsk", + "type": "bool" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "collection", + "type": "address" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "strategy", + "type": "address" + }, + { + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minPercentageToAsk", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "params", + "type": "bytes" + }, + { + "internalType": "address", + "name": "interceptor", + "type": "address" + }, + { + "internalType": "bytes", + "name": "interceptorExtra", + "type": "bytes" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IBendExchange.MakerOrder", + "name": "makerAsk", + "type": "tuple" + } + ], + "name": "matchAskWithTakerBidUsingETHAndWETH", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } +] diff --git a/abis/ICryptoPunksMarket.json b/abis/ICryptoPunksMarket.json new file mode 100644 index 0000000..cfb02a5 --- /dev/null +++ b/abis/ICryptoPunksMarket.json @@ -0,0 +1,152 @@ +[ + { + "inputs": [ + { + "internalType": "uint256", + "name": "punkIndex", + "type": "uint256" + } + ], + "name": "buyPunk", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "punkIndex", + "type": "uint256" + } + ], + "name": "getPunk", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "punkIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minSalePriceInWei", + "type": "uint256" + } + ], + "name": "offerPunkForSale", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "punkIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minSalePriceInWei", + "type": "uint256" + }, + { + "internalType": "address", + "name": "toAddress", + "type": "address" + } + ], + "name": "offerPunkForSaleToAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "punkIndex", + "type": "uint256" + } + ], + "name": "punkIndexToAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "punkIndex", + "type": "uint256" + } + ], + "name": "punksOfferedForSale", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "isForSale", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "punkIndex", + "type": "uint256" + }, + { + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minValue", + "type": "uint256" + }, + { + "internalType": "address", + "name": "onlySellTo", + "type": "address" + } + ], + "internalType": "struct ICryptoPunksMarket.Offer", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "punkIndex", + "type": "uint256" + } + ], + "name": "transferPunk", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abis/IDebtToken.json b/abis/IDebtToken.json new file mode 100644 index 0000000..8d72031 --- /dev/null +++ b/abis/IDebtToken.json @@ -0,0 +1,222 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "delegatee", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approveDelegation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "scaledBalanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abis/IDownpayment.json b/abis/IDownpayment.json new file mode 100644 index 0000000..82be495 --- /dev/null +++ b/abis/IDownpayment.json @@ -0,0 +1,274 @@ +[ + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "contract IWETH", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adapter", + "type": "address" + } + ], + "name": "addAdapter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adapter", + "type": "address" + }, + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IDownpayment.Sig", + "name": "sig", + "type": "tuple" + } + ], + "name": "buy", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adapter", + "type": "address" + }, + { + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IDownpayment.Sig", + "name": "sig", + "type": "tuple" + } + ], + "name": "buyWithERC20", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getAaveLendPool", + "outputs": [ + { + "internalType": "contract IAaveLendPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBendLendPool", + "outputs": [ + { + "internalType": "contract ILendPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adapter", + "type": "address" + } + ], + "name": "getFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getFeeCollector", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adapter", + "type": "address" + } + ], + "name": "isAdapterWhitelisted", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adapter", + "type": "address" + } + ], + "name": "removeAdapter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "viewCountWhitelistedAdapters", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "cursor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "size", + "type": "uint256" + } + ], + "name": "viewWhitelistedAdapters", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/abis/IENSReverseRegistrar.json b/abis/IENSReverseRegistrar.json new file mode 100644 index 0000000..439b78f --- /dev/null +++ b/abis/IENSReverseRegistrar.json @@ -0,0 +1,21 @@ +[ + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + } + ], + "name": "setName", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abis/ILendPool.json b/abis/ILendPool.json new file mode 100644 index 0000000..e3df61a --- /dev/null +++ b/abis/ILendPool.json @@ -0,0 +1,156 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "reserveAsset", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "nftAsset", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nftTokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "onBehalfOf", + "type": "address" + }, + { + "internalType": "uint16", + "name": "referralCode", + "type": "uint16" + } + ], + "name": "borrow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "reserve", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "onBehalfOf", + "type": "address" + }, + { + "internalType": "uint16", + "name": "referralCode", + "type": "uint16" + } + ], + "name": "deposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "nftAsset", + "type": "address" + }, + { + "internalType": "address", + "name": "reserveAsset", + "type": "address" + } + ], + "name": "getNftCollateralData", + "outputs": [ + { + "internalType": "uint256", + "name": "totalCollateralInETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalCollateralInReserve", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "availableBorrowsInETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "availableBorrowsInReserve", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "ltv", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidationThreshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidationBonus", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "nftAsset", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nftTokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "repay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abis/ILendPoolAddressesProvider.json b/abis/ILendPoolAddressesProvider.json new file mode 100644 index 0000000..3307935 --- /dev/null +++ b/abis/ILendPoolAddressesProvider.json @@ -0,0 +1,15 @@ +[ + { + "inputs": [], + "name": "getLendPool", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/abis/ILooksRareExchange.json b/abis/ILooksRareExchange.json new file mode 100644 index 0000000..43ec8c1 --- /dev/null +++ b/abis/ILooksRareExchange.json @@ -0,0 +1,147 @@ +[ + { + "inputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "isOrderAsk", + "type": "bool" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minPercentageToAsk", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "params", + "type": "bytes" + } + ], + "internalType": "struct ILooksRareExchange.TakerOrder", + "name": "takerBid", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bool", + "name": "isOrderAsk", + "type": "bool" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "collection", + "type": "address" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "strategy", + "type": "address" + }, + { + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minPercentageToAsk", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "params", + "type": "bytes" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct ILooksRareExchange.MakerOrder", + "name": "makerAsk", + "type": "tuple" + } + ], + "name": "matchAskWithTakerBidUsingETHAndWETH", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "transferSelectorNFT", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/abis/ILooksRareTransferSelectorNFT.json b/abis/ILooksRareTransferSelectorNFT.json new file mode 100644 index 0000000..5626305 --- /dev/null +++ b/abis/ILooksRareTransferSelectorNFT.json @@ -0,0 +1,21 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "collection", + "type": "address" + } + ], + "name": "checkTransferManagerForToken", + "outputs": [ + { + "internalType": "address", + "name": "transferManager", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/abis/INFTOracle.json b/abis/INFTOracle.json new file mode 100644 index 0000000..c32deea --- /dev/null +++ b/abis/INFTOracle.json @@ -0,0 +1,150 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_nftContract", + "type": "address" + } + ], + "name": "getAssetPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_nftContract", + "type": "address" + } + ], + "name": "getLatestTimestamp", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_nftContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_numOfRoundBack", + "type": "uint256" + } + ], + "name": "getPreviousPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_nftContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_numOfRoundBack", + "type": "uint256" + } + ], + "name": "getPreviousTimestamp", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeedAdmin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_nftContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "setAssetData", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_nftContract", + "type": "address" + }, + { + "internalType": "bool", + "name": "val", + "type": "bool" + } + ], + "name": "setPause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_twapInterval", + "type": "uint256" + } + ], + "name": "setTwapInterval", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abis/IOpenseaExchage.json b/abis/IOpenseaExchage.json new file mode 100644 index 0000000..6805e55 --- /dev/null +++ b/abis/IOpenseaExchage.json @@ -0,0 +1,110 @@ +[ + { + "inputs": [ + { + "internalType": "address[14]", + "name": "addrs", + "type": "address[14]" + }, + { + "internalType": "uint256[18]", + "name": "uints", + "type": "uint256[18]" + }, + { + "internalType": "uint8[8]", + "name": "feeMethodsSidesKindsHowToCalls", + "type": "uint8[8]" + }, + { + "internalType": "bytes", + "name": "calldataBuy", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "calldataSell", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "replacementPatternBuy", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "replacementPatternSell", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "staticExtradataBuy", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "staticExtradataSell", + "type": "bytes" + }, + { + "internalType": "uint8[2]", + "name": "vs", + "type": "uint8[2]" + }, + { + "internalType": "bytes32[5]", + "name": "rssMetadata", + "type": "bytes32[5]" + } + ], + "name": "atomicMatch_", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "registry", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "tokenTransferProxy", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/abis/IOpenseaRegistry.json b/abis/IOpenseaRegistry.json new file mode 100644 index 0000000..472ebc8 --- /dev/null +++ b/abis/IOpenseaRegistry.json @@ -0,0 +1,34 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "proxies", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "registerProxy", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abis/ISeaport.json b/abis/ISeaport.json new file mode 100644 index 0000000..ace1f2b --- /dev/null +++ b/abis/ISeaport.json @@ -0,0 +1,236 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "offerer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "zone", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "components": [ + { + "internalType": "enum ISeaport.ItemType", + "name": "itemType", + "type": "uint8" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "identifier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "indexed": false, + "internalType": "struct ISeaport.SpentItem[]", + "name": "offer", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "enum ISeaport.ItemType", + "name": "itemType", + "type": "uint8" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "identifier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + } + ], + "indexed": false, + "internalType": "struct ISeaport.ReceivedItem[]", + "name": "consideration", + "type": "tuple[]" + } + ], + "name": "OrderFulfilled", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "considerationToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "considerationIdentifier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "considerationAmount", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "offerer", + "type": "address" + }, + { + "internalType": "address", + "name": "zone", + "type": "address" + }, + { + "internalType": "address", + "name": "offerToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "offerIdentifier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "offerAmount", + "type": "uint256" + }, + { + "internalType": "enum ISeaport.BasicOrderType", + "name": "basicOrderType", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endTime", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "zoneHash", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "salt", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "offererConduitKey", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "fulfillerConduitKey", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "totalOriginalAdditionalRecipients", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + } + ], + "internalType": "struct ISeaport.AdditionalRecipient[]", + "name": "additionalRecipients", + "type": "tuple[]" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct ISeaport.BasicOrderParameters", + "name": "parameters", + "type": "tuple" + } + ], + "name": "fulfillBasicOrder", + "outputs": [ + { + "internalType": "bool", + "name": "fulfilled", + "type": "bool" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "offerer", + "type": "address" + } + ], + "name": "getCounter", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/abis/IWETH.json b/abis/IWETH.json new file mode 100644 index 0000000..40763f8 --- /dev/null +++ b/abis/IWETH.json @@ -0,0 +1,142 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "guy", + "type": "address" + }, + { + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "deposit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abis/IWrappedPunks.json b/abis/IWrappedPunks.json new file mode 100644 index 0000000..5ad0061 --- /dev/null +++ b/abis/IWrappedPunks.json @@ -0,0 +1,352 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "punkIndex", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "punkIndex", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "proxyInfo", + "outputs": [ + { + "internalType": "address", + "name": "proxy", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "punkContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "registerProxy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "_approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abis/IX2Y2.json b/abis/IX2Y2.json new file mode 100644 index 0000000..c416aab --- /dev/null +++ b/abis/IX2Y2.json @@ -0,0 +1,245 @@ +[ + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "uint256", + "name": "salt", + "type": "uint256" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "uint256", + "name": "network", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "intent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "delegateType", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "internalType": "bytes", + "name": "dataMask", + "type": "bytes" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "internalType": "struct IX2Y2.OrderItem[]", + "name": "items", + "type": "tuple[]" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "signVersion", + "type": "uint8" + } + ], + "internalType": "struct IX2Y2.Order[]", + "name": "orders", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "enum IX2Y2.Op", + "name": "op", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "orderIdx", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "itemIdx", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "itemHash", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "executionDelegate", + "type": "address" + }, + { + "internalType": "bytes", + "name": "dataReplacement", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "bidIncentivePct", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "aucMinIncrementPct", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "aucIncDurationSecs", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "percentage", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "internalType": "struct IX2Y2.Fee[]", + "name": "fees", + "type": "tuple[]" + } + ], + "internalType": "struct IX2Y2.SettleDetail[]", + "name": "details", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "salt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountToEth", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountToWeth", + "type": "uint256" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "bool", + "name": "canFail", + "type": "bool" + } + ], + "internalType": "struct IX2Y2.SettleShared", + "name": "shared", + "type": "tuple" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + } + ], + "internalType": "struct IX2Y2.RunInput", + "name": "input", + "type": "tuple" + } + ], + "name": "run", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "toAdd", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "toRemove", + "type": "address[]" + } + ], + "name": "updateSigners", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abis/LooksRareExchangeAdapter.json b/abis/LooksRareExchangeAdapter.json new file mode 100644 index 0000000..bb1ee2c --- /dev/null +++ b/abis/LooksRareExchangeAdapter.json @@ -0,0 +1,365 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "buyer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "nftToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nftTokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "borrowedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "flashLoanFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "downpaymentFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "Purchased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "contract IWETH", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "downpayment", + "outputs": [ + { + "internalType": "contract IDownpayment", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_amounts", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_premiums", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "_initiator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_params", + "type": "bytes" + } + ], + "name": "executeOperation", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_downpayment", + "type": "address" + }, + { + "internalType": "address", + "name": "_looksRareExchange", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "looksRareExchange", + "outputs": [ + { + "internalType": "contract ILooksRareExchange", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "registrar", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + } + ], + "name": "setENSName", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/abis/PercentageMath.json b/abis/PercentageMath.json new file mode 100644 index 0000000..a86f4f3 --- /dev/null +++ b/abis/PercentageMath.json @@ -0,0 +1,80 @@ +[ + { + "inputs": [], + "name": "HALF_PERCENT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ONE_PERCENT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ONE_TEN_THOUSANDTH_PERCENT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ONE_THOUSANDTH_PERCENT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PERCENTAGE_FACTOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TEN_PERCENT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/abis/PunkAdapter.json b/abis/PunkAdapter.json new file mode 100644 index 0000000..a3a39c9 --- /dev/null +++ b/abis/PunkAdapter.json @@ -0,0 +1,396 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "buyer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "nftToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nftTokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "borrowedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "flashLoanFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "downpaymentFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "Purchased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "contract IWETH", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "downpayment", + "outputs": [ + { + "internalType": "contract IDownpayment", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_amounts", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_premiums", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "_initiator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_params", + "type": "bytes" + } + ], + "name": "executeOperation", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_downpayment", + "type": "address" + }, + { + "internalType": "address", + "name": "_cryptoPunksMarket", + "type": "address" + }, + { + "internalType": "address", + "name": "_wrappedPunks", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "punksMarket", + "outputs": [ + { + "internalType": "contract ICryptoPunksMarket", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "registrar", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + } + ], + "name": "setENSName", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "wpunkProxy", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "wrappedPunks", + "outputs": [ + { + "internalType": "contract IWrappedPunks", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/abis/SeaportAdapter.json b/abis/SeaportAdapter.json new file mode 100644 index 0000000..9027182 --- /dev/null +++ b/abis/SeaportAdapter.json @@ -0,0 +1,383 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "buyer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "nftToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nftTokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "borrowedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "flashLoanFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "downpaymentFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "Purchased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "contract IWETH", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "conduitAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "downpayment", + "outputs": [ + { + "internalType": "contract IDownpayment", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_amounts", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_premiums", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "_initiator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_params", + "type": "bytes" + } + ], + "name": "executeOperation", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_downpayment", + "type": "address" + }, + { + "internalType": "address", + "name": "_seaportExchange", + "type": "address" + }, + { + "internalType": "address", + "name": "_conduitAddress", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "seaportExchange", + "outputs": [ + { + "internalType": "contract ISeaport", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "registrar", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + } + ], + "name": "setENSName", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/abis/X2Y2Adapter.json b/abis/X2Y2Adapter.json new file mode 100644 index 0000000..202595d --- /dev/null +++ b/abis/X2Y2Adapter.json @@ -0,0 +1,365 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "buyer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "nftToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nftTokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "borrowedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "flashLoanFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "downpaymentFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "Purchased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "contract IWETH", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "downpayment", + "outputs": [ + { + "internalType": "contract IDownpayment", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_amounts", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_premiums", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "_initiator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_params", + "type": "bytes" + } + ], + "name": "executeOperation", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_downpayment", + "type": "address" + }, + { + "internalType": "address", + "name": "_x2y2", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "registrar", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + } + ], + "name": "setENSName", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "x2y2", + "outputs": [ + { + "internalType": "contract IX2Y2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/contracts/Downpayment.sol b/contracts/Downpayment.sol index 79c18f6..3b0146f 100644 --- a/contracts/Downpayment.sol +++ b/contracts/Downpayment.sol @@ -79,6 +79,25 @@ contract Downpayment is OwnableUpgradeable, ReentrancyGuardUpgradeable, IDownpay _incrementNonce(msg.sender); } + function buyWithERC20( + address adapter, + address currency, + uint256 borrowAmount, + bytes calldata data, + Sig calldata sig + ) external override onlyWhitelisted(adapter) nonReentrant { + IAaveLendPool aavePool = IAaveLendPool(aaveAddressesProvider.getLendingPool()); + address[] memory assets = new address[](1); + assets[0] = address(currency); + uint256[] memory amounts = new uint256[](1); + amounts[0] = borrowAmount; + uint256[] memory modes = new uint256[](1); + modes[0] = 0; + bytes memory dataWithSignature = abi.encode(data, msg.sender, sig.v, sig.r, sig.s); + aavePool.flashLoan(adapter, assets, amounts, modes, address(0), dataWithSignature, 0); + _incrementNonce(msg.sender); + } + function addAdapter(address adapter) external override onlyOwner { require(adapter != address(0), "Adapter: can not be null address"); require(!_whitelistedAdapters.contains(adapter), "Adapter: already whitelisted"); @@ -88,7 +107,6 @@ contract Downpayment is OwnableUpgradeable, ReentrancyGuardUpgradeable, IDownpay function removeAdapter(address adapter) external override onlyOwner onlyWhitelisted(adapter) { _whitelistedAdapters.remove(adapter); - emit AdapterRemoved(adapter); } diff --git a/contracts/adapters/BaseAdapterV2.sol b/contracts/adapters/BaseAdapterV2.sol new file mode 100644 index 0000000..9d632fb --- /dev/null +++ b/contracts/adapters/BaseAdapterV2.sol @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.8.9; + +import {EIP712Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; +import {IERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol"; +import {ERC721HolderUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol"; +import {IERC20Upgradeable, SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; +import {SignatureCheckerUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/SignatureCheckerUpgradeable.sol"; + +import {IAaveFlashLoanReceiver} from "../interfaces/IAaveFlashLoanReceiver.sol"; +import {ILendPool} from "../interfaces/ILendPool.sol"; +import {PercentageMath} from "../libraries/PercentageMath.sol"; +import {IWETH} from "../interfaces/IWETH.sol"; +import {IDownpayment} from "../interfaces/IDownpayment.sol"; +import {IENSReverseRegistrar} from "../interfaces/IENSReverseRegistrar.sol"; + +abstract contract BaseAdapterV2 is + IAaveFlashLoanReceiver, + OwnableUpgradeable, + PausableUpgradeable, + ReentrancyGuardUpgradeable, + EIP712Upgradeable, + ERC721HolderUpgradeable +{ + using SafeERC20Upgradeable for IERC20Upgradeable; + using PercentageMath for uint256; + event Purchased( + address indexed buyer, + address indexed nftToken, + uint256 nftTokenId, + address indexed currency, + uint256 borrowedAmount, + uint256 price, + uint256 flashLoanFee, + uint256 downpaymentFee, + bytes32 orderHash + ); + IDownpayment public downpayment; + IWETH public WETH; + uint256[43] private __gap; + + function __BaseAdapter_init( + string memory _name, + string memory _version, + address _downpayment + ) internal onlyInitializing { + __Ownable_init(); + __Pausable_init(); + __ReentrancyGuard_init(); + __EIP712_init(_name, _version); + downpayment = IDownpayment(_downpayment); + WETH = downpayment.WETH(); + } + + struct BaseParams { + address nftAsset; + uint256 nftTokenId; + IERC20Upgradeable currency; + uint256 salePrice; + bytes32 paramsHash; + } + struct LocalVars { + address buyer; + uint256 bendFeeAmount; + uint256 buyerPayment; + uint256 flashBorrowedAmount; + uint256 flashFee; + uint256 flashLoanDebt; + uint256 nonce; + bytes params; + uint8 v; + bytes32 r; + bytes32 s; + } + + // external functions + function executeOperation( + address[] calldata _assets, + uint256[] calldata _amounts, + uint256[] calldata _premiums, + address _initiator, + bytes calldata _params + ) external override nonReentrant whenNotPaused returns (bool) { + require(msg.sender == address(downpayment.getAaveLendPool()), "Adapter: caller must be aave lending pool"); + require(_initiator == address(downpayment), "Adapter: flashloan initiator must be downpayment"); + uint256 fee = downpayment.getFee(address(this)); + require( + _assets.length == 1 && _amounts.length == 1 && _premiums.length == 1, + "Adapter: multiple assets not supported" + ); + LocalVars memory vars; + (vars.params, vars.buyer, vars.v, vars.r, vars.s) = abi.decode( + _params, + (bytes, address, uint8, bytes32, bytes32) + ); + + vars.flashBorrowedAmount = _amounts[0]; + vars.flashFee = _premiums[0]; + vars.nonce = downpayment.nonces(vars.buyer); + + BaseParams memory baseParams = _checkParams( + vars.buyer, + vars.flashBorrowedAmount, + vars.flashFee, + vars.params, + vars.nonce + ); + _checkSig(vars.buyer, baseParams.paramsHash, vars.v, vars.r, vars.s); + + require( + vars.flashBorrowedAmount <= baseParams.currency.balanceOf(address(this)), + "Adapter: insufficient flash loan" + ); + + // Check if the flash loan can be paid off and payment sufficient + vars.bendFeeAmount = baseParams.salePrice.percentMul(fee); + + vars.buyerPayment = vars.bendFeeAmount + vars.flashFee + baseParams.salePrice - vars.flashBorrowedAmount; + require( + baseParams.currency.balanceOf(vars.buyer) >= vars.buyerPayment && + baseParams.currency.allowance(vars.buyer, address(this)) >= vars.buyerPayment, + "Adapter: currency Insufficient" + ); + + vars.flashLoanDebt = vars.flashBorrowedAmount + vars.flashFee; + + // Prepare currency, need buyer approve currency to this contract + if (vars.buyerPayment > 0) { + baseParams.currency.safeTransferFrom(vars.buyer, address(this), vars.buyerPayment); + } + + // Do exchange + _exchange(baseParams, vars.params); + + _beforeBorrow( + baseParams.nftAsset, + baseParams.nftTokenId, + vars.buyer, + baseParams.currency, + vars.flashBorrowedAmount + ); + + // Borrow from bend, need buyer approve NFT to this contract + _borrow(baseParams.nftAsset, baseParams.nftTokenId, vars.buyer, baseParams.currency, vars.flashBorrowedAmount); + + _afterBorrow( + baseParams.nftAsset, + baseParams.nftTokenId, + vars.buyer, + baseParams.currency, + vars.flashBorrowedAmount + ); + + // Charge fee, sent to bend collector + _chargeFee(baseParams.currency, vars.bendFeeAmount); + + // Repay flash loan + _repayFlashLoan(baseParams.currency, vars.flashLoanDebt); + + emit Purchased( + vars.buyer, + baseParams.nftAsset, + baseParams.nftTokenId, + address(baseParams.currency), + vars.flashBorrowedAmount, + baseParams.salePrice, + vars.flashFee, + vars.bendFeeAmount, + baseParams.paramsHash + ); + return true; + } + + function pause() external onlyOwner whenNotPaused { + _pause(); + } + + function unpause() external onlyOwner whenPaused { + _unpause(); + } + + function setENSName(address registrar, string memory name) external onlyOwner returns (bytes32) { + return IENSReverseRegistrar(registrar).setName(name); + } + + // abstract functions + function _checkParams( + address _buyer, + uint256 _flashBorrowedAmount, + uint256 _flashFee, + bytes memory _params, + uint256 _nonce + ) internal view virtual returns (BaseParams memory); + + function _exchange(BaseParams memory baseParams, bytes memory _params) internal virtual; + + // internal functions + function _chargeFee(IERC20Upgradeable currency_, uint256 _amount) internal { + if (_amount > 0) { + currency_.safeTransfer(downpayment.getFeeCollector(), _amount); + } + } + + function _beforeBorrow( + address nftAsset_, + uint256 nftTokenId_, + address onBehalfOf_, + IERC20Upgradeable currency_, + uint256 amount_ + ) internal virtual {} + + function _borrow( + address nftAsset_, + uint256 nftTokenId_, + address onBehalfOf_, + IERC20Upgradeable currency_, + uint256 amount_ + ) internal { + ILendPool _pool = downpayment.getBendLendPool(); + IERC721Upgradeable _nftERC721 = IERC721Upgradeable(nftAsset_); + require(_nftERC721.ownerOf(nftTokenId_) == address(this), "Adapter: not own nft"); + _nftERC721.approve(address(_pool), nftTokenId_); + _pool.borrow(address(currency_), amount_, nftAsset_, nftTokenId_, onBehalfOf_, 0); + } + + function _afterBorrow( + address nftAsset_, + uint256 nftTokenId_, + address onBehalfOf_, + IERC20Upgradeable currency_, + uint256 amount_ + ) internal virtual {} + + function _repayFlashLoan(IERC20Upgradeable currency_, uint256 flashLoanDebt_) internal { + address aaveLendPool = address(downpayment.getAaveLendPool()); + currency_.approve(aaveLendPool, 0); + currency_.approve(aaveLendPool, flashLoanDebt_); + } + + function _checkSig( + address _signer, + bytes32 paramsHash, + uint8 v, + bytes32 r, + bytes32 s + ) internal view { + require( + SignatureCheckerUpgradeable.isValidSignatureNow( + _signer, + _hashTypedDataV4(paramsHash), + abi.encodePacked(r, s, v) + ), + "Adapter: invalid signature" + ); + } + + /** + * @dev Only WETH contract is allowed to transfer ETH here. Prevent other addresses to send Ether to this contract. + */ + receive() external payable { + require(msg.sender == address(WETH), "Adapter: receive not allowed"); + } +} diff --git a/contracts/adapters/BendExchangeAdapter.sol b/contracts/adapters/BendExchangeAdapter.sol index 1e673a9..4b5a7f3 100644 --- a/contracts/adapters/BendExchangeAdapter.sol +++ b/contracts/adapters/BendExchangeAdapter.sol @@ -4,9 +4,10 @@ pragma solidity 0.8.9; import {IBendExchange} from "../interfaces/IBendExchange.sol"; import {IAuthorizationManager} from "../interfaces/IAuthorizationManager.sol"; -import {BaseAdapter} from "./BaseAdapter.sol"; +import {BaseAdapterV2, IERC20Upgradeable, SafeERC20Upgradeable} from "./BaseAdapterV2.sol"; -contract BendExchangeAdapter is BaseAdapter { +contract BendExchangeAdapter is BaseAdapterV2 { + using SafeERC20Upgradeable for IERC20Upgradeable; string public constant NAME = "Bend Exchange Downpayment Adapter"; string public constant VERSION = "1.0"; @@ -33,15 +34,13 @@ contract BendExchangeAdapter is BaseAdapter { // Check order params require(_orderParams.isOrderAsk, "Adapter: maker must ask order"); - require( - _orderParams.currency == address(WETH) || _orderParams.currency == address(0), - "Adapter: currency must be ETH or WETH" - ); return BaseParams({ nftAsset: _orderParams.collection, nftTokenId: _orderParams.tokenId, - currency: _orderParams.currency, + currency: _orderParams.currency == address(0) + ? IERC20Upgradeable(address(WETH)) + : IERC20Upgradeable(_orderParams.currency), salePrice: _orderParams.price, paramsHash: _hashParams(_orderParams, _nonce) }); @@ -93,9 +92,15 @@ contract BendExchangeAdapter is BaseAdapter { takerBid.interceptorExtra = new bytes(0); } - WETH.approve(proxy, _baseParams.salePrice); - bendExchange.matchAskWithTakerBidUsingETHAndWETH(takerBid, makerAsk); - WETH.approve(proxy, 0); + if (makerAsk.currency == address(0)) { + WETH.approve(proxy, _baseParams.salePrice); + bendExchange.matchAskWithTakerBidUsingETHAndWETH(takerBid, makerAsk); + WETH.approve(proxy, 0); + } else { + _baseParams.currency.safeIncreaseAllowance(proxy, _baseParams.salePrice); + bendExchange.matchAskWithTakerBid(takerBid, makerAsk); + _baseParams.currency.safeApprove(proxy, 0); + } } function _decodeParams(bytes memory _params) internal pure returns (IBendExchange.MakerOrder memory) { diff --git a/contracts/interfaces/IBendExchange.sol b/contracts/interfaces/IBendExchange.sol index 44c38a7..3d41ca6 100644 --- a/contracts/interfaces/IBendExchange.sol +++ b/contracts/interfaces/IBendExchange.sol @@ -38,5 +38,7 @@ interface IBendExchange { external payable; + function matchAskWithTakerBid(TakerOrder calldata takerBid, MakerOrder calldata makerAsk) external; + function authorizationManager() external view returns (address); } diff --git a/contracts/interfaces/IDownpayment.sol b/contracts/interfaces/IDownpayment.sol index 879a177..88a26b1 100644 --- a/contracts/interfaces/IDownpayment.sol +++ b/contracts/interfaces/IDownpayment.sol @@ -37,6 +37,14 @@ interface IDownpayment { Sig calldata sig ) external payable; + function buyWithERC20( + address adapter, + address currency, + uint256 borrowAmount, + bytes calldata data, + Sig calldata sig + ) external; + function addAdapter(address adapter) external; function removeAdapter(address adapter) external; diff --git a/contracts/test/MintableERC20.sol b/contracts/test/MintableERC20.sol new file mode 100644 index 0000000..93be085 --- /dev/null +++ b/contracts/test/MintableERC20.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.8.9; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +/** + * @title ERC20Mintable + * @dev ERC20 minting logic + */ +contract MintableERC20 is ERC20, Ownable { + uint8 private _decimals; + mapping(address => uint256) public mintValues; + address public faucet; + + constructor( + string memory name, + string memory symbol, + uint8 decimals_ + ) ERC20(name, symbol) { + _setupDecimals(decimals_); + } + + function _setupDecimals(uint8 decimals_) internal { + _decimals = decimals_; + } + + function decimals() public view virtual override returns (uint8) { + return _decimals; + } + + /** + * @dev Function to mint tokens + * @param value The amount of tokens to mint. + * @return A boolean that indicates if the operation was successful. + */ + function mint(uint256 value) public returns (bool) { + if (faucet == address(0)) { + require( + (mintValues[_msgSender()] + value) <= (1000000 * (10**_decimals)), + "MintableERC20: exceed mint limit" + ); + } else { + require(faucet == _msgSender(), "MintableERC20: minting not allowed"); + } + + mintValues[_msgSender()] += value; + + _mint(_msgSender(), value); + return true; + } + + function setFaucet(address faucet_) public onlyOwner { + faucet = faucet_; + } +} diff --git a/contracts/test/MockAaveLendPool.sol b/contracts/test/MockAaveLendPool.sol index 311ef50..1cc4681 100644 --- a/contracts/test/MockAaveLendPool.sol +++ b/contracts/test/MockAaveLendPool.sol @@ -3,6 +3,7 @@ pragma solidity 0.8.9; import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {IAaveFlashLoanReceiver} from "../interfaces/IAaveFlashLoanReceiver.sol"; +import "hardhat/console.sol"; contract MockAaveLendPool { using SafeERC20 for IERC20; diff --git a/deployments/deployed-contracts-goerli.json b/deployments/deployed-contracts-goerli.json index 5c3e2c9..60cec8d 100644 --- a/deployments/deployed-contracts-goerli.json +++ b/deployments/deployed-contracts-goerli.json @@ -8,7 +8,7 @@ "deployer": "0xcbb8a164d498e0c2312F0DDcF0a6Ee2F5bad983A" }, "BendExchangeAdapter": { - "address": "0xDE5d6CFf93ac2638629275e0b97c3D581f1Cc43f", + "address": "0xE1A8858D1CBb17430Ebdf693cb3E035030c310Ba", "deployer": "0xcbb8a164d498e0c2312F0DDcF0a6Ee2F5bad983A" }, "PunkAdapter": { diff --git a/hardhat.config.ts b/hardhat.config.ts index c3ce596..4cc9f21 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -19,7 +19,7 @@ const MNEMONIC_PATH = "m/44'/60'/0'/0"; const MNEMONIC = process.env.MNEMONIC || ""; const PRIVATE_KEY = process.env.PRIVATE_KEY || ""; const REPORT_GAS = !!process.env.REPORT_GAS; -// const GWEI = 1000 * 1000 * 1000; +const GWEI = 1000 * 1000 * 1000; const tasksPath = path.join(__dirname, "tasks"); fs.readdirSync(tasksPath) @@ -41,7 +41,7 @@ const config: HardhatUserConfig = { initialBaseFeePerGas: 0, forking: { url: NETWORKS_RPC_URL[Network.goerli], - blockNumber: 8969035, + blockNumber: 9487196, }, }, goerli: { diff --git a/tasks/deploy.ts b/tasks/deploy.ts index 967f960..4452def 100644 --- a/tasks/deploy.ts +++ b/tasks/deploy.ts @@ -10,7 +10,7 @@ import { PunkMarket, Seaport15, WETH, - // X2Y2, + X2Y2, } from "../test/config"; import { IDownpayment } from "../typechain-types"; import { @@ -31,7 +31,7 @@ task("deploy:full", "Deploy all contracts").setAction(async (_, { run }) => { await run("deploy:bendExchangeAdapter"); await run("deploy:punkAdapter"); await run("deploy:seaport15Adapter"); - // await run("deploy:x2y2Adapter"); + await run("deploy:x2y2Adapter"); }); task("deploy:downpayment", "Deploy downpayment").setAction(async (_, { network, run }) => { @@ -47,15 +47,15 @@ task("deploy:downpayment", "Deploy downpayment").setAction(async (_, { network, await deployProxyContract("Downpayment", [aaveAddressesProvider, bendAddressesProvider, feeCollector, weth], true); }); -// task("deploy:x2y2Adapter", "Deploy x2y2Adapter").setAction(async (_, { network, run }) => { -// await run("set-DRE"); -// await run("compile"); -// const networkName = network.name; +task("deploy:x2y2Adapter", "Deploy x2y2Adapter").setAction(async (_, { network, run }) => { + await run("set-DRE"); + await run("compile"); + const networkName = network.name; -// const exchange = getParams(X2Y2, networkName)[0]; -// const downpayment = await getContractFromDB("Downpayment"); -// await deployProxyContract("X2Y2Adapter", [downpayment.address, exchange], true); -// }); + const exchange = getParams(X2Y2, networkName)[0]; + const downpayment = await getContractFromDB("Downpayment"); + await deployProxyContract("X2Y2Adapter", [downpayment.address, exchange], true); +}); task("deploy:seaport15Adapter", "Deploy seaportAdapter").setAction(async (_, { network, run }) => { await run("set-DRE"); @@ -147,13 +147,13 @@ task("config:full", "Config adapters") await run("config:addAdapter", { adapter: "BendExchangeAdapter" }); await run("config:addAdapter", { adapter: "PunkAdapter" }); await run("config:addAdapter", { adapter: "Seaport15Adapter" }); - // await run("config:addAdapter", { adapter: "X2Y2Adapter" }); + await run("config:addAdapter", { adapter: "X2Y2Adapter" }); await run("config:updateFee", { adapter: "LooksRareExchangeAdapter", fee }); await run("config:updateFee", { adapter: "BendExchangeAdapter", fee }); await run("config:updateFee", { adapter: "PunkAdapter", fee }); await run("config:updateFee", { adapter: "Seaport15Adapter", fee }); - // await run("config:updateFee", { adapter: "X2Y2Adapter", fee }); + await run("config:updateFee", { adapter: "X2Y2Adapter", fee }); }); task("prepareUpgrade", "Deploy new implmentation for upgrade") @@ -208,11 +208,9 @@ task("forceImport", "force import implmentation to proxy") task("verify:Implementation", "Verify Implementation") .addParam("proxyid", "The proxy contract id") - .setAction(async ({ proxyid }, { network, upgrades, run }) => { + .setAction(async ({ proxyid }, { upgrades, run }) => { await run("set-DRE"); await run("compile"); - const networkName = network.name; - const proxyAddress = await getContractAddressFromDB(proxyid); const implAddress = await upgrades.erc1967.getImplementationAddress(proxyAddress); console.log("proxyAddress:", proxyAddress, "implAddress:", implAddress); diff --git a/tasks/downpayment.ts b/tasks/downpayment.ts index 85564b9..98eac58 100644 --- a/tasks/downpayment.ts +++ b/tasks/downpayment.ts @@ -11,6 +11,7 @@ import { ILendPool, ILendPoolAddressesProvider, ISeaport, + IWETH, } from "../typechain-types"; import { getContractFromDB, getContractAddressFromDB, getChainId, getContract, waitForTx } from "./utils/helpers"; import * as bend from "../test/signer/bend"; @@ -39,7 +40,7 @@ task("repay", "repay loan") const bendLendPool = await getContract("ILendPool", await bendAddressesProvider.getLendPool()); const weth = getParams(WETH, network.name); const signer = new ethers.Wallet(await findPrivateKey(sender), ethers.provider); - const wethContract = await getContract("IWETH", weth); + const wethContract = await getContract("IWETH", weth); const allowance = await wethContract.allowance(sender, bendLendPool.address); if (allowance.lt(constants.MaxUint256)) { console.log("approve weth"); @@ -147,7 +148,8 @@ task("downpayment:bendExchange", "downpayment with bend exchange") .addParam("nft", "address of nft") .addParam("tokenid", "token id of nft") .addParam("price", "sell price of nft") - .setAction(async ({ maker, taker, nft, tokenid, price }, { ethers, network, run }) => { + .addParam("nonce", "nonce of order") + .setAction(async ({ maker, taker, nft, tokenid, price, nonce }, { ethers, network, run }) => { await run("set-DRE"); const chainId = await getChainId(); console.log(`chainId: ${chainId}`); @@ -155,6 +157,7 @@ task("downpayment:bendExchange", "downpayment with bend exchange") console.log(`taker: ${taker}`); console.log(`nft: ${nft}`); console.log(`tokenid: ${tokenid}`); + console.log(`nonce: ${nonce}`); const config = getParams(BendExchange, network.name); const bendExchange = await getContract("IBendExchange", config[0]); @@ -162,7 +165,6 @@ task("downpayment:bendExchange", "downpayment with bend exchange") const bendExchangeAdapter = await getContractAddressFromDB("BendExchangeAdapter"); const downpayment = await getContractFromDB("Downpayment"); - const nonce = await downpayment.nonces(taker); const makerSigner = new ethers.Wallet(await findPrivateKey(maker), ethers.provider); const takerSigner = new ethers.Wallet(await findPrivateKey(taker), ethers.provider); @@ -229,7 +231,7 @@ task("downpayment:bendExchange", "downpayment with bend exchange") amount: constants.One, strategy, currency: constants.AddressZero, - nonce: constants.Zero, + nonce, startTime: startTimeOrder, endTime: endTimeOrder, minPercentageToAsk: constants.Zero, @@ -239,7 +241,7 @@ task("downpayment:bendExchange", "downpayment with bend exchange") verifyingContract: bendExchange.address, }, bendExchangeAdapter, - nonce + await downpayment.nonces(taker) ); waitForTx( await downpayment diff --git a/test/_setup.ts b/test/_setup.ts index 137b47d..53f1495 100644 --- a/test/_setup.ts +++ b/test/_setup.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { ethers, network } from "hardhat"; -import { parseEther } from "ethers/lib/utils"; +import { parseEther, parseUnits } from "ethers/lib/utils"; import { Downpayment, PunkAdapter, @@ -28,6 +28,7 @@ import { ISeaport, X2Y2Adapter, IX2Y2, + MintableERC20, } from "../typechain-types"; import { getParams, @@ -39,6 +40,7 @@ import { LooksRareExchange, Seaport15, X2Y2, + USDT, } from "./config"; import { waitForTx } from "../tasks/utils/helpers"; import { constants, Contract } from "ethers"; @@ -58,6 +60,10 @@ export interface Contracts { bWETH: IBToken; debtWETH: IDebtToken; + // mock erc20 + usdt: MintableERC20; + debtUSDT: IDebtToken; + // nft bayc: MintableERC721; bBAYC: IERC721; @@ -105,12 +111,16 @@ export async function setupEnv(env: Env, contracts: Contracts): Promise { for (const user of users) { // Each user gets 30 WETH waitForTx(await contracts.weth.connect(user).deposit({ value: parseEther("100") })); + waitForTx(await contracts.usdt.connect(user).mint(parseUnits("100", 6))); } // init aave lend pool waitForTx(await contracts.weth.connect(env.admin).deposit({ value: parseEther("1000") })); waitForTx(await contracts.weth.connect(env.admin).transfer(contracts.aaveLendPool.address, parseEther("800"))); + waitForTx(await contracts.usdt.connect(env.admin).mint(parseUnits("1000", 6))); + waitForTx(await contracts.usdt.connect(env.admin).transfer(contracts.aaveLendPool.address, parseUnits("800", 6))); + // add adapter and fees waitForTx(await contracts.downpayment.addAdapter(contracts.punkAdapter.address)); waitForTx(await contracts.downpayment.addAdapter(contracts.bendExchangeAdapter.address)); @@ -127,11 +137,17 @@ export async function setupEnv(env: Env, contracts: Contracts): Promise { // add reserve balance for bend waitForTx(await contracts.weth.connect(env.admin).approve(contracts.bendLendPool.address, constants.MaxUint256)); + waitForTx(await contracts.usdt.connect(env.admin).approve(contracts.bendLendPool.address, constants.MaxUint256)); waitForTx( await contracts.bendLendPool .connect(env.admin) .deposit(contracts.weth.address, parseEther("200"), env.admin.address, 0) ); + waitForTx( + await contracts.bendLendPool + .connect(env.admin) + .deposit(contracts.usdt.address, parseUnits("200", 6), env.admin.address, 0) + ); } export async function setupContracts(): Promise { @@ -149,6 +165,8 @@ export async function setupContracts(): Promise { const weth = await ethers.getContractAt("IWETH", getParams(WETH, networkName)); const debtWETH = await ethers.getContractAt("IDebtToken", bendProtocolParams[2]); const bWETH = await ethers.getContractAt("IBToken", bendProtocolParams[3]); + const usdt = await ethers.getContractAt("MintableERC20", getParams(USDT, networkName)); + const debtUSDT = await ethers.getContractAt("IDebtToken", bendProtocolParams[7]); // nft const bayc = await ethers.getContractAt("MintableERC721", getParams(BAYC, networkName)); @@ -223,6 +241,8 @@ export async function setupContracts(): Promise { weth, bWETH, debtWETH, + usdt, + debtUSDT, bayc, bBAYC, bWPUNK, diff --git a/test/adapters/BendExchangeAdapter.ts b/test/adapters/BendExchangeAdapter.ts index 2c06441..009c819 100644 --- a/test/adapters/BendExchangeAdapter.ts +++ b/test/adapters/BendExchangeAdapter.ts @@ -2,16 +2,16 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { expect } from "chai"; -import { BigNumber, constants, utils } from "ethers"; +import { BigNumber, Contract, constants, utils } from "ethers"; import { Contracts, Env, makeSuite, Snapshots } from "../_setup"; import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { waitForTx } from "../../tasks/utils/helpers"; -import { assertAlmostEqualTol } from "../helpers/equals"; import { BendExchange, getParams } from "../config"; import { ethers, network } from "hardhat"; -import { BendExchangeAdapter, IAuthorizationManager, IERC721, MintableERC721 } from "../../typechain-types"; +import { BendExchangeAdapter, IAuthorizationManager, IERC20, IERC721, MintableERC721 } from "../../typechain-types"; import { createSignedFlashloanParams, createSignedMakerOrder, createTakerOrder } from "../signer/bend"; +import { parseUnits } from "ethers/lib/utils"; const { parseEther, defaultAbiCoder } = utils; const emptyEncodedBytes = defaultAbiCoder.encode([], []); @@ -21,7 +21,6 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna let tokenId: BigNumber; let nft: MintableERC721; let bnft: IERC721; - let borrowAmount: BigNumber; let nonce: BigNumber; let adapter: BendExchangeAdapter; let authorizationManager: IAuthorizationManager; @@ -58,9 +57,8 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna waitForTx(await nft.connect(seller).setApprovalForAll(sellerProxy, true)); waitForTx(await contracts.weth.connect(buyer).approve(buyerProxy, constants.MaxUint256)); + waitForTx(await contracts.usdt.connect(buyer).approve(buyerProxy, constants.MaxUint256)); - const nftCollateralData = await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.weth.address); - borrowAmount = nftCollateralData.availableBorrowsInReserve.sub(1); await snapshots.capture("init"); }); @@ -68,16 +66,21 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna await snapshots.revert("init"); }); + const getContract = async ( + contractName: string, + address: string + ): Promise => (await ethers.getContractAt(contractName, address)) as ContractType; + async function exceptDownpaymentSuccessed(price: BigNumber, currency: string, borrowAmount: BigNumber) { const aaveFee = borrowAmount.mul(9).div(10000); const bendFee = price.mul(env.fee).div(10000); const paymentAmount = price.add(aaveFee).add(bendFee).sub(borrowAmount); - const expectAaveWethBalance = (await contracts.weth.balanceOf(contracts.aaveLendPool.address)).add(aaveFee); + const currencyERC20 = + currency === constants.AddressZero ? contracts.weth : await getContract("IERC20", currency); + const expectAaveBalance = (await currencyERC20.balanceOf(contracts.aaveLendPool.address)).add(aaveFee); - const expectBendCollectorWethBalance = (await contracts.weth.balanceOf(contracts.bendCollector.address)).add( - bendFee - ); - const expectBuyerWethBalance = (await contracts.weth.balanceOf(buyer.address)).sub(paymentAmount); + const expectBendCollectorBalance = (await currencyERC20.balanceOf(contracts.bendCollector.address)).add(bendFee); + const expectBuyerBalance = (await currencyERC20.balanceOf(buyer.address)).sub(paymentAmount); const dataWithSig = await createSignedFlashloanParams( buyer.address, @@ -104,20 +107,24 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna adapter.address, nonce ); - waitForTx( - await contracts.downpayment.connect(buyer).buy(adapter.address, borrowAmount, dataWithSig.data, dataWithSig.sig) - ); + if (currency === contracts.weth.address || currency === constants.AddressZero) { + waitForTx( + await contracts.downpayment.connect(buyer).buy(adapter.address, borrowAmount, dataWithSig.data, dataWithSig.sig) + ); + } else { + waitForTx( + await contracts.downpayment + .connect(buyer) + .buyWithERC20(adapter.address, currency, borrowAmount, dataWithSig.data, dataWithSig.sig) + ); + } expect(await nft.ownerOf(tokenId)).to.be.equal(bnft.address); expect(await bnft.ownerOf(tokenId)).to.be.equal(buyer.address); - expect(expectAaveWethBalance).to.be.equal(await contracts.weth.balanceOf(contracts.aaveLendPool.address)); - assertAlmostEqualTol( - expectBendCollectorWethBalance, - await contracts.weth.balanceOf(contracts.bendCollector.address), - 0.01 - ); - expect(expectBuyerWethBalance).to.be.equal(await contracts.weth.balanceOf(buyer.address)); + expect(expectAaveBalance).closeTo(await currencyERC20.balanceOf(contracts.aaveLendPool.address), 2); + expect(expectBendCollectorBalance).closeTo(await currencyERC20.balanceOf(contracts.bendCollector.address), 2); + expect(expectBuyerBalance).closeTo(await currencyERC20.balanceOf(buyer.address), 2); } async function approveBuyerWeth() { @@ -128,6 +135,15 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna waitForTx(await contracts.debtWETH.connect(buyer).approveDelegation(adapter.address, constants.MaxUint256)); } + async function approveBuyerUsdt() { + waitForTx(await contracts.usdt.connect(buyer).approve(adapter.address, 0)); + waitForTx(await contracts.usdt.connect(buyer).approve(adapter.address, constants.MaxUint256)); + } + + async function approveBuyerDebtUsdt() { + waitForTx(await contracts.debtUSDT.connect(buyer).approveDelegation(adapter.address, constants.MaxUint256)); + } + it("BendExchange match order", async () => { const price = parseEther("10"); const makerAskOrder = await createSignedMakerOrder({ @@ -197,12 +213,18 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna adapter.address, nonce ); + const borrowAmount = ( + await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.weth.address) + ).availableBorrowsInReserve.sub(1); await expect( contracts.downpayment.connect(buyer).buy(adapter.address, borrowAmount, dataWithSig.data, dataWithSig.sig) ).to.revertedWith("Adapter: maker must ask order"); }); - it("Currency must be ETH or WETH", async () => { - const price = parseEther("10"); + + it("Should approve WETH and debtWETH", async () => { + const borrowAmount = (await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.weth.address)) + .availableBorrowsInReserve; + const price = borrowAmount.add(parseEther("10")); const dataWithSig = await createSignedFlashloanParams( buyer.address, { @@ -215,7 +237,7 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna tokenId, amount: constants.One, strategy, - currency: "0x0000000000000000000000000000000000000001", + currency: constants.AddressZero, nonce: sellerNonce, startTime: startTimeOrder, endTime: endTimeOrder, @@ -228,13 +250,39 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna adapter.address, nonce ); + + await approveBuyerWeth(); + + // no debt weth approvement await expect( contracts.downpayment.connect(buyer).buy(adapter.address, borrowAmount, dataWithSig.data, dataWithSig.sig) - ).to.revertedWith("Adapter: currency must be ETH or WETH"); + ).to.revertedWith("503"); + await approveBuyerDebtWeth(); + await exceptDownpaymentSuccessed(price, constants.AddressZero, borrowAmount); }); - it("Should approve WETH and debtWETH", async () => { - const price = parseEther("10"); + it("Sell order with ETH", async () => { + await approveBuyerWeth(); + await approveBuyerDebtWeth(); + const borrowAmount = (await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.weth.address)) + .availableBorrowsInReserve; + const price = borrowAmount.add(parseEther("10")); + await exceptDownpaymentSuccessed(price, constants.AddressZero, borrowAmount); + }); + + it("Sell order with WETH", async () => { + await approveBuyerWeth(); + await approveBuyerDebtWeth(); + const borrowAmount = (await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.weth.address)) + .availableBorrowsInReserve; + const price = borrowAmount.add(parseEther("10")); + await exceptDownpaymentSuccessed(price, contracts.weth.address, borrowAmount); + }); + + it("Should approve usdt and debtUSDT", async () => { + const borrowAmount = (await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.usdt.address)) + .availableBorrowsInReserve; + const price = borrowAmount.add(parseUnits("10", 6)); const dataWithSig = await createSignedFlashloanParams( buyer.address, { @@ -247,7 +295,7 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna tokenId, amount: constants.One, strategy, - currency: constants.AddressZero, + currency: contracts.usdt.address, nonce: sellerNonce, startTime: startTimeOrder, endTime: endTimeOrder, @@ -261,19 +309,24 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna nonce ); - await approveBuyerWeth(); + await approveBuyerUsdt(); // no debt weth approvement + await expect( - contracts.downpayment.connect(buyer).buy(adapter.address, borrowAmount, dataWithSig.data, dataWithSig.sig) + contracts.downpayment + .connect(buyer) + .buyWithERC20(adapter.address, contracts.usdt.address, borrowAmount, dataWithSig.data, dataWithSig.sig) ).to.revertedWith("503"); - await approveBuyerDebtWeth(); - await exceptDownpaymentSuccessed(price, constants.AddressZero, borrowAmount); + await approveBuyerDebtUsdt(); + await exceptDownpaymentSuccessed(price, contracts.usdt.address, borrowAmount); }); it("Sell order with WETH", async () => { - await approveBuyerWeth(); - await approveBuyerDebtWeth(); - const price = parseEther("10"); - await exceptDownpaymentSuccessed(price, contracts.weth.address, borrowAmount); + await approveBuyerUsdt(); + await approveBuyerDebtUsdt(); + const borrowAmount = (await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.usdt.address)) + .availableBorrowsInReserve; + const price = borrowAmount.add(parseUnits("10", 6)); + await exceptDownpaymentSuccessed(price, contracts.usdt.address, borrowAmount); }); }); diff --git a/test/config.ts b/test/config.ts index 9ecca6c..11a7b0c 100644 --- a/test/config.ts +++ b/test/config.ts @@ -47,6 +47,11 @@ export const WETH: Params = { [Network.mainnet]: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", }; +export const USDT: Params = { + [Network.goerli]: "0x8096Fd3B381164af8421F25c84063B8afC637fE5", + [Network.mainnet]: "0xdac17f958d2ee523a2206206994597c13d831ec7", +}; + export const PunkMarket: Params = { [Network.goerli]: [ "0xBccC7a1E79215EC3FD36824615801BCeE0Df2eC3", // PunkMarket @@ -94,6 +99,7 @@ export const BendProtocol: Params = { "0x83f90CF9c281636a0128614EA043b5d8Ccd380fa", // bWPUNK "0x529710d1e2ab61bDea707039bB841583A983b228", // bBAYC "0xE7E268cC1D025906fe8f6b076ecc40FF1a8dfA61", // NFTOracle + "0xdCc531F4543aB083a2948E23c732F31d5153677D", // debtUSDT ], [Network.mainnet]: [ "0x24451f47caf13b24f4b5034e1df6c0e401ec0e46", // addresses provider @@ -103,6 +109,7 @@ export const BendProtocol: Params = { "0x6c415673C79b31aCA38669AD9fb5cdb7012C0e8e", // bWPUNK "0xDBfD76AF2157Dc15eE4e57F3f942bB45Ba84aF24", // bBAYC "0x7C2A19e54e48718f6C60908a9Cff3396E4Ea1eBA", // NFTOracle + "0x02716c55f49a9107467507b82f9889480949afe4", // debtUSDT ], }; From 267a1c1bc8f480deb379fe3964027819d5c6fa4d Mon Sep 17 00:00:00 2001 From: Thor Seldon Date: Tue, 12 Mar 2024 14:24:05 +0800 Subject: [PATCH 2/2] chore: Deploy bend exchange adapter v2 --- .openzeppelin/mainnet.json | 204 +++++++++++ abis/BendExchangeAdapterV2.json | 365 +++++++++++++++++++ contracts/adapters/BendExchangeAdapter.sol | 25 +- contracts/adapters/BendExchangeAdapterV2.sol | 109 ++++++ deployments/deployed-contracts-mainnet.json | 4 + tasks/deploy.ts | 10 + test/_setup.ts | 8 + test/adapters/BendExchangeAdapter.ts | 125 ++----- test/adapters/BendExchangeAdapterV2.ts | 332 +++++++++++++++++ test/downpayment.ts | 8 +- 10 files changed, 1082 insertions(+), 108 deletions(-) create mode 100644 abis/BendExchangeAdapterV2.json create mode 100644 contracts/adapters/BendExchangeAdapterV2.sol create mode 100644 test/adapters/BendExchangeAdapterV2.ts diff --git a/.openzeppelin/mainnet.json b/.openzeppelin/mainnet.json index 2ef4c98..b5c3aae 100644 --- a/.openzeppelin/mainnet.json +++ b/.openzeppelin/mainnet.json @@ -54,6 +54,11 @@ "address": "0x8B5ABF01b87f87Fb8e0FfC60D32ed7DD29b1f06b", "txHash": "0xd1c4158335909058df3af4c560da91f9578deeb38b4f00067bb8b8c8bf163150", "kind": "transparent" + }, + { + "address": "0xb1d69bf6B4d21e0bE7007472722e5B2808d81D68", + "txHash": "0xa46805d37aadbe7af9e40f0c85fdcc9a6096ce668770cfdd497a35b0d93c2670", + "kind": "transparent" } ], "impls": { @@ -4205,6 +4210,205 @@ } } } + }, + "ad4e94de073643a10cfc3201a52d574224f52f7ec5c8634faea9f34d03b95995": { + "address": "0xa7Ab84d7EeB96FfC03b64038795994b53A82aEf6", + "txHash": "0x1df44c67cce5e4b97a571fa3e4befd2a8a3e68372a38a4a02d2546822ea6a04f", + "layout": { + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "label": "_owner", + "offset": 0, + "slot": "51", + "type": "t_address", + "contract": "OwnableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22" + }, + { + "label": "__gap", + "offset": 0, + "slot": "52", + "type": "t_array(t_uint256)49_storage", + "contract": "OwnableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:87" + }, + { + "label": "_paused", + "offset": 0, + "slot": "101", + "type": "t_bool", + "contract": "PausableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)49_storage", + "contract": "PausableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:102" + }, + { + "label": "_status", + "offset": 0, + "slot": "151", + "type": "t_uint256", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "152", + "type": "t_array(t_uint256)49_storage", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:74" + }, + { + "label": "_HASHED_NAME", + "offset": 0, + "slot": "201", + "type": "t_bytes32", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol:32" + }, + { + "label": "_HASHED_VERSION", + "offset": 0, + "slot": "202", + "type": "t_bytes32", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol:33" + }, + { + "label": "__gap", + "offset": 0, + "slot": "203", + "type": "t_array(t_uint256)50_storage", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol:120" + }, + { + "label": "__gap", + "offset": 0, + "slot": "253", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC721HolderUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol:40" + }, + { + "label": "downpayment", + "offset": 0, + "slot": "303", + "type": "t_contract(IDownpayment)10552", + "contract": "BaseAdapterV2", + "src": "contracts/adapters/BaseAdapterV2.sol:41" + }, + { + "label": "WETH", + "offset": 0, + "slot": "304", + "type": "t_contract(IWETH)10895", + "contract": "BaseAdapterV2", + "src": "contracts/adapters/BaseAdapterV2.sol:42" + }, + { + "label": "__gap", + "offset": 0, + "slot": "305", + "type": "t_array(t_uint256)43_storage", + "contract": "BaseAdapterV2", + "src": "contracts/adapters/BaseAdapterV2.sol:43" + }, + { + "label": "bendExchange", + "offset": 0, + "slot": "348", + "type": "t_contract(IBendExchange)10355", + "contract": "BendExchangeAdapterV2", + "src": "contracts/adapters/BendExchangeAdapterV2.sol:17" + }, + { + "label": "proxy", + "offset": 0, + "slot": "349", + "type": "t_address", + "contract": "BendExchangeAdapterV2", + "src": "contracts/adapters/BendExchangeAdapterV2.sol:18" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)43_storage": { + "label": "uint256[43]", + "numberOfBytes": "1376" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_contract(IBendExchange)10355": { + "label": "contract IBendExchange", + "numberOfBytes": "20" + }, + "t_contract(IDownpayment)10552": { + "label": "contract IDownpayment", + "numberOfBytes": "20" + }, + "t_contract(IWETH)10895": { + "label": "contract IWETH", + "numberOfBytes": "20" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } } } } diff --git a/abis/BendExchangeAdapterV2.json b/abis/BendExchangeAdapterV2.json new file mode 100644 index 0000000..dd10ae6 --- /dev/null +++ b/abis/BendExchangeAdapterV2.json @@ -0,0 +1,365 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "buyer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "nftToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nftTokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "borrowedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "flashLoanFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "downpaymentFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "Purchased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "contract IWETH", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bendExchange", + "outputs": [ + { + "internalType": "contract IBendExchange", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "downpayment", + "outputs": [ + { + "internalType": "contract IDownpayment", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_amounts", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_premiums", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "_initiator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_params", + "type": "bytes" + } + ], + "name": "executeOperation", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_downpayment", + "type": "address" + }, + { + "internalType": "address", + "name": "_bendExchange", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "registrar", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + } + ], + "name": "setENSName", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/contracts/adapters/BendExchangeAdapter.sol b/contracts/adapters/BendExchangeAdapter.sol index 4b5a7f3..1e673a9 100644 --- a/contracts/adapters/BendExchangeAdapter.sol +++ b/contracts/adapters/BendExchangeAdapter.sol @@ -4,10 +4,9 @@ pragma solidity 0.8.9; import {IBendExchange} from "../interfaces/IBendExchange.sol"; import {IAuthorizationManager} from "../interfaces/IAuthorizationManager.sol"; -import {BaseAdapterV2, IERC20Upgradeable, SafeERC20Upgradeable} from "./BaseAdapterV2.sol"; +import {BaseAdapter} from "./BaseAdapter.sol"; -contract BendExchangeAdapter is BaseAdapterV2 { - using SafeERC20Upgradeable for IERC20Upgradeable; +contract BendExchangeAdapter is BaseAdapter { string public constant NAME = "Bend Exchange Downpayment Adapter"; string public constant VERSION = "1.0"; @@ -34,13 +33,15 @@ contract BendExchangeAdapter is BaseAdapterV2 { // Check order params require(_orderParams.isOrderAsk, "Adapter: maker must ask order"); + require( + _orderParams.currency == address(WETH) || _orderParams.currency == address(0), + "Adapter: currency must be ETH or WETH" + ); return BaseParams({ nftAsset: _orderParams.collection, nftTokenId: _orderParams.tokenId, - currency: _orderParams.currency == address(0) - ? IERC20Upgradeable(address(WETH)) - : IERC20Upgradeable(_orderParams.currency), + currency: _orderParams.currency, salePrice: _orderParams.price, paramsHash: _hashParams(_orderParams, _nonce) }); @@ -92,15 +93,9 @@ contract BendExchangeAdapter is BaseAdapterV2 { takerBid.interceptorExtra = new bytes(0); } - if (makerAsk.currency == address(0)) { - WETH.approve(proxy, _baseParams.salePrice); - bendExchange.matchAskWithTakerBidUsingETHAndWETH(takerBid, makerAsk); - WETH.approve(proxy, 0); - } else { - _baseParams.currency.safeIncreaseAllowance(proxy, _baseParams.salePrice); - bendExchange.matchAskWithTakerBid(takerBid, makerAsk); - _baseParams.currency.safeApprove(proxy, 0); - } + WETH.approve(proxy, _baseParams.salePrice); + bendExchange.matchAskWithTakerBidUsingETHAndWETH(takerBid, makerAsk); + WETH.approve(proxy, 0); } function _decodeParams(bytes memory _params) internal pure returns (IBendExchange.MakerOrder memory) { diff --git a/contracts/adapters/BendExchangeAdapterV2.sol b/contracts/adapters/BendExchangeAdapterV2.sol new file mode 100644 index 0000000..df56fa4 --- /dev/null +++ b/contracts/adapters/BendExchangeAdapterV2.sol @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.8.9; + +import {IBendExchange} from "../interfaces/IBendExchange.sol"; +import {IAuthorizationManager} from "../interfaces/IAuthorizationManager.sol"; + +import {BaseAdapterV2, IERC20Upgradeable, SafeERC20Upgradeable} from "./BaseAdapterV2.sol"; + +contract BendExchangeAdapterV2 is BaseAdapterV2 { + using SafeERC20Upgradeable for IERC20Upgradeable; + string public constant NAME = "Bend Exchange Downpayment Adapter"; + string public constant VERSION = "1.0"; + + //keccak256("Params(bool isOrderAsk,address maker,address collection,uint256 price,uint256 tokenId,uint256 amount,address strategy,address currency,uint256 nonce,uint256 startTime,uint256 endTime,uint256 minPercentageToAsk,bytes params,address interceptor,bytes interceptorExtra,uint8 v,bytes32 r,bytes32 s,uint256 nonce2)"); + bytes32 private constant _PARAMS_TYPEHASH = 0x6482968240152d913828da2846e216aa4e202dd2e56802d8dfd4767d64867463; + + IBendExchange public bendExchange; + address private proxy; + + function initialize(address _downpayment, address _bendExchange) external initializer { + __BaseAdapter_init(NAME, VERSION, _downpayment); + bendExchange = IBendExchange(_bendExchange); + proxy = IAuthorizationManager(bendExchange.authorizationManager()).registerProxy(); + } + + function _checkParams( + address, + uint256, + uint256, + bytes memory _params, + uint256 _nonce + ) internal view override returns (BaseParams memory) { + IBendExchange.MakerOrder memory _orderParams = _decodeParams(_params); + + // Check order params + require(_orderParams.isOrderAsk, "Adapter: maker must ask order"); + return + BaseParams({ + nftAsset: _orderParams.collection, + nftTokenId: _orderParams.tokenId, + currency: _orderParams.currency == address(0) + ? IERC20Upgradeable(address(WETH)) + : IERC20Upgradeable(_orderParams.currency), + salePrice: _orderParams.price, + paramsHash: _hashParams(_orderParams, _nonce) + }); + } + + function _hashParams(IBendExchange.MakerOrder memory _orderParams, uint256 _nonce) internal pure returns (bytes32) { + return + keccak256( + bytes.concat( + abi.encode( + _PARAMS_TYPEHASH, + _orderParams.isOrderAsk, + _orderParams.maker, + _orderParams.collection, + _orderParams.price, + _orderParams.tokenId, + _orderParams.amount, + _orderParams.strategy, + _orderParams.currency, + _orderParams.nonce, + _orderParams.startTime, + _orderParams.endTime, + _orderParams.minPercentageToAsk + ), + abi.encode( + keccak256(_orderParams.params), + _orderParams.interceptor, + keccak256(_orderParams.interceptorExtra), + _orderParams.v, + _orderParams.r, + _orderParams.s, + _nonce + ) + ) + ); + } + + function _exchange(BaseParams memory _baseParams, bytes memory _params) internal override { + IBendExchange.MakerOrder memory makerAsk = _decodeParams(_params); + IBendExchange.TakerOrder memory takerBid; + { + takerBid.isOrderAsk = false; + takerBid.taker = address(this); + takerBid.price = makerAsk.price; + takerBid.tokenId = makerAsk.tokenId; + takerBid.minPercentageToAsk = 0; + takerBid.params = new bytes(0); + takerBid.interceptor = address(0); + takerBid.interceptorExtra = new bytes(0); + } + + if (makerAsk.currency == address(0)) { + WETH.approve(proxy, _baseParams.salePrice); + bendExchange.matchAskWithTakerBidUsingETHAndWETH(takerBid, makerAsk); + WETH.approve(proxy, 0); + } else { + _baseParams.currency.safeIncreaseAllowance(proxy, _baseParams.salePrice); + bendExchange.matchAskWithTakerBid(takerBid, makerAsk); + _baseParams.currency.safeApprove(proxy, 0); + } + } + + function _decodeParams(bytes memory _params) internal pure returns (IBendExchange.MakerOrder memory) { + return abi.decode(_params, (IBendExchange.MakerOrder)); + } +} diff --git a/deployments/deployed-contracts-mainnet.json b/deployments/deployed-contracts-mainnet.json index 378f013..272ad49 100644 --- a/deployments/deployed-contracts-mainnet.json +++ b/deployments/deployed-contracts-mainnet.json @@ -34,5 +34,9 @@ "Seaport15Adapter": { "address": "0x8B5ABF01b87f87Fb8e0FfC60D32ed7DD29b1f06b", "deployer": "0x868964fa49a6fd6e116FE82c8f4165904406f479" + }, + "BendExchangeAdapterV2": { + "address": "0xb1d69bf6B4d21e0bE7007472722e5B2808d81D68", + "deployer": "0x868964fa49a6fd6e116FE82c8f4165904406f479" } } \ No newline at end of file diff --git a/tasks/deploy.ts b/tasks/deploy.ts index 4452def..fae1cfe 100644 --- a/tasks/deploy.ts +++ b/tasks/deploy.ts @@ -93,6 +93,16 @@ task("deploy:bendExchangeAdapter", "Deploy bendExchangeAdapter").setAction(async await deployProxyContract("BendExchangeAdapter", [downpayment.address, bendExchange], true); }); +task("deploy:bendExchangeAdapterV2", "Deploy bendExchangeAdapterV2").setAction(async (_, { network, run }) => { + await run("set-DRE"); + await run("compile"); + const networkName = network.name; + + const bendExchange = getParams(BendExchange, networkName)[0]; + const downpayment = await getContractFromDB("Downpayment"); + await deployProxyContract("BendExchangeAdapterV2", [downpayment.address, bendExchange], true); +}); + task("deploy:punkAdapter", "Deploy punkAdapter").setAction(async (_, { network, run }) => { await run("set-DRE"); await run("compile"); diff --git a/test/_setup.ts b/test/_setup.ts index 53f1495..b024f1b 100644 --- a/test/_setup.ts +++ b/test/_setup.ts @@ -29,6 +29,7 @@ import { X2Y2Adapter, IX2Y2, MintableERC20, + BendExchangeAdapterV2, } from "../typechain-types"; import { getParams, @@ -87,6 +88,7 @@ export interface Contracts { looksRareExchangeAdapter: LooksRareExchangeAdapter; seaportAdapter: SeaportAdapter; x2y2Adapter: X2Y2Adapter; + bendExchangeAdapterV2: BendExchangeAdapterV2; // aave aaveLendPool: IAaveLendPool; @@ -127,6 +129,7 @@ export async function setupEnv(env: Env, contracts: Contracts): Promise { waitForTx(await contracts.downpayment.addAdapter(contracts.looksRareExchangeAdapter.address)); waitForTx(await contracts.downpayment.addAdapter(contracts.seaportAdapter.address)); waitForTx(await contracts.downpayment.addAdapter(contracts.x2y2Adapter.address)); + waitForTx(await contracts.downpayment.addAdapter(contracts.bendExchangeAdapterV2.address)); waitForTx(await contracts.downpayment.updateFee(contracts.punkAdapter.address, 0)); // test zero fee @@ -134,6 +137,7 @@ export async function setupEnv(env: Env, contracts: Contracts): Promise { waitForTx(await contracts.downpayment.updateFee(contracts.looksRareExchangeAdapter.address, env.fee)); waitForTx(await contracts.downpayment.updateFee(contracts.seaportAdapter.address, env.fee)); waitForTx(await contracts.downpayment.updateFee(contracts.x2y2Adapter.address, env.fee)); + waitForTx(await contracts.downpayment.updateFee(contracts.bendExchangeAdapterV2.address, env.fee)); // add reserve balance for bend waitForTx(await contracts.weth.connect(env.admin).approve(contracts.bendLendPool.address, constants.MaxUint256)); @@ -230,6 +234,9 @@ export async function setupContracts(): Promise { const x2y2Adapter = await deployContract("X2Y2Adapter", []); await x2y2Adapter.initialize(downpayment.address, x2y2Exchange.address); + const bendExchangeAdapterV2 = await deployContract("BendExchangeAdapterV2", []); + await bendExchangeAdapterV2.initialize(downpayment.address, bendExchange.address); + /** Return contracts */ return { @@ -255,6 +262,7 @@ export async function setupContracts(): Promise { bendExchangeAdapter, bendExchange, authorizationManager, + bendExchangeAdapterV2, aaveLendPool, bendLendPool, nftOracle, diff --git a/test/adapters/BendExchangeAdapter.ts b/test/adapters/BendExchangeAdapter.ts index 009c819..2c06441 100644 --- a/test/adapters/BendExchangeAdapter.ts +++ b/test/adapters/BendExchangeAdapter.ts @@ -2,16 +2,16 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { expect } from "chai"; -import { BigNumber, Contract, constants, utils } from "ethers"; +import { BigNumber, constants, utils } from "ethers"; import { Contracts, Env, makeSuite, Snapshots } from "../_setup"; import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { waitForTx } from "../../tasks/utils/helpers"; +import { assertAlmostEqualTol } from "../helpers/equals"; import { BendExchange, getParams } from "../config"; import { ethers, network } from "hardhat"; -import { BendExchangeAdapter, IAuthorizationManager, IERC20, IERC721, MintableERC721 } from "../../typechain-types"; +import { BendExchangeAdapter, IAuthorizationManager, IERC721, MintableERC721 } from "../../typechain-types"; import { createSignedFlashloanParams, createSignedMakerOrder, createTakerOrder } from "../signer/bend"; -import { parseUnits } from "ethers/lib/utils"; const { parseEther, defaultAbiCoder } = utils; const emptyEncodedBytes = defaultAbiCoder.encode([], []); @@ -21,6 +21,7 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna let tokenId: BigNumber; let nft: MintableERC721; let bnft: IERC721; + let borrowAmount: BigNumber; let nonce: BigNumber; let adapter: BendExchangeAdapter; let authorizationManager: IAuthorizationManager; @@ -57,8 +58,9 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna waitForTx(await nft.connect(seller).setApprovalForAll(sellerProxy, true)); waitForTx(await contracts.weth.connect(buyer).approve(buyerProxy, constants.MaxUint256)); - waitForTx(await contracts.usdt.connect(buyer).approve(buyerProxy, constants.MaxUint256)); + const nftCollateralData = await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.weth.address); + borrowAmount = nftCollateralData.availableBorrowsInReserve.sub(1); await snapshots.capture("init"); }); @@ -66,21 +68,16 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna await snapshots.revert("init"); }); - const getContract = async ( - contractName: string, - address: string - ): Promise => (await ethers.getContractAt(contractName, address)) as ContractType; - async function exceptDownpaymentSuccessed(price: BigNumber, currency: string, borrowAmount: BigNumber) { const aaveFee = borrowAmount.mul(9).div(10000); const bendFee = price.mul(env.fee).div(10000); const paymentAmount = price.add(aaveFee).add(bendFee).sub(borrowAmount); - const currencyERC20 = - currency === constants.AddressZero ? contracts.weth : await getContract("IERC20", currency); - const expectAaveBalance = (await currencyERC20.balanceOf(contracts.aaveLendPool.address)).add(aaveFee); + const expectAaveWethBalance = (await contracts.weth.balanceOf(contracts.aaveLendPool.address)).add(aaveFee); - const expectBendCollectorBalance = (await currencyERC20.balanceOf(contracts.bendCollector.address)).add(bendFee); - const expectBuyerBalance = (await currencyERC20.balanceOf(buyer.address)).sub(paymentAmount); + const expectBendCollectorWethBalance = (await contracts.weth.balanceOf(contracts.bendCollector.address)).add( + bendFee + ); + const expectBuyerWethBalance = (await contracts.weth.balanceOf(buyer.address)).sub(paymentAmount); const dataWithSig = await createSignedFlashloanParams( buyer.address, @@ -107,24 +104,20 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna adapter.address, nonce ); - if (currency === contracts.weth.address || currency === constants.AddressZero) { - waitForTx( - await contracts.downpayment.connect(buyer).buy(adapter.address, borrowAmount, dataWithSig.data, dataWithSig.sig) - ); - } else { - waitForTx( - await contracts.downpayment - .connect(buyer) - .buyWithERC20(adapter.address, currency, borrowAmount, dataWithSig.data, dataWithSig.sig) - ); - } + waitForTx( + await contracts.downpayment.connect(buyer).buy(adapter.address, borrowAmount, dataWithSig.data, dataWithSig.sig) + ); expect(await nft.ownerOf(tokenId)).to.be.equal(bnft.address); expect(await bnft.ownerOf(tokenId)).to.be.equal(buyer.address); - expect(expectAaveBalance).closeTo(await currencyERC20.balanceOf(contracts.aaveLendPool.address), 2); - expect(expectBendCollectorBalance).closeTo(await currencyERC20.balanceOf(contracts.bendCollector.address), 2); - expect(expectBuyerBalance).closeTo(await currencyERC20.balanceOf(buyer.address), 2); + expect(expectAaveWethBalance).to.be.equal(await contracts.weth.balanceOf(contracts.aaveLendPool.address)); + assertAlmostEqualTol( + expectBendCollectorWethBalance, + await contracts.weth.balanceOf(contracts.bendCollector.address), + 0.01 + ); + expect(expectBuyerWethBalance).to.be.equal(await contracts.weth.balanceOf(buyer.address)); } async function approveBuyerWeth() { @@ -135,15 +128,6 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna waitForTx(await contracts.debtWETH.connect(buyer).approveDelegation(adapter.address, constants.MaxUint256)); } - async function approveBuyerUsdt() { - waitForTx(await contracts.usdt.connect(buyer).approve(adapter.address, 0)); - waitForTx(await contracts.usdt.connect(buyer).approve(adapter.address, constants.MaxUint256)); - } - - async function approveBuyerDebtUsdt() { - waitForTx(await contracts.debtUSDT.connect(buyer).approveDelegation(adapter.address, constants.MaxUint256)); - } - it("BendExchange match order", async () => { const price = parseEther("10"); const makerAskOrder = await createSignedMakerOrder({ @@ -213,18 +197,12 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna adapter.address, nonce ); - const borrowAmount = ( - await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.weth.address) - ).availableBorrowsInReserve.sub(1); await expect( contracts.downpayment.connect(buyer).buy(adapter.address, borrowAmount, dataWithSig.data, dataWithSig.sig) ).to.revertedWith("Adapter: maker must ask order"); }); - - it("Should approve WETH and debtWETH", async () => { - const borrowAmount = (await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.weth.address)) - .availableBorrowsInReserve; - const price = borrowAmount.add(parseEther("10")); + it("Currency must be ETH or WETH", async () => { + const price = parseEther("10"); const dataWithSig = await createSignedFlashloanParams( buyer.address, { @@ -237,7 +215,7 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna tokenId, amount: constants.One, strategy, - currency: constants.AddressZero, + currency: "0x0000000000000000000000000000000000000001", nonce: sellerNonce, startTime: startTimeOrder, endTime: endTimeOrder, @@ -250,39 +228,13 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna adapter.address, nonce ); - - await approveBuyerWeth(); - - // no debt weth approvement await expect( contracts.downpayment.connect(buyer).buy(adapter.address, borrowAmount, dataWithSig.data, dataWithSig.sig) - ).to.revertedWith("503"); - await approveBuyerDebtWeth(); - await exceptDownpaymentSuccessed(price, constants.AddressZero, borrowAmount); + ).to.revertedWith("Adapter: currency must be ETH or WETH"); }); - it("Sell order with ETH", async () => { - await approveBuyerWeth(); - await approveBuyerDebtWeth(); - const borrowAmount = (await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.weth.address)) - .availableBorrowsInReserve; - const price = borrowAmount.add(parseEther("10")); - await exceptDownpaymentSuccessed(price, constants.AddressZero, borrowAmount); - }); - - it("Sell order with WETH", async () => { - await approveBuyerWeth(); - await approveBuyerDebtWeth(); - const borrowAmount = (await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.weth.address)) - .availableBorrowsInReserve; - const price = borrowAmount.add(parseEther("10")); - await exceptDownpaymentSuccessed(price, contracts.weth.address, borrowAmount); - }); - - it("Should approve usdt and debtUSDT", async () => { - const borrowAmount = (await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.usdt.address)) - .availableBorrowsInReserve; - const price = borrowAmount.add(parseUnits("10", 6)); + it("Should approve WETH and debtWETH", async () => { + const price = parseEther("10"); const dataWithSig = await createSignedFlashloanParams( buyer.address, { @@ -295,7 +247,7 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna tokenId, amount: constants.One, strategy, - currency: contracts.usdt.address, + currency: constants.AddressZero, nonce: sellerNonce, startTime: startTimeOrder, endTime: endTimeOrder, @@ -309,24 +261,19 @@ makeSuite("BendExchangeAdapter", (contracts: Contracts, env: Env, snapshots: Sna nonce ); - await approveBuyerUsdt(); + await approveBuyerWeth(); // no debt weth approvement - await expect( - contracts.downpayment - .connect(buyer) - .buyWithERC20(adapter.address, contracts.usdt.address, borrowAmount, dataWithSig.data, dataWithSig.sig) + contracts.downpayment.connect(buyer).buy(adapter.address, borrowAmount, dataWithSig.data, dataWithSig.sig) ).to.revertedWith("503"); - await approveBuyerDebtUsdt(); - await exceptDownpaymentSuccessed(price, contracts.usdt.address, borrowAmount); + await approveBuyerDebtWeth(); + await exceptDownpaymentSuccessed(price, constants.AddressZero, borrowAmount); }); it("Sell order with WETH", async () => { - await approveBuyerUsdt(); - await approveBuyerDebtUsdt(); - const borrowAmount = (await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.usdt.address)) - .availableBorrowsInReserve; - const price = borrowAmount.add(parseUnits("10", 6)); - await exceptDownpaymentSuccessed(price, contracts.usdt.address, borrowAmount); + await approveBuyerWeth(); + await approveBuyerDebtWeth(); + const price = parseEther("10"); + await exceptDownpaymentSuccessed(price, contracts.weth.address, borrowAmount); }); }); diff --git a/test/adapters/BendExchangeAdapterV2.ts b/test/adapters/BendExchangeAdapterV2.ts new file mode 100644 index 0000000..fb9d6c3 --- /dev/null +++ b/test/adapters/BendExchangeAdapterV2.ts @@ -0,0 +1,332 @@ +/* eslint-disable node/no-extraneous-import */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import { expect } from "chai"; +import { BigNumber, Contract, constants, utils } from "ethers"; +import { Contracts, Env, makeSuite, Snapshots } from "../_setup"; +import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; +import { waitForTx } from "../../tasks/utils/helpers"; + +import { BendExchange, getParams } from "../config"; +import { ethers, network } from "hardhat"; +import { BendExchangeAdapter, IAuthorizationManager, IERC20, IERC721, MintableERC721 } from "../../typechain-types"; +import { createSignedFlashloanParams, createSignedMakerOrder, createTakerOrder } from "../signer/bend"; +import { parseUnits } from "ethers/lib/utils"; +const { parseEther, defaultAbiCoder } = utils; +const emptyEncodedBytes = defaultAbiCoder.encode([], []); + +makeSuite("BendExchangeAdapterV2", (contracts: Contracts, env: Env, snapshots: Snapshots) => { + let buyer: SignerWithAddress; + let seller: SignerWithAddress; + let tokenId: BigNumber; + let nft: MintableERC721; + let bnft: IERC721; + let nonce: BigNumber; + let adapter: BendExchangeAdapter; + let authorizationManager: IAuthorizationManager; + let strategy: string; + let startTimeOrder: BigNumber; + let endTimeOrder: BigNumber; + let sellerNonce: BigNumber; + + before(async () => { + startTimeOrder = BigNumber.from((await ethers.provider.getBlock(await ethers.provider.getBlockNumber())).timestamp); + endTimeOrder = startTimeOrder.add(1000); + seller = env.accounts[1]; + buyer = env.accounts[2]; + nft = contracts.bayc; + bnft = contracts.bBAYC; + tokenId = BigNumber.from(7211); + const config = getParams(BendExchange, network.name); + strategy = config[1]; + adapter = contracts.bendExchangeAdapterV2; + authorizationManager = contracts.authorizationManager; + + waitForTx(await nft.connect(seller).mint(tokenId)); + expect(await nft.ownerOf(tokenId)).to.be.eq(seller.address); + + nonce = await contracts.downpayment.nonces(buyer.address); + sellerNonce = BigNumber.from(100); + + waitForTx(await authorizationManager.connect(seller).registerProxy()); + waitForTx(await authorizationManager.connect(buyer).registerProxy()); + + const sellerProxy = await authorizationManager.proxies(seller.address); + const buyerProxy = await authorizationManager.proxies(buyer.address); + + waitForTx(await nft.connect(seller).setApprovalForAll(sellerProxy, true)); + + waitForTx(await contracts.weth.connect(buyer).approve(buyerProxy, constants.MaxUint256)); + waitForTx(await contracts.usdt.connect(buyer).approve(buyerProxy, constants.MaxUint256)); + + await snapshots.capture("init"); + }); + + afterEach(async () => { + await snapshots.revert("init"); + }); + + const getContract = async ( + contractName: string, + address: string + ): Promise => (await ethers.getContractAt(contractName, address)) as ContractType; + + async function exceptDownpaymentSuccessed(price: BigNumber, currency: string, borrowAmount: BigNumber) { + const aaveFee = borrowAmount.mul(9).div(10000); + const bendFee = price.mul(env.fee).div(10000); + const paymentAmount = price.add(aaveFee).add(bendFee).sub(borrowAmount); + const currencyERC20 = + currency === constants.AddressZero ? contracts.weth : await getContract("IERC20", currency); + const expectAaveBalance = (await currencyERC20.balanceOf(contracts.aaveLendPool.address)).add(aaveFee); + + const expectBendCollectorBalance = (await currencyERC20.balanceOf(contracts.bendCollector.address)).add(bendFee); + const expectBuyerBalance = (await currencyERC20.balanceOf(buyer.address)).sub(paymentAmount); + + const dataWithSig = await createSignedFlashloanParams( + buyer.address, + { + isOrderAsk: true, + maker: seller.address, + interceptor: constants.AddressZero, + interceptorExtra: emptyEncodedBytes, + collection: nft.address, + price, + tokenId, + amount: constants.One, + strategy, + currency, + nonce: sellerNonce, + startTime: startTimeOrder, + endTime: endTimeOrder, + minPercentageToAsk: constants.Zero, + params: emptyEncodedBytes, + signerUser: seller.address, + chainId: env.chainId, + verifyingContract: contracts.bendExchange.address, + }, + adapter.address, + nonce + ); + if (currency === contracts.weth.address || currency === constants.AddressZero) { + waitForTx( + await contracts.downpayment.connect(buyer).buy(adapter.address, borrowAmount, dataWithSig.data, dataWithSig.sig) + ); + } else { + waitForTx( + await contracts.downpayment + .connect(buyer) + .buyWithERC20(adapter.address, currency, borrowAmount, dataWithSig.data, dataWithSig.sig) + ); + } + + expect(await nft.ownerOf(tokenId)).to.be.equal(bnft.address); + expect(await bnft.ownerOf(tokenId)).to.be.equal(buyer.address); + + expect(expectAaveBalance).closeTo(await currencyERC20.balanceOf(contracts.aaveLendPool.address), 2); + expect(expectBendCollectorBalance).closeTo(await currencyERC20.balanceOf(contracts.bendCollector.address), 2); + expect(expectBuyerBalance).closeTo(await currencyERC20.balanceOf(buyer.address), 2); + } + + async function approveBuyerWeth() { + waitForTx(await contracts.weth.connect(buyer).approve(adapter.address, constants.MaxUint256)); + } + + async function approveBuyerDebtWeth() { + waitForTx(await contracts.debtWETH.connect(buyer).approveDelegation(adapter.address, constants.MaxUint256)); + } + + async function approveBuyerUsdt() { + waitForTx(await contracts.usdt.connect(buyer).approve(adapter.address, 0)); + waitForTx(await contracts.usdt.connect(buyer).approve(adapter.address, constants.MaxUint256)); + } + + async function approveBuyerDebtUsdt() { + waitForTx(await contracts.debtUSDT.connect(buyer).approveDelegation(adapter.address, constants.MaxUint256)); + } + + it("BendExchange match order", async () => { + const price = parseEther("10"); + const makerAskOrder = await createSignedMakerOrder({ + isOrderAsk: true, + maker: seller.address, + collection: nft.address, + price: price, + tokenId: tokenId, + amount: constants.One, + strategy: strategy, + currency: constants.AddressZero, + nonce: sellerNonce, + startTime: startTimeOrder, + endTime: endTimeOrder, + minPercentageToAsk: constants.Zero, + params: emptyEncodedBytes, + interceptor: constants.AddressZero, + interceptorExtra: emptyEncodedBytes, + signerUser: seller.address, + chainId: env.chainId, + verifyingContract: contracts.bendExchange.address, + }); + const takerBidOrder = createTakerOrder({ + isOrderAsk: false, + taker: buyer.address, + price: price, + tokenId: tokenId, + minPercentageToAsk: constants.Zero, + params: emptyEncodedBytes, + interceptor: constants.AddressZero, + interceptorExtra: emptyEncodedBytes, + }); + waitForTx( + await contracts.bendExchange.connect(buyer).matchAskWithTakerBidUsingETHAndWETH(takerBidOrder, makerAskOrder, { + value: takerBidOrder.price, + }) + ); + + expect(await nft.ownerOf(tokenId)).to.be.equal(buyer.address); + }); + + it("Maker must ask order", async () => { + const price = parseEther("10"); + const dataWithSig = await createSignedFlashloanParams( + buyer.address, + { + isOrderAsk: false, + maker: seller.address, + interceptor: constants.AddressZero, + interceptorExtra: emptyEncodedBytes, + collection: nft.address, + price, + tokenId, + amount: constants.One, + strategy, + currency: constants.AddressZero, + nonce: sellerNonce, + startTime: startTimeOrder, + endTime: endTimeOrder, + minPercentageToAsk: constants.Zero, + params: emptyEncodedBytes, + signerUser: seller.address, + chainId: env.chainId, + verifyingContract: contracts.bendExchange.address, + }, + + adapter.address, + nonce + ); + const borrowAmount = ( + await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.weth.address) + ).availableBorrowsInReserve.sub(1); + await expect( + contracts.downpayment.connect(buyer).buy(adapter.address, borrowAmount, dataWithSig.data, dataWithSig.sig) + ).to.revertedWith("Adapter: maker must ask order"); + }); + + it("Should approve WETH and debtWETH", async () => { + const borrowAmount = (await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.weth.address)) + .availableBorrowsInReserve; + const price = borrowAmount.add(parseEther("10")); + const dataWithSig = await createSignedFlashloanParams( + buyer.address, + { + isOrderAsk: true, + maker: seller.address, + interceptor: constants.AddressZero, + interceptorExtra: emptyEncodedBytes, + collection: nft.address, + price, + tokenId, + amount: constants.One, + strategy, + currency: constants.AddressZero, + nonce: sellerNonce, + startTime: startTimeOrder, + endTime: endTimeOrder, + minPercentageToAsk: constants.Zero, + params: emptyEncodedBytes, + signerUser: seller.address, + chainId: env.chainId, + verifyingContract: contracts.bendExchange.address, + }, + adapter.address, + nonce + ); + + await approveBuyerWeth(); + + // no debt weth approvement + await expect( + contracts.downpayment.connect(buyer).buy(adapter.address, borrowAmount, dataWithSig.data, dataWithSig.sig) + ).to.revertedWith("503"); + await approveBuyerDebtWeth(); + await exceptDownpaymentSuccessed(price, constants.AddressZero, borrowAmount); + }); + + it("Sell order with ETH", async () => { + await approveBuyerWeth(); + await approveBuyerDebtWeth(); + const borrowAmount = (await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.weth.address)) + .availableBorrowsInReserve; + const price = borrowAmount.add(parseEther("10")); + await exceptDownpaymentSuccessed(price, constants.AddressZero, borrowAmount); + }); + + it("Sell order with WETH", async () => { + await approveBuyerWeth(); + await approveBuyerDebtWeth(); + const borrowAmount = (await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.weth.address)) + .availableBorrowsInReserve; + const price = borrowAmount.add(parseEther("10")); + await exceptDownpaymentSuccessed(price, contracts.weth.address, borrowAmount); + }); + + it("Should approve usdt and debtUSDT", async () => { + const borrowAmount = (await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.usdt.address)) + .availableBorrowsInReserve; + const price = borrowAmount.add(parseUnits("10", 6)); + const dataWithSig = await createSignedFlashloanParams( + buyer.address, + { + isOrderAsk: true, + maker: seller.address, + interceptor: constants.AddressZero, + interceptorExtra: emptyEncodedBytes, + collection: nft.address, + price, + tokenId, + amount: constants.One, + strategy, + currency: contracts.usdt.address, + nonce: sellerNonce, + startTime: startTimeOrder, + endTime: endTimeOrder, + minPercentageToAsk: constants.Zero, + params: emptyEncodedBytes, + signerUser: seller.address, + chainId: env.chainId, + verifyingContract: contracts.bendExchange.address, + }, + adapter.address, + nonce + ); + + await approveBuyerUsdt(); + // no debt weth approvement + + await expect( + contracts.downpayment + .connect(buyer) + .buyWithERC20(adapter.address, contracts.usdt.address, borrowAmount, dataWithSig.data, dataWithSig.sig) + ).to.revertedWith("503"); + await approveBuyerDebtUsdt(); + await exceptDownpaymentSuccessed(price, contracts.usdt.address, borrowAmount); + }); + + it("Sell order with WETH", async () => { + await approveBuyerUsdt(); + await approveBuyerDebtUsdt(); + const borrowAmount = (await contracts.bendLendPool.getNftCollateralData(nft.address, contracts.usdt.address)) + .availableBorrowsInReserve; + const price = borrowAmount.add(parseUnits("10", 6)); + await exceptDownpaymentSuccessed(price, contracts.usdt.address, borrowAmount); + }); +}); diff --git a/test/downpayment.ts b/test/downpayment.ts index 0672910..f07bdea 100644 --- a/test/downpayment.ts +++ b/test/downpayment.ts @@ -61,28 +61,28 @@ makeSuite("downpayment", (contracts: Contracts, env: Env) => { expect(await contracts.downpayment.isAdapterWhitelisted(contracts.weth.address)).to.be.true; let numberAdapters = await contracts.downpayment.viewCountWhitelistedAdapters(); - assert.equal(numberAdapters.toString(), "6"); + assert.equal(numberAdapters.toString(), "7"); let tx = await contracts.downpayment.viewWhitelistedAdapters("0", "1"); assert.equal(tx[0].length, 1); expect(BigNumber.from(tx[1].toString())).to.be.eq(constants.One); tx = await contracts.downpayment.viewWhitelistedAdapters("1", "100"); - assert.equal(tx[0].length, 5); + assert.equal(tx[0].length, 6); expect(BigNumber.from(tx[1].toString())).to.be.eq(BigNumber.from(numberAdapters.toString())); await contracts.downpayment.connect(env.admin).removeAdapter(contracts.weth.address); expect(await contracts.downpayment.isAdapterWhitelisted(contracts.weth.address)).to.be.false; numberAdapters = await contracts.downpayment.viewCountWhitelistedAdapters(); - assert.equal(numberAdapters.toString(), "5"); + assert.equal(numberAdapters.toString(), "6"); tx = await contracts.downpayment.viewWhitelistedAdapters("0", "1"); assert.equal(tx[0].length, 1); expect(BigNumber.from(tx[1].toString())).to.be.eq(constants.One); tx = await contracts.downpayment.viewWhitelistedAdapters("1", "100"); - assert.equal(tx[0].length, 4); + assert.equal(tx[0].length, 5); expect(BigNumber.from(tx[1].toString())).to.be.eq(BigNumber.from(numberAdapters.toString())); }); });