diff --git a/.env.example b/.env.example deleted file mode 100644 index a0cf48b..0000000 --- a/.env.example +++ /dev/null @@ -1,12 +0,0 @@ -CHAIN_TO_FORK=sepolia - -# do | dn - Digital(Original | Native) -COLLECTION=do - -FORKED_CHAIN=sepolia -FORKED_CHAIN_URL=http://localhost:8545/ -FORKED_CHAIN_ID=31337 - -REPORT_GAS=false -ETHERSCAN_API_KEY= -COINMARKETCAP_API_KEY= diff --git a/.gitignore b/.gitignore index deeb924..ca4a6d6 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,11 @@ artifacts venv docs + config.yaml config.env.yaml +config.chain.yaml +config.collection.yaml +config.market.yaml -TODO.md +NOTES.md diff --git a/README.md b/README.md index 0eaa939..311fcfc 100644 --- a/README.md +++ b/README.md @@ -9,25 +9,39 @@ Digital Original (DO) is a modular on-chain framework for managing primary sales and secondary markets of digital collectibles (NFTs). This repository hosts all **Solidity smart-contracts, tests and tooling** required to deploy and operate the protocol. +## 🧩 Features + +- **Primary Sales & Minting**: Directly mint and purchase NFTs with built-in revenue distribution. +- **Secondary Markets**: Peer-to-peer trading of NFTs with off-chain order matching. +- **Auction House**: English-style auctions for primary NFT sales. +- **EIP-712 Permits**: Gas-efficient and secure transactions with cryptographic authorization. +- **Role-Based Access Control**: Granular control over contract functions and administrative actions. +- **Flexible Fee Structures**: Configurable maker and taker fees for market transactions. +- **Multi-Currency Support**: Support for multiple ERC-20 tokens for payments. +- **Upgradeable Contracts**: Upgradeable contract architecture for future improvements. + ## 📚 Contracts ### ArtToken + The `ArtToken` contract is an upgradeable ERC-721 NFT implementation that serves as the core collectible in the Digital Original ecosystem. Key features: -- **Primary Sales**: Supports direct minting and purchasing through the `buy()` function with built-in revenue distribution +- **Primary Sales**: Supports direct minting and purchasing through the `mint()` function with built-in revenue distribution - **EIP-712 Permits**: All primary sales require cryptographic authorization from designated signers - **Compliance & Regulation**: Optional transfer restrictions for regulated tokens - **AuctionHouse Integration**: Works seamlessly with the AuctionHouse for auction-based primary sales - **Revenue Splitting**: Automatic distribution of sale proceeds among multiple participants according to predefined shares ### AuctionHouse + The `AuctionHouse` contract manages English-style auctions for primary NFT sales. Key features: - **Auction Creation**: Authorized creation of time-bound auctions with EIP-712 signatures - **Bidding System**: Progressive bidding with minimum raise steps and automatic refunds to outbid participants -- **USDC Integration**: All bids and settlements are conducted in USDC for stable pricing +- **Multi-Currency**: Configurable support for multiple ERC-20 payment currencies ### Market + The `Market` contract facilitates peer-to-peer secondary trading of NFTs through off-chain order matching. Key features: - **Order Types**: Supports both sell-side (ask) and buy-side (bid) orders @@ -38,28 +52,19 @@ The `Market` contract facilitates peer-to-peer secondary trading of NFTs through - **Revenue Sharing**: Built-in mechanism for distributing fees among multiple participants - **Security**: Time-bound orders with replay protection and signature verification -## 🗂 Repository Layout - -``` -contracts/ Solidity sources -├─ art-token/ ▸ `ArtToken` and base logic -├─ auction-house/ ▸ `AuctionHouse` contracts -├─ market/ ▸ `Market` and order libs -├─ utils/ ▸ Shared libraries & helpers -tests/ Hardhat unit tests (TypeScript) -scripts/ Re-usable deployment scripts -tasks/ Hardhat CLI tasks (`npx hardhat `) -abis/ Pre-generated ABIs -``` +## 🏃🏽 Getting Started -## ⚡️ Quick Start +### 📋 Prerequisites +- [Node.js](https://nodejs.org/) (v24+) +- [Python](https://www.python.org/) (for static analysis) +### ⚡️ Quick Start ```bash # 1. install deps npm install -# 2. copy environment templates and adjust values -cp config.env.example.yaml config.env.yaml +# 2. init config templates +source ./init.sh # 3. compile npm run compile @@ -68,36 +73,69 @@ npm run compile npm run test ``` -### Local fork +### ⚙️ Configuration + +The project uses YAML files for configuration. You'll need to create your own configuration files by copying the example files and editing them with your desired settings. + +Every Hardhat network entry gets enriched with a `protocolConfig` object at runtime, see `hardhat.config.ts`. + +1. **Environment Config:** Copy `config.env.example.yaml` to `config.env.yaml` and add your API keys (e.g., Etherscan, CoinMarketCap). + +2. **Chain Config:** Copy `config.chain.example.yaml` to `config.chain.yaml` and add your RPC URLs and deployer private keys for the desired networks. + +3. **Collection Config:** Copy `config.collection.example.yaml` to `config.collection.yaml` and configure the art token collection parameters. + +4. **Market Config:** Copy `config.market.example.yaml` to `config.market.yaml` and configure the marketplace parameters. -Spin up a mainnet-fork (uses `config.env.yaml` for URL): +### 🍴 Local Fork +Spin up a mainnet-fork using the URL from `config.chain.yaml`: ```bash npm run fork -# in another terminal you can deploy the collection -npx hardhat deploy-collection --network fork ``` -## 🔧 Configuration Files - -* `config.env.yaml` – chain URLs, private keys, API keys (never commit real secrets) -* `config.do.yaml` / `config.dn.yaml` – collection parameters -* `config.market.yaml` – market parameters - -Every Hardhat network entry gets enriched with a `protocolConfig` object at runtime, see `hardhat.config.ts`. +In a separate terminal, you can then use hardhat tasks: +```bash +npx hardhat deploy-collection --network fork +``` -## 🛠 NPM Scripts +### 📜 NPM Scripts -| Script | Description | -| ------ | ----------- | -| `npm run compile` | Clean & compile contracts | -| `npm run test` | Execute TypeScript test-suite | -| `npm run fork` | Start a local Hardhat node (optionally forking) | +| Script | Description | +| ----------------- | ------------------------------------------------------------------ | +| `npm run compile` | Clean & compile contracts | +| `npm run test` | Execute TypeScript test-suite | +| `npm run fork` | Start a local Hardhat node (optionally forking) | | `npm run slither` | Static analysis using [Slither](https://github.com/crytic/slither) | -| `npm run lint` | Lint Solidity with Solhint | -| `npm run format` | Auto-format using Prettier | - -## 🛡️ Slither Static Analysis +| `npm run lint` | Lint Solidity with Solhint | +| `npm run format` | Auto-format using Prettier | + +### 👷🏽 Hardhat Tasks + +- **Deploy Collection**: + ```bash + npx hardhat deploy-collection --network + ``` +- **Deploy Market**: + ```bash + npx hardhat deploy-market --network + ``` +- **Deploy Individual Implementations**: + ```bash + npx hardhat deploy-art-token-impl --network + npx hardhat deploy-auction-house-impl --network + npx hardhat deploy-market-impl --network + ``` +- **Verify Contracts on Etherscan**: + ```bash + npx hardhat verify-art-token --network + npx hardhat verify-auction-house --network + npx hardhat verify-market --network + ``` + +To see a full list of available tasks, run `npx hardhat --help`. + +## 🛡️ Static Analysis To run Slither for smart contract security analysis, you need to set up a Python virtual environment first: @@ -124,28 +162,6 @@ The Slither configuration is defined in `slither.config.json`. After running, yo deactivate ``` -## 🤖 Hardhat Tasks - -```bash -# Deploy collection (ArtToken + AuctionHouse proxies) -npx hardhat deploy-collection --network - -# Deploy individual implementations -npx hardhat deploy-art-token-impl --network -npx hardhat deploy-auction-house-impl --network -npx hardhat deploy-market-impl --network - -# Deploy Market proxy -npx hardhat deploy-market --network - -# Verify on Etherscan -npx hardhat verify-art-token --network -npx hardhat verify-auction-house --network -npx hardhat verify-market --network -``` - -Run `npx hardhat --help` to list all available tasks. - ## 📜 License Licensed under **GPL-3.0** – see [LICENSE](./LICENSE) for details. diff --git a/abis/ArtToken.json b/abis/ArtToken.json index 3998756..a3a9976 100644 --- a/abis/ArtToken.json +++ b/abis/ArtToken.json @@ -15,21 +15,6 @@ "internalType": "address", "name": "auctionHouse", "type": "address" - }, - { - "internalType": "address", - "name": "usdc", - "type": "address" - }, - { - "internalType": "uint256", - "name": "minPrice", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minFee", - "type": "uint256" } ], "stateMutability": "nonpayable", @@ -70,7 +55,7 @@ }, { "inputs": [], - "name": "ArtTokenEmptyTokenURI", + "name": "ArtTokenCurrencyInvalid", "type": "error" }, { @@ -94,6 +79,17 @@ "name": "ArtTokenMisconfiguration", "type": "error" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ArtTokenNonexistentToken", + "type": "error" + }, { "inputs": [], "name": "ArtTokenTokenReserved", @@ -439,6 +435,25 @@ "name": "BatchMetadataUpdate", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "allowed", + "type": "bool" + } + ], + "name": "CurrencyStatusUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -614,20 +629,7 @@ }, { "inputs": [], - "name": "MIN_FEE", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "MIN_PRICE", + "name": "ROYALTY_PERCENT_IN_BP", "outputs": [ { "internalType": "uint256", @@ -638,19 +640,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "USDC", - "outputs": [ - { - "internalType": "contract IERC20", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -688,6 +677,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "currency", + "type": "address" + } + ], + "name": "currencyAllowed", + "outputs": [ + { + "internalType": "bool", + "name": "allowed", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -805,6 +813,11 @@ "name": "minter", "type": "address" }, + { + "internalType": "address", + "name": "currency", + "type": "address" + }, { "internalType": "uint256", "name": "price", @@ -865,7 +878,7 @@ ], "name": "mint", "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { @@ -977,6 +990,35 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "salePrice", + "type": "uint256" + } + ], + "name": "royaltyInfo", + "outputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "royaltyAmount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1046,6 +1088,24 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_tokenURI", + "type": "string" + } + ], + "name": "setTokenURI", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1270,6 +1330,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "internalType": "bool", + "name": "allowed", + "type": "bool" + } + ], + "name": "updateCurrencyStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/abis/AuctionHouse.json b/abis/AuctionHouse.json index f55d582..3c60526 100644 --- a/abis/AuctionHouse.json +++ b/abis/AuctionHouse.json @@ -16,25 +16,10 @@ "name": "artToken", "type": "address" }, - { - "internalType": "address", - "name": "usdc", - "type": "address" - }, { "internalType": "uint256", "name": "minAuctionDuration", "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minPrice", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minFee", - "type": "uint256" } ], "stateMutability": "nonpayable", @@ -94,7 +79,7 @@ }, { "inputs": [], - "name": "AuctionHouseEmptyTokenURI", + "name": "AuctionHouseInvalidCurrency", "type": "error" }, { @@ -170,32 +155,6 @@ "name": "AuthorizationUnauthorizedAction", "type": "error" }, - { - "inputs": [], - "name": "DistributionParticipantsSharesMismatch", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "sharesSum", - "type": "uint256" - } - ], - "name": "DistributionSharesSumInvalid", - "type": "error" - }, - { - "inputs": [], - "name": "DistributionZeroAddress", - "type": "error" - }, - { - "inputs": [], - "name": "DistributionZeroShare", - "type": "error" - }, { "inputs": [], "name": "ECDSAInvalidSignature", @@ -286,6 +245,26 @@ "name": "RoleSystemZeroAddress", "type": "error" }, + { + "inputs": [], + "name": "SafeERC20BulkTransferIncorrectTotalAmount", + "type": "error" + }, + { + "inputs": [], + "name": "SafeERC20BulkTransferInvalidInputLengths", + "type": "error" + }, + { + "inputs": [], + "name": "SafeERC20BulkTransferZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "SafeERC20BulkTransferZeroValue", + "type": "error" + }, { "inputs": [ { @@ -297,6 +276,45 @@ "name": "SafeERC20FailedOperation", "type": "error" }, + { + "inputs": [], + "name": "ShareDistributorParticipantsSharesMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sharesSum", + "type": "uint256" + } + ], + "name": "ShareDistributorSharesSumInvalid", + "type": "error" + }, + { + "inputs": [], + "name": "ShareDistributorZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ShareDistributorZeroShare", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "auctionId", + "type": "uint256" + } + ], + "name": "Cancelled", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -328,6 +346,25 @@ "name": "Created", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "allowed", + "type": "bool" + } + ], + "name": "CurrencyStatusUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -501,45 +538,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "MIN_FEE", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "MIN_PRICE", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "USDC", - "outputs": [ - { - "internalType": "contract IERC20", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -601,6 +599,11 @@ "internalType": "uint256[]", "name": "shares", "type": "uint256[]" + }, + { + "internalType": "address", + "name": "currency", + "type": "address" } ], "internalType": "struct Auction.Type", @@ -611,6 +614,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "auctionId", + "type": "uint256" + } + ], + "name": "cancel", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -625,6 +641,11 @@ "name": "tokenId", "type": "uint256" }, + { + "internalType": "address", + "name": "currency", + "type": "address" + }, { "internalType": "uint256", "name": "price", @@ -698,6 +719,25 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "currency", + "type": "address" + } + ], + "name": "currencyAllowed", + "outputs": [ + { + "internalType": "bool", + "name": "allowed", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -768,7 +808,7 @@ ], "name": "raise", "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { @@ -786,7 +826,7 @@ ], "name": "raiseInitial", "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { @@ -862,5 +902,23 @@ ], "stateMutability": "view", "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "currency", + "type": "address" + }, + { + "internalType": "bool", + "name": "allowed", + "type": "bool" + } + ], + "name": "updateCurrencyStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" } ] diff --git a/abis/Market.json b/abis/Market.json index b54c028..21221b8 100644 --- a/abis/Market.json +++ b/abis/Market.json @@ -575,7 +575,7 @@ ], "name": "executeAsk", "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { diff --git a/config.chain.example.yaml b/config.chain.example.yaml new file mode 100644 index 0000000..259ed23 --- /dev/null +++ b/config.chain.example.yaml @@ -0,0 +1,11 @@ +sepolia: + chainId: 11155111 + url: '' + deployerPrivateKey: '' + main: '' + +ethereum: + chainId: 1 + url: '' + deployerPrivateKey: '' + main: '' diff --git a/config.collection.example.yaml b/config.collection.example.yaml new file mode 100644 index 0000000..9c07fc6 --- /dev/null +++ b/config.collection.example.yaml @@ -0,0 +1,24 @@ +name: 'DigitalOriginal' +symbol: 'DO' + +sepolia: + minAuctionDurationHours: 0.25 + artToken: + proxy: '' + impl: '' + admin: '' + auctionHouse: + proxy: '' + impl: '' + admin: '' + +ethereum: + minAuctionDurationHours: 24 + artToken: + proxy: '' + impl: '' + admin: '' + auctionHouse: + proxy: '' + impl: '' + admin: '' diff --git a/config.dn.yaml b/config.dn.yaml deleted file mode 100644 index d1caf5b..0000000 --- a/config.dn.yaml +++ /dev/null @@ -1,40 +0,0 @@ -name: 'DigitalNative' -symbol: 'DN' - -sepolia: - minPriceUsd: 50 - minFeeUsd: 50 - minAuctionDurationHours: 0.25 - - # dev - artToken: - proxy: '0xf048e2A207f384998BBC063A85BB59550b6b9721' - impl: '0x1e6b581F60dd8495900701e50B48BF20630331F7' - admin: '0xaCB27D0692B723600b9AdFD3f91507A8a10Cf4eA' - auctionHouse: - proxy: '0x58Bb53C2aDd8e468538122c434CD3D57bd9Aa93D' - impl: '0x88C539cd819F0734D249Da4cC10AA6D018bC4845' - admin: '0x444d63843B8787F36c966435A4a8398eBB0eb362' - - # local - # artToken: - # proxy: '0x3dB89e927b1EA33bAD00a24d3d962c9BCe224714' - # impl: '0x54e82eC58A90785032AD9ba6d6bfD2007b927Cc4' - # admin: '0xaAF46D91FDE570427ccB22c22f91ABB335DAb2cD' - # auctionHouse: - # proxy: '0x07FB267bcec6485B1a9b8e5d1F95E5974566a5fE' - # impl: '0xD7669Df7C0F99ae50b102A7e42fCfB11334600dA' - # admin: '0xDdc680Aa4852dA4a43198e7c1FF3d04bA53f8910' - -ethereum: - minPriceUsd: 30 - minFeeUsd: 30 - minAuctionDurationHours: 12 - artToken: - proxy: '0x9ada5D6A6192eAda21b45268Da4948e69059EA69' - impl: '0x1e6b581F60dd8495900701e50B48BF20630331F7' - admin: '0xc092f522AAdB74FAE51fF38696BfdDd0E017ff0c' - auctionHouse: - proxy: '0x534ecf8fBb28a31851B7137B8dB96592F8E6b22C' - impl: '0x15f22f722E8d923a2fC8F3288Dd2A1BB9fE6563D' - admin: '0x8E73Aa836017bAf87eF6d8feC1a075b98D5Da008' diff --git a/config.do.yaml b/config.do.yaml deleted file mode 100644 index c947e93..0000000 --- a/config.do.yaml +++ /dev/null @@ -1,40 +0,0 @@ -name: 'DigitalOriginal' -symbol: 'DO' - -sepolia: - minPriceUsd: 100 - minFeeUsd: 100 - minAuctionDurationHours: 0.25 - - # dev - artToken: - proxy: '0xaf99c146DC881A37a8e960d9EdC1818eEF6CaE7A' - impl: '0xC223b0B26bD1669dfcb1773A01bb4860E8064701' - admin: '0x6c6e09B662Ff1611826fb304A095fE34daCD1c8d' - auctionHouse: - proxy: '0x68748499241200b3173082567d5F38B00B8CEe06' - impl: '0x9C8eAE30b12E6A12EFf556ea8350F45FCFCaEADc' - admin: '0xE2B7755956382bE4a2fCE7a0e67d4BDd74770a48' - - # local - # artToken: - # proxy: '0xe74D07495C9CD456574Dccb5b48cD80B59412136' - # impl: '0xc022E88EBdc40BB1BBec8b29F759A898477329c9' - # admin: '0x23e435Dd7fd98313Da588bFb5df74A067ac9Cb98' - # auctionHouse: - # proxy: '0xFaF5E7bb2EF569d89eF0Af819e54eEf780cCBc25' - # impl: '0x472A116dd99291DFBf3eaeEE913dFda17634ACB2' - # admin: '0xfaa84c3EE49FBF050B850A073186A83780b01964' - -ethereum: - minPriceUsd: 100 - minFeeUsd: 100 - minAuctionDurationHours: 24 - artToken: - proxy: '0x653cdB21a83b59374C194002Da332D683F5678aA' - impl: '0x2A87F19DC4Ff1633691813CcA5b04690c3c22862' - admin: '0x6c54061AC5c758B12453558c846c570842B82A13' - auctionHouse: - proxy: '0x7bb8807250928FC57c1eb01A4B65860439F94e36' - impl: '0xBed85fc1F272aea5aE0b0100C67ae1c691FAF500' - admin: '0xA6D10309e4dbC8259a80e37eeF09eAd6D08f92c9' diff --git a/config.env.example.yaml b/config.env.example.yaml index cd2d041..fdee84c 100644 --- a/config.env.example.yaml +++ b/config.env.example.yaml @@ -1,15 +1,7 @@ -sepolia: - chainId: 11155111 - url: '' - deployerPrivateKey: '' - - usdc: '0x622333D6627BaE0a7e76F507f8E21aAed577Dd57' - main: '0x27fc066baF73Ee97Ce5b95172d82F407490D49b1' - -ethereum: - chainId: 1 - url: '' - deployerPrivateKey: '' - - usdc: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' - main: '0x445458607007b26dB4f80DcF0f26bd6e1A4af8A5' +fork: + name: 'ethereum' + chainId: 31337 + url: 'http://localhost:8545/' +reportGas: false +etherscanApiKey: '' +coinmarketcapApiKey: '' diff --git a/config.market.yaml b/config.market.example.yaml similarity index 60% rename from config.market.yaml rename to config.market.example.yaml index e289068..d808786 100644 --- a/config.market.yaml +++ b/config.market.example.yaml @@ -1,16 +1,9 @@ sepolia: - # dev market: proxy: '' impl: '' admin: '' - # local - # market: - # proxy: '' - # impl: '' - # admin: '' - ethereum: market: proxy: '' diff --git a/contracts/art-token/ArtToken.sol b/contracts/art-token/ArtToken.sol index 0a15b05..9d4ed72 100644 --- a/contracts/art-token/ArtToken.sol +++ b/contracts/art-token/ArtToken.sol @@ -6,6 +6,7 @@ import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol import {EIP712Domain} from "../utils/EIP712Domain.sol"; import {RoleSystem} from "../utils/role-system/RoleSystem.sol"; import {Authorization} from "../utils/Authorization.sol"; +import {CurrencyManager} from "../utils/currency-manager/CurrencyManager.sol"; import {SafeERC20BulkTransfer} from "../utils/SafeERC20BulkTransfer.sol"; import {TokenConfig} from "../utils/TokenConfig.sol"; import {Roles} from "../utils/Roles.sol"; @@ -29,25 +30,15 @@ contract ArtToken is EIP712Domain, RoleSystem, Authorization, + CurrencyManager, ArtTokenConfigManager, ArtTokenRoyaltyManager { - // TODO: need to implement method for validation mint conditions (tokenId, URI, config, etc) - using SafeERC20 for IERC20; using TokenMintingPermit for TokenMintingPermit.Type; /// @notice Address of the accompanying AuctionHouse contract. IAuctionHouse public immutable AUCTION_HOUSE; - /// @notice Settlement token. - IERC20 public immutable USDC; - - /// @notice Minimum allowed primary-sale price. - uint256 public immutable MIN_PRICE; - - /// @notice Minimum allowed platform fee. - uint256 public immutable MIN_FEE; - /** * @notice Contract constructor. * @@ -55,27 +46,15 @@ contract ArtToken is * (used for EIP-712 domain separator). * @param main Address that will be set as {RoleSystem.MAIN}. * @param auctionHouse Address of the AuctionHouse contract. - * @param usdc Address of the USDC token contract. - * @param minPrice Absolute minimum `price` accepted for a primary sale. - * @param minFee Absolute minimum `fee` accepted for a primary sale. */ constructor( address proxy, address main, - address auctionHouse, - address usdc, - uint256 minPrice, - uint256 minFee + address auctionHouse ) EIP712Domain(proxy, "ArtToken", "1") RoleSystem(main) { if (auctionHouse == address(0)) revert ArtTokenMisconfiguration(2); - if (usdc == address(0)) revert ArtTokenMisconfiguration(3); - if (minPrice == 0) revert ArtTokenMisconfiguration(4); - if (minFee == 0) revert ArtTokenMisconfiguration(5); AUCTION_HOUSE = IAuctionHouse(auctionHouse); - USDC = IERC20(usdc); - MIN_PRICE = minPrice; - MIN_FEE = minFee; } /** @@ -97,18 +76,18 @@ contract ArtToken is /** * @inheritdoc IArtToken */ - function mint(TokenMintingPermit.Type calldata permit, bytes calldata permitSignature) external { + function mint(TokenMintingPermit.Type calldata permit, bytes calldata permitSignature) external payable { _requireAuthorizedAction(permit.hash(), permit.deadline, permitSignature); if (permit.minter != msg.sender) { revert ArtTokenUnauthorizedAccount(msg.sender); } - if (permit.price < MIN_PRICE) { + if (permit.price == 0) { revert ArtTokenInvalidPrice(); } - if (permit.fee < MIN_FEE) { + if (permit.fee == 0) { revert ArtTokenInvalidFee(); } @@ -116,13 +95,30 @@ contract ArtToken is revert ArtTokenTokenReserved(); } + if (!currencyAllowed(permit.currency)) { + revert ArtTokenCurrencyInvalid(); + } + + IERC20 currency = IERC20(permit.currency); + _mint(permit.minter, permit.tokenId, permit.tokenURI, permit.tokenConfig); - USDC.safeTransferFrom(msg.sender, address(this), permit.price + permit.fee); + SafeERC20.safeTransferFrom(currency, msg.sender, address(this), permit.price + permit.fee); - SafeERC20BulkTransfer.safeTransfer(USDC, permit.price, permit.participants, permit.rewards); + SafeERC20BulkTransfer.safeTransfer(currency, permit.price, permit.participants, permit.rewards); - USDC.safeTransfer(uniqueRoleOwner(Roles.FINANCIAL_ROLE), permit.fee); + SafeERC20.safeTransfer(currency, uniqueRoleOwner(Roles.FINANCIAL_ROLE), permit.fee); + } + + /** + * @inheritdoc IArtToken + */ + function setTokenURI(uint256 tokenId, string memory _tokenURI) external onlyRole(Roles.ADMIN_ROLE) { + if (_ownerOf(tokenId) == address(0)) { + revert ArtTokenNonexistentToken(tokenId); + } + + _setTokenURI(tokenId, _tokenURI); } /** @@ -141,8 +137,10 @@ contract ArtToken is /** * @notice Internal function to mint a new token. + * * @dev This function is called by both `mintFromAuctionHouse` and `mint`. It handles the core * minting logic and sets the token URI and configuration. + * * @param to The address that will receive the newly minted token. * @param tokenId The unique identifier of the token to mint. * @param _tokenURI The metadata URI that will be associated with the token. @@ -154,15 +152,17 @@ contract ArtToken is string calldata _tokenURI, TokenConfig.Type calldata tokenConfig ) internal { - if (bytes(_tokenURI).length == 0) { - revert ArtTokenEmptyTokenURI(); - } - _safeMintAndSetTokenURI(to, tokenId, _tokenURI); _setTokenConfig(tokenId, tokenConfig); } - /// @dev Reverts unless `account` passes {recipientAuthorized}. + /** + * @notice Reverts unless `account` passes {recipientAuthorized}. + * + * @dev This function is used to enforce that only authorized accounts can receive tokens. + * + * @param account The account to check. + */ function _requireAuthorizedRecipient(address account) private view { if (!recipientAuthorized(account)) { revert ArtTokenUnauthorizedAccount(account); diff --git a/contracts/art-token/ArtTokenBase.sol b/contracts/art-token/ArtTokenBase.sol index 9b47310..b1df1d8 100644 --- a/contracts/art-token/ArtTokenBase.sol +++ b/contracts/art-token/ArtTokenBase.sol @@ -2,12 +2,8 @@ pragma solidity ^0.8.20; import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; -import { - ERC721URIStorageUpgradeable -} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol"; -import { - ERC721EnumerableUpgradeable -} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; +import {ERC721URIStorageUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol"; +import {ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol"; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import {IERC2981} from "@openzeppelin/contracts/interfaces/IERC2981.sol"; diff --git a/contracts/art-token/ArtTokenRoyaltyManager.sol b/contracts/art-token/ArtTokenRoyaltyManager.sol index ff46e85..d3f01c0 100644 --- a/contracts/art-token/ArtTokenRoyaltyManager.sol +++ b/contracts/art-token/ArtTokenRoyaltyManager.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.20; import {IERC2981} from "@openzeppelin/contracts/interfaces/IERC2981.sol"; import {ArtTokenConfigManager} from "./art-token-config-manager/ArtTokenConfigManager.sol"; +import {ONE_HUNDRED_PERCENT_IN_BP} from "../utils/Constants.sol"; /** * @title ArtTokenRoyaltyManager @@ -14,14 +15,9 @@ import {ArtTokenConfigManager} from "./art-token-config-manager/ArtTokenConfigMa */ abstract contract ArtTokenRoyaltyManager is IERC2981, ArtTokenConfigManager { /** - * @notice The royalty percentage in basis points (500 = 5%). + * @notice The royalty percentage in basis points - 5%. */ - uint256 public constant ROYALTY_PERCENT_IN_BP = 500; // 5% - - /** - * @notice One hundred percent represented in basis points (10000 = 100%). - */ - uint256 public constant ONE_HUNDRED_PERCENT_IN_BP = 10000; // 100% in basis points + uint256 public constant ROYALTY_PERCENT_IN_BP = ONE_HUNDRED_PERCENT_IN_BP / 20; // 5% /** * @notice Calculates the royalty payment for a token sale, returning the recipient's address and the royalty amount. diff --git a/contracts/art-token/IArtToken.sol b/contracts/art-token/IArtToken.sol index 1c3d07a..242a35d 100644 --- a/contracts/art-token/IArtToken.sol +++ b/contracts/art-token/IArtToken.sol @@ -32,7 +32,15 @@ interface IArtToken is IERC721 { * @param permit The `TokenMintingPermit` struct containing the sale details. * @param permitSignature The EIP-712 signature of the `permit`, signed by the art-token signer. */ - function mint(TokenMintingPermit.Type calldata permit, bytes calldata permitSignature) external; + function mint(TokenMintingPermit.Type calldata permit, bytes calldata permitSignature) external payable; + + /** + * @notice Sets the token URI for a given token. + * + * @param tokenId The ID of the token to update. + * @param _tokenURI The new token URI. + */ + function setTokenURI(uint256 tokenId, string memory _tokenURI) external; /** * @notice Returns whether `tokenId` has already been minted (i.e., is reserved). @@ -55,8 +63,11 @@ interface IArtToken is IERC721 { /// @dev Thrown when an action involves an account that is not authorized by the contract rules. error ArtTokenUnauthorizedAccount(address account); - /// @dev Thrown when an empty string is passed as a token URI where a non-empty value is required. - error ArtTokenEmptyTokenURI(); + /// @dev Thrown when a token does not exist. + error ArtTokenNonexistentToken(uint256 tokenId); + + /// @dev Thrown when a currency is invalid. + error ArtTokenCurrencyInvalid(); /// @dev Thrown when `price` supplied to {buy} is below the minimum configured price. error ArtTokenInvalidPrice(); diff --git a/contracts/art-token/art-token-config-manager/ArtTokenConfigManager.sol b/contracts/art-token/art-token-config-manager/ArtTokenConfigManager.sol index 854388b..019e8eb 100644 --- a/contracts/art-token/art-token-config-manager/ArtTokenConfigManager.sol +++ b/contracts/art-token/art-token-config-manager/ArtTokenConfigManager.sol @@ -18,7 +18,6 @@ abstract contract ArtTokenConfigManager is IArtTokenConfigManager, RoleSystem { /** * @inheritdoc IArtTokenConfigManager */ - // TODO: Should I add validation for null value? function updateTokenCreator(uint256 tokenId, address creator) external onlyRole(Roles.ADMIN_ROLE) { ArtTokenConfigManagerStorage.Layout storage $ = ArtTokenConfigManagerStorage.layout(); diff --git a/contracts/art-token/libraries/TokenMintingPermit.sol b/contracts/art-token/libraries/TokenMintingPermit.sol index 16531bd..3473272 100644 --- a/contracts/art-token/libraries/TokenMintingPermit.sol +++ b/contracts/art-token/libraries/TokenMintingPermit.sol @@ -17,6 +17,7 @@ library TokenMintingPermit { * * @param tokenId The ID of the token to be minted. * @param minter The address of the account that will mint the token. + * @param currency The token used for payment. * @param price The price of the token for the primary sale. * @param fee The platform fee for the primary sale. * @param tokenURI The metadata URI for the token. @@ -28,6 +29,7 @@ library TokenMintingPermit { struct Type { uint256 tokenId; address minter; + address currency; uint256 price; uint256 fee; string tokenURI; @@ -44,6 +46,7 @@ library TokenMintingPermit { "TokenMintingPermit(" "uint256 tokenId," "address minter," + "address currency," "uint256 price," "uint256 fee," "string tokenURI," @@ -68,6 +71,7 @@ library TokenMintingPermit { TYPE_HASH, permit.tokenId, permit.minter, + permit.currency, permit.price, permit.fee, keccak256(bytes(permit.tokenURI)), diff --git a/contracts/auction-house/AuctionHouse.sol b/contracts/auction-house/AuctionHouse.sol index c1c03d7..644c182 100644 --- a/contracts/auction-house/AuctionHouse.sol +++ b/contracts/auction-house/AuctionHouse.sol @@ -6,7 +6,8 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {EIP712Domain} from "../utils/EIP712Domain.sol"; import {RoleSystem} from "../utils/role-system/RoleSystem.sol"; import {Authorization} from "../utils/Authorization.sol"; -import {Distribution} from "../utils/Distribution.sol"; +import {ShareDistributor} from "./libraries/ShareDistributor.sol"; +import {CurrencyManager} from "../utils/currency-manager/CurrencyManager.sol"; import {Roles} from "../utils/Roles.sol"; import {IArtToken} from "../art-token/IArtToken.sol"; import {AuctionCreationPermit} from "./libraries/AuctionCreationPermit.sol"; @@ -22,28 +23,18 @@ import {IAuctionHouse} from "./IAuctionHouse.sol"; * USDC and, after the auction ends, the highest bidder receives the token while funds are * split between participants and the protocol treasury. */ -contract AuctionHouse is IAuctionHouse, EIP712Domain, RoleSystem, Authorization { - using SafeERC20 for IERC20; +contract AuctionHouse is IAuctionHouse, EIP712Domain, RoleSystem, Authorization, CurrencyManager { using AuctionCreationPermit for AuctionCreationPermit.Type; /// @notice Address of the associated {ArtToken} contract. IArtToken public immutable ART_TOKEN; - /// @notice Settlement token (USDC) used for bidding and payouts. - IERC20 public immutable USDC; - /// @notice Minimum auction duration configured at deployment. uint256 public immutable MIN_DURATION; /// @notice Hard-coded upper bound for auction duration (21 days). uint256 public constant MAX_DURATION = 21 days; - /// @notice Minimal allowed starting price / bid value. - uint256 public immutable MIN_PRICE; - - /// @notice Minimal platform fee that must accompany each auction. - uint256 public immutable MIN_FEE; - /// @notice Ensures that an auction with `auctionId` exists. /// @dev Reverts with {AuctionHouseAuctionNotExists} otherwise. modifier auctionExists(uint256 auctionId) { @@ -120,31 +111,19 @@ contract AuctionHouse is IAuctionHouse, EIP712Domain, RoleSystem, Authorization * @param proxy Proxy address used for EIP-712 verifying contract. * @param main Address that will be set as {RoleSystem.MAIN}. * @param artToken Address of the {ArtToken} contract. - * @param usdc Address of the USDC ERC-20 token. * @param minAuctionDuration Minimum auction duration (seconds). - * @param minPrice Minimum starting price/bid. - * @param minFee Minimum platform fee. */ constructor( address proxy, address main, address artToken, - address usdc, - uint256 minAuctionDuration, - uint256 minPrice, - uint256 minFee + uint256 minAuctionDuration ) EIP712Domain(proxy, "AuctionHouse", "1") RoleSystem(main) { if (artToken == address(0)) revert AuctionHouseMisconfiguration(2); - if (usdc == address(0)) revert AuctionHouseMisconfiguration(3); - if (minAuctionDuration == 0) revert AuctionHouseMisconfiguration(4); - if (minPrice == 0) revert AuctionHouseMisconfiguration(5); - if (minFee == 0) revert AuctionHouseMisconfiguration(6); + if (minAuctionDuration == 0) revert AuctionHouseMisconfiguration(3); ART_TOKEN = IArtToken(artToken); - USDC = IERC20(usdc); MIN_DURATION = minAuctionDuration; - MIN_PRICE = minPrice; - MIN_FEE = minFee; } /** @@ -156,15 +135,11 @@ contract AuctionHouse is IAuctionHouse, EIP712Domain, RoleSystem, Authorization ) external auctionNotExist(permit.auctionId) { _requireAuthorizedAction(permit.hash(), permit.deadline, permitSignature); - if (bytes(permit.tokenURI).length == 0) { - revert AuctionHouseEmptyTokenURI(); - } - - if (permit.price < MIN_PRICE) { + if (permit.price == 0) { revert AuctionHouseInvalidPrice(); } - if (permit.fee < MIN_FEE) { + if (permit.fee == 0) { revert AuctionHouseInvalidFee(); } @@ -180,6 +155,10 @@ contract AuctionHouse is IAuctionHouse, EIP712Domain, RoleSystem, Authorization revert AuctionHouseInvalidEndTime(); } + if (!currencyAllowed(permit.currency)) { + revert AuctionHouseInvalidCurrency(); + } + if (tokenReserved(permit.tokenId)) { revert AuctionHouseTokenReserved(); } @@ -188,7 +167,7 @@ contract AuctionHouse is IAuctionHouse, EIP712Domain, RoleSystem, Authorization revert AuctionHouseTokenReserved(); } - Distribution.requireValidConditions(permit.participants, permit.shares); + ShareDistributor.requireValidConditions(permit.participants, permit.shares); AuctionHouseStorage.Layout storage $ = AuctionHouseStorage.layout(); @@ -202,7 +181,8 @@ contract AuctionHouse is IAuctionHouse, EIP712Domain, RoleSystem, Authorization sold: false, tokenURI: permit.tokenURI, participants: permit.participants, - shares: permit.shares + shares: permit.shares, + currency: permit.currency }); $.tokenAuctionId[permit.tokenId] = permit.auctionId; @@ -229,19 +209,31 @@ contract AuctionHouse is IAuctionHouse, EIP712Domain, RoleSystem, Authorization function raiseInitial( uint256 auctionId, uint256 newPrice - ) external authorizedBuyer(msg.sender) auctionExists(auctionId) auctionNotEnded(auctionId) withoutBuyer(auctionId) { + ) + external + payable + authorizedBuyer(msg.sender) + auctionExists(auctionId) + auctionNotEnded(auctionId) + withoutBuyer(auctionId) + { AuctionHouseStorage.Layout storage $ = AuctionHouseStorage.layout(); if (newPrice < $.auction[auctionId].price) { revert AuctionHouseRaiseTooLow($.auction[auctionId].price); } - emit Raised(auctionId, msg.sender, newPrice); - $.auction[auctionId].buyer = msg.sender; $.auction[auctionId].price = newPrice; - USDC.safeTransferFrom(msg.sender, address(this), newPrice + $.auction[auctionId].fee); + emit Raised(auctionId, msg.sender, newPrice); + + SafeERC20.safeTransferFrom( + IERC20($.auction[auctionId].currency), + msg.sender, + address(this), + newPrice + $.auction[auctionId].fee + ); } /** @@ -261,27 +253,46 @@ contract AuctionHouse is IAuctionHouse, EIP712Domain, RoleSystem, Authorization function raise( uint256 auctionId, uint256 newPrice - ) external authorizedBuyer(msg.sender) auctionExists(auctionId) auctionNotEnded(auctionId) withBuyer(auctionId) { + ) + external + payable + authorizedBuyer(msg.sender) + auctionExists(auctionId) + auctionNotEnded(auctionId) + withBuyer(auctionId) + { AuctionHouseStorage.Layout storage $ = AuctionHouseStorage.layout(); Auction.Type memory _auction = $.auction[auctionId]; - uint256 price = _auction.price; - address buyer = _auction.buyer; uint256 step = _auction.step; + uint256 price = _auction.price; uint256 fee = _auction.fee; + address currency = _auction.currency; if (newPrice < price + step) { revert AuctionHouseRaiseTooLow(price + step); } + emit Raised(auctionId, msg.sender, newPrice); + + SafeERC20.safeTransferFrom( + IERC20(currency), + msg.sender, + address(this), + newPrice + fee // + ); + + address buyer = _auction.buyer; + $.auction[auctionId].buyer = msg.sender; $.auction[auctionId].price = newPrice; - emit Raised(auctionId, msg.sender, newPrice); - - USDC.safeTransferFrom(msg.sender, address(this), newPrice + fee); - USDC.safeTransfer(buyer, price + fee); + SafeERC20.safeTransfer( + IERC20(currency), + buyer, + price + fee // + ); } /** @@ -292,7 +303,7 @@ contract AuctionHouse is IAuctionHouse, EIP712Domain, RoleSystem, Authorization * 2. Mints the NFT to the stored `buyer` via {ArtToken.mintFromAuctionHouse}. * 3. Transfers the platform `fee` to the treasury (owner of {Roles.FINANCIAL_ROLE}). * 4. Splits the sale `price` among `participants` according to `shares` using - * {Distribution.distribute}. + * {ShareDistributor.distribute}. * * Reverts with {AuctionHouseTokenSold} if already settled. * @@ -318,9 +329,40 @@ contract AuctionHouse is IAuctionHouse, EIP712Domain, RoleSystem, Authorization $.tokenConfig[_auction.tokenId] ); - USDC.safeTransfer(uniqueRoleOwner(Roles.FINANCIAL_ROLE), _auction.fee); + address currency = _auction.currency; + + SafeERC20.safeTransfer( + IERC20(currency), + uniqueRoleOwner(Roles.FINANCIAL_ROLE), + _auction.fee // + ); + + ShareDistributor.distribute( + currency, + _auction.price, + _auction.participants, + _auction.shares // + ); + } + + /** + * @inheritdoc IAuctionHouse + * + * @dev Cancels an auction that has no bids. + * Can only be called by an account with the `ADMIN_ROLE`. + * The function marks the auction as ended by setting its `endTime` to the current block timestamp. + * + * @param auctionId Identifier of the auction to cancel. + */ + function cancel( + uint256 auctionId + ) external auctionExists(auctionId) auctionNotEnded(auctionId) withoutBuyer(auctionId) onlyRole(Roles.ADMIN_ROLE) { + AuctionHouseStorage.Layout storage $ = AuctionHouseStorage.layout(); + + // Mark the auction as ended by setting endTime to current timestamp + $.auction[auctionId].endTime = block.timestamp; - Distribution.distribute(USDC, _auction.price, _auction.participants, _auction.shares); + emit Cancelled(auctionId); } /** @@ -362,21 +404,34 @@ contract AuctionHouse is IAuctionHouse, EIP712Domain, RoleSystem, Authorization return false; } - /// @dev Internal helper that returns true if `auctionId`'s `endTime` is in the past. + /** + * @notice Internal helper that returns true if `auctionId`'s `endTime` is in the past. + * + * @param auctionId The ID of the auction to check. + * @return bool True if the auction has ended, false otherwise. + */ function _auctionEnded(uint256 auctionId) private view returns (bool) { AuctionHouseStorage.Layout storage $ = AuctionHouseStorage.layout(); return $.auction[auctionId].endTime <= block.timestamp; } - /// @dev Internal helper that checks whether an auction struct has been populated. + /** + * @notice Internal helper that checks whether an auction struct has been populated. + * @param auctionId The ID of the auction to check. + * @return bool True if the auction exists, false otherwise. + */ function _auctionExists(uint256 auctionId) private view returns (bool) { AuctionHouseStorage.Layout storage $ = AuctionHouseStorage.layout(); return $.auction[auctionId].endTime != 0; } - /// @dev Internal helper that returns true when an auction has a non-zero buyer. + /** + * @notice Internal helper that returns true when an auction has a non-zero buyer. + * @param auctionId The ID of the auction to check. + * @return bool True if the auction has a buyer, false otherwise. + */ function _auctionWithBuyer(uint256 auctionId) private view returns (bool) { AuctionHouseStorage.Layout storage $ = AuctionHouseStorage.layout(); diff --git a/contracts/auction-house/IAuctionHouse.sol b/contracts/auction-house/IAuctionHouse.sol index 740b2a6..fc3d834 100644 --- a/contracts/auction-house/IAuctionHouse.sol +++ b/contracts/auction-house/IAuctionHouse.sol @@ -33,9 +33,18 @@ interface IAuctionHouse { /** * @notice Emitted when {finish} successfully settles the auction. + * + * @param auctionId Identifier of the auction that was sold. */ event Sold(uint256 indexed auctionId); + /** + * @notice Emitted when an auction is cancelled. + * + * @param auctionId Identifier of the auction that was cancelled. + */ + event Cancelled(uint256 indexed auctionId); + /** * @notice Creates a new auction with parameters validated and authorized via * an EIP-712 signature. @@ -48,12 +57,12 @@ interface IAuctionHouse { /** * @notice Places the first bid on an auction that has no current bidder. */ - function raiseInitial(uint256 auctionId, uint256 price) external; + function raiseInitial(uint256 auctionId, uint256 newPrice) external payable; /** * @notice Places a bid higher than the current highest bid by at least `step`. */ - function raise(uint256 auctionId, uint256 price) external; + function raise(uint256 auctionId, uint256 newPrice) external payable; /** * @notice Finalizes the auction, mints the token to the highest bidder @@ -61,22 +70,28 @@ interface IAuctionHouse { */ function finish(uint256 auctionId) external; + /** + * @notice Cancels an auction. + */ + function cancel(uint256 auctionId) external; + /** * @notice Returns the full auction struct for `auctionId`. + * + * @param auctionId The ID of the auction to retrieve. */ function auction(uint256 auctionId) external view returns (Auction.Type memory); /** * @notice Indicates whether any active auction has reserved `tokenId`. + * + * @param tokenId The ID of the token to check. */ function tokenReserved(uint256 tokenId) external view returns (bool reserved); /// @dev Thrown when an action is attempted by an unauthorized account. error AuctionHouseUnauthorizedAccount(address account); - /// @dev Thrown when an empty string is supplied as `tokenURI`. - error AuctionHouseEmptyTokenURI(); - /// @dev Thrown when `price` provided is below minimum allowed. error AuctionHouseInvalidPrice(); @@ -89,6 +104,9 @@ interface IAuctionHouse { /// @dev Thrown when `endTime` is outside the permitted window. error AuctionHouseInvalidEndTime(); + /// @dev Thrown when a currency is invalid. + error AuctionHouseInvalidCurrency(); + /// @dev Thrown when the token is already reserved by an auction. error AuctionHouseTokenReserved(); diff --git a/contracts/auction-house/libraries/Auction.sol b/contracts/auction-house/libraries/Auction.sol index e698baa..2de18bc 100644 --- a/contracts/auction-house/libraries/Auction.sol +++ b/contracts/auction-house/libraries/Auction.sol @@ -19,6 +19,7 @@ library Auction { * @param tokenURI The metadata URI for the token. * @param participants The addresses of the participants in the revenue share. * @param shares The corresponding shares for each participant. + * @param currency The token used for payment. */ struct Type { uint256 tokenId; @@ -31,5 +32,6 @@ library Auction { string tokenURI; address[] participants; uint256[] shares; + address currency; } } diff --git a/contracts/auction-house/libraries/AuctionCreationPermit.sol b/contracts/auction-house/libraries/AuctionCreationPermit.sol index da00041..4356a18 100644 --- a/contracts/auction-house/libraries/AuctionCreationPermit.sol +++ b/contracts/auction-house/libraries/AuctionCreationPermit.sol @@ -16,6 +16,7 @@ library AuctionCreationPermit { * * @param auctionId The ID of the auction to be created. * @param tokenId The ID of the token to be auctioned. + * @param currency The token used for payment. * @param price The starting price of the auction. * @param fee The platform fee for the auction. * @param step The minimum bid increment for the auction. @@ -29,6 +30,7 @@ library AuctionCreationPermit { struct Type { uint256 auctionId; uint256 tokenId; + address currency; uint256 price; uint256 fee; uint256 step; @@ -47,6 +49,7 @@ library AuctionCreationPermit { "AuctionCreationPermit(" "uint256 auctionId," "uint256 tokenId," + "address currency," "uint256 price," "uint256 fee," "uint256 step," @@ -73,6 +76,7 @@ library AuctionCreationPermit { TYPE_HASH, permit.auctionId, permit.tokenId, + permit.currency, permit.price, permit.fee, permit.step, diff --git a/contracts/auction-house/libraries/ShareDistributor.sol b/contracts/auction-house/libraries/ShareDistributor.sol new file mode 100644 index 0000000..f1a7d75 --- /dev/null +++ b/contracts/auction-house/libraries/ShareDistributor.sol @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.20; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {SafeERC20BulkTransfer} from "../../utils/SafeERC20BulkTransfer.sol"; +import {ONE_HUNDRED_PERCENT_IN_BP} from "../../utils/Constants.sol"; + +/** + * @title ShareDistributor + * @notice A library for distributing a total amount of an ERC20 token among multiple participants + * based on specified shares. + */ +library ShareDistributor { + /** + * @notice Distributes a given amount of an ERC20 token to a list of participants. + * + * @dev Calculates rewards and uses {SafeERC20BulkTransfer} to transfer the amounts. + * + * @param currency The address of the ERC20 token to distribute. + * @param amount The total amount of the token to be distributed. + * @param participants An array of addresses for the recipients. + * @param shares An array of shares (in basis points) corresponding to each participant. + */ + function distribute( + address currency, + uint256 amount, + address[] memory participants, + uint256[] memory shares + ) internal { + uint256[] memory rewards = calculateRewards(amount, shares); + + SafeERC20BulkTransfer.safeTransfer( + IERC20(currency), + amount, + participants, + rewards // + ); + } + + /** + * @notice Calculates the individual reward amounts from a total amount based on shares. + * + * @dev The last participant receives the remaining amount to prevent loss from rounding errors. + * + * @param amount The total amount to be divided. + * @param shares An array of shares (in basis points). + * + * @return rewards An array of calculated reward amounts for each participant. + */ + function calculateRewards( + uint256 amount, + uint256[] memory shares + ) internal pure returns (uint256[] memory rewards) { + rewards = new uint256[](shares.length); + + uint256 lastIndex = shares.length - 1; + uint256 rewardsSum = 0; + + for (uint256 i = 0; i < lastIndex; ) { + uint256 value = Math.mulDiv(amount, shares[i], ONE_HUNDRED_PERCENT_IN_BP); + + rewardsSum += value; + + rewards[i] = value; + + unchecked { + i++; + } + } + + // calculates the last reward out of the loop not to lose wei after division + rewards[lastIndex] = amount - rewardsSum; + } + + /** + * @notice Validates the conditions for a share distribution. + * + * @dev Checks for correct array lengths, non-zero addresses, non-zero shares, and that the + * total shares sum up to 100%. + * + * @param participants An array of addresses for the recipients. + * @param shares An array of shares (in basis points). + */ + function requireValidConditions(address[] calldata participants, uint256[] calldata shares) internal pure { + uint256 participantsCount = participants.length; + + if (participantsCount != shares.length) { + revert ShareDistributorParticipantsSharesMismatch(); + } + + uint256 sharesSum = 0; + + for (uint256 i = 0; i < participantsCount; ) { + if (participants[i] == address(0)) { + revert ShareDistributorZeroAddress(); + } + + uint256 share = shares[i]; + + if (share == 0) { + revert ShareDistributorZeroShare(); + } + + sharesSum += share; + + unchecked { + i++; + } + } + + if (sharesSum != ONE_HUNDRED_PERCENT_IN_BP) { + revert ShareDistributorSharesSumInvalid(sharesSum); + } + } + + /// @dev Thrown when `participants.length != shares.length`. + error ShareDistributorParticipantsSharesMismatch(); + + /// @dev Thrown when a share value is zero. + error ShareDistributorZeroShare(); + + /// @dev Thrown when a participant address is zero. + error ShareDistributorZeroAddress(); + + /// @dev Thrown when `sum(shares) != ONE_HUNDRED_PERCENT_IN_BP`. + error ShareDistributorSharesSumInvalid(uint256 sharesSum); +} diff --git a/contracts/market/IMarket.sol b/contracts/market/IMarket.sol index 3f16a96..5cb715a 100644 --- a/contracts/market/IMarket.sol +++ b/contracts/market/IMarket.sol @@ -78,7 +78,7 @@ interface IMarket { OrderExecutionPermit.Type calldata permit, bytes calldata orderSignature, bytes calldata permitSignature - ) external; + ) external payable; /** * @notice Executes a buy-side order (bid). diff --git a/contracts/market/Market.sol b/contracts/market/Market.sol index e4d16cf..c1d7f66 100644 --- a/contracts/market/Market.sol +++ b/contracts/market/Market.sol @@ -50,7 +50,7 @@ contract Market is IMarket, EIP712Domain, RoleSystem, CurrencyManager, Authoriza OrderExecutionPermit.Type calldata permit, bytes calldata orderSignature, bytes calldata permitSignature - ) external { + ) external payable { if (order.side != Order.Side.Ask) { revert MarketInvalidOrderSide(); } diff --git a/contracts/tests/AllDeployer.sol b/contracts/tests/AllDeployer.sol index 3d78ad7..4d78be6 100644 --- a/contracts/tests/AllDeployer.sol +++ b/contracts/tests/AllDeployer.sol @@ -11,74 +11,67 @@ import {USDC} from "../tests/USDC.sol"; contract AllDeployer { event Deployed(address artToken, address auctionHouse, address market, address usdc); - constructor( - address signer, - address financier, - address admin, - uint256 minPrice, - uint256 minFee, - uint256 minAuctionDuration - ) { + constructor(address signer, address financier, address admin, uint256 minAuctionDuration) { address usdc = address(new USDC()); - address calculatedArtTokenProxy = Deployment.calculateContractAddress(address(this), 5); - address calculatedAuctionHouseProxy = Deployment.calculateContractAddress(address(this), 6); - address calculatedMarketProxy = Deployment.calculateContractAddress(address(this), 7); + address artTokenProxy = Deployment.calculateContractAddress(address(this), 5); + address auctionHouseProxy = Deployment.calculateContractAddress(address(this), 6); + address marketProxy = Deployment.calculateContractAddress(address(this), 7); { address artTokenImpl = address( new ArtToken( - calculatedArtTokenProxy, + artTokenProxy, address(this), - calculatedAuctionHouseProxy, - usdc, - minPrice, - minFee + auctionHouseProxy // ) ); address auctionHouseImpl = address( new AuctionHouse( - calculatedAuctionHouseProxy, + auctionHouseProxy, address(this), - calculatedArtTokenProxy, - usdc, - minAuctionDuration, - minPrice, - minFee + artTokenProxy, + minAuctionDuration // ) ); address marketImpl = address( new Market( - calculatedMarketProxy, + marketProxy, address(this) // ) ); - address artTokenProxy = Deployment.deployUpgradeableContract(artTokenImpl, address(this)); - address auctionHouseProxy = Deployment.deployUpgradeableContract(auctionHouseImpl, address(this)); - address marketProxy = Deployment.deployUpgradeableContract(marketImpl, address(this)); + address _artTokenProxy = Deployment.deployUpgradeableContract(artTokenImpl, address(this)); + address _auctionHouseProxy = Deployment.deployUpgradeableContract(auctionHouseImpl, address(this)); + address _marketProxy = Deployment.deployUpgradeableContract(marketImpl, address(this)); - if (artTokenProxy != calculatedArtTokenProxy) revert DeployerIncorrectAddress(); - if (auctionHouseProxy != calculatedAuctionHouseProxy) revert DeployerIncorrectAddress(); - if (marketProxy != calculatedMarketProxy) revert DeployerIncorrectAddress(); + if (_artTokenProxy != artTokenProxy) revert DeployerIncorrectAddress(); + if (_auctionHouseProxy != auctionHouseProxy) revert DeployerIncorrectAddress(); + if (_marketProxy != marketProxy) revert DeployerIncorrectAddress(); emit Deployed(artTokenProxy, auctionHouseProxy, marketProxy, usdc); } - ArtToken(calculatedArtTokenProxy).transferUniqueRole(Roles.SIGNER_ROLE, signer); - ArtToken(calculatedArtTokenProxy).transferUniqueRole(Roles.FINANCIAL_ROLE, financier); - ArtToken(calculatedArtTokenProxy).grantRole(Roles.PARTNER_ROLE, calculatedAuctionHouseProxy); - ArtToken(calculatedArtTokenProxy).grantRole(Roles.PARTNER_ROLE, calculatedMarketProxy); + ArtToken(artTokenProxy).transferUniqueRole(Roles.SIGNER_ROLE, signer); + ArtToken(artTokenProxy).transferUniqueRole(Roles.FINANCIAL_ROLE, financier); + ArtToken(artTokenProxy).grantRole(Roles.PARTNER_ROLE, auctionHouseProxy); + ArtToken(artTokenProxy).grantRole(Roles.PARTNER_ROLE, marketProxy); + ArtToken(artTokenProxy).grantRole(Roles.ADMIN_ROLE, address(this)); + ArtToken(artTokenProxy).updateCurrencyStatus(usdc, true); + if (admin != address(0)) ArtToken(artTokenProxy).grantRole(Roles.ADMIN_ROLE, admin); - AuctionHouse(calculatedAuctionHouseProxy).transferUniqueRole(Roles.FINANCIAL_ROLE, financier); - AuctionHouse(calculatedAuctionHouseProxy).transferUniqueRole(Roles.SIGNER_ROLE, signer); + AuctionHouse(auctionHouseProxy).transferUniqueRole(Roles.FINANCIAL_ROLE, financier); + AuctionHouse(auctionHouseProxy).transferUniqueRole(Roles.SIGNER_ROLE, signer); + AuctionHouse(auctionHouseProxy).grantRole(Roles.ADMIN_ROLE, address(this)); + AuctionHouse(auctionHouseProxy).updateCurrencyStatus(usdc, true); + if (admin != address(0)) AuctionHouse(auctionHouseProxy).grantRole(Roles.ADMIN_ROLE, admin); - Market(calculatedMarketProxy).transferUniqueRole(Roles.SIGNER_ROLE, signer); - Market(calculatedMarketProxy).transferUniqueRole(Roles.FINANCIAL_ROLE, financier); - if (admin != address(0)) Market(calculatedMarketProxy).grantRole(Roles.ADMIN_ROLE, admin); - Market(calculatedMarketProxy).grantRole(Roles.ADMIN_ROLE, address(this)); - Market(calculatedMarketProxy).updateCurrencyStatus(usdc, true); + Market(marketProxy).transferUniqueRole(Roles.SIGNER_ROLE, signer); + Market(marketProxy).transferUniqueRole(Roles.FINANCIAL_ROLE, financier); + Market(marketProxy).grantRole(Roles.ADMIN_ROLE, address(this)); + Market(marketProxy).updateCurrencyStatus(usdc, true); + if (admin != address(0)) Market(marketProxy).grantRole(Roles.ADMIN_ROLE, admin); } error DeployerIncorrectAddress(); diff --git a/contracts/utils/CollectionDeployer.sol b/contracts/utils/CollectionDeployer.sol index 64a2dc9..8f1ae0b 100644 --- a/contracts/utils/CollectionDeployer.sol +++ b/contracts/utils/CollectionDeployer.sol @@ -41,20 +41,9 @@ contract CollectionDeployer { * @param name ERC-721 collection name. * @param symbol ERC-721 collection symbol. * @param main Address that will be set as {RoleSystem.MAIN}. - * @param usdc Address of the USDC token contract. - * @param minPrice Global minimum primary-sale price. - * @param minFee Global minimum platform fee. * @param minAuctionDuration Minimum auction duration (seconds) enforced by AuctionHouse. */ - constructor( - string memory name, - string memory symbol, - address main, - address usdc, - uint256 minPrice, - uint256 minFee, - uint256 minAuctionDuration - ) { + constructor(string memory name, string memory symbol, address main, uint256 minAuctionDuration) { address calculatedArtTokenProxy = Deployment.calculateContractAddress(address(this), 3); address calculatedAuctionHouseProxy = Deployment.calculateContractAddress(address(this), 4); @@ -62,10 +51,7 @@ contract CollectionDeployer { new ArtToken( calculatedArtTokenProxy, main, - calculatedAuctionHouseProxy, - usdc, - minPrice, - minFee // + calculatedAuctionHouseProxy // ) ); @@ -74,10 +60,7 @@ contract CollectionDeployer { calculatedAuctionHouseProxy, main, calculatedArtTokenProxy, - usdc, - minAuctionDuration, - minPrice, - minFee + minAuctionDuration // ) ); diff --git a/contracts/utils/Constants.sol b/contracts/utils/Constants.sol new file mode 100644 index 0000000..079ce92 --- /dev/null +++ b/contracts/utils/Constants.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.20; + +/// @dev Special constant to represent native Ether currency. +address constant ETHER = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + +/// @dev Represents 100% in basis points (100.00%). +uint256 constant ONE_HUNDRED_PERCENT_IN_BP = 10_000; diff --git a/contracts/utils/Distribution.sol b/contracts/utils/Distribution.sol deleted file mode 100644 index c5cfe53..0000000 --- a/contracts/utils/Distribution.sol +++ /dev/null @@ -1,137 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity ^0.8.20; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; - -/** - * @title Distribution - * - * @notice Library for deterministic ERC-20 amount splitting. - * - * @dev Provides helpers to safely distribute `amount` among `participants` given a - * {TOTAL_SHARE}-denominated `shares` array (10,000 — i.e. basis points). - */ -library Distribution { - using SafeERC20 for IERC20; - - /** - * @dev Denominator used for share calculations (basis points). - */ - uint256 internal constant TOTAL_SHARE = 10_000; - - /** - * @notice Performs a validation pass and then distributes `amount` between `participants` - * according to `shares`. - * - * @dev Reverts with one of the custom errors declared at the bottom of the contract if - * validation fails. Uses {SafeERC20.safeTransfer} to guard against non-standard ERC-20s. - * - * @param currency ERC20 currency address. - * @param amount Amount to distribute. - * @param participants Addresses that will receive a portion of `amount`. - * @param shares Shares (in basis points) assigned to each participant. - */ - function safeDistribute( - IERC20 currency, - uint256 amount, - address[] memory participants, - uint256[] memory shares - ) internal { - requireValidConditions(participants, shares); - distribute(currency, amount, participants, shares); - } - - /** - * @notice Distributes `amount` between `participants` according to `shares`. - * - * @dev Performs **no** parameter validation — callers MUST ensure that {requireValidConditions} - * has been invoked prior to calling this function. - * - * @param currency ERC20 currency address. - * @param amount Amount to distribute. - * @param participants An array of participant addresses. - * @param shares An array of shares (in basis points) corresponding to each participant. - */ - function distribute( - IERC20 currency, - uint256 amount, - address[] memory participants, - uint256[] memory shares - ) internal { - uint256 lastIndex = participants.length - 1; - uint256 distributed = 0; - - for (uint256 i = 0; i < lastIndex; ) { - uint256 value = Math.mulDiv(amount, shares[i], TOTAL_SHARE); - - distributed += value; - - currency.safeTransfer(participants[i], value); - - unchecked { - i++; - } - } - - // calculates last share out of loop not to lose wei after division - currency.safeTransfer(participants[lastIndex], amount - distributed); - } - - /** - * @notice Validates distribution parameters. - * - * @dev Reverts with a custom error if: - * - `participants` and `shares` lengths mismatch; - * - Any participant is the zero address; - * - Any share is zero; - * - The sum of `shares` does not equal {TOTAL_SHARE}. - * - * @param participants An array of participant addresses. - * @param shares An array of shares (in basis points) corresponding to each participant. - */ - function requireValidConditions(address[] memory participants, uint256[] memory shares) internal pure { - uint256 participantsCount = participants.length; - - if (participantsCount != shares.length) { - revert DistributionParticipantsSharesMismatch(); - } - - uint256 sharesSum = 0; - - for (uint256 i = 0; i < participantsCount; ) { - if (participants[i] == address(0)) { - revert DistributionZeroAddress(); - } - - uint256 share = shares[i]; - - if (share == 0) { - revert DistributionZeroShare(); - } - - sharesSum += share; - - unchecked { - i++; - } - } - - if (sharesSum != TOTAL_SHARE) { - revert DistributionSharesSumInvalid(sharesSum); - } - } - - /// @dev Thrown when `participants.length != shares.length`. - error DistributionParticipantsSharesMismatch(); - - /// @dev Thrown when a share value is zero. - error DistributionZeroShare(); - - /// @dev Thrown when a participant address is zero. - error DistributionZeroAddress(); - - /// @dev Thrown when `sum(shares) != TOTAL_SHARE`. - error DistributionSharesSumInvalid(uint256 sharesSum); -} diff --git a/contracts/utils/SafeERC20BulkTransfer.sol b/contracts/utils/SafeERC20BulkTransfer.sol index 993ea2a..bbc9881 100644 --- a/contracts/utils/SafeERC20BulkTransfer.sol +++ b/contracts/utils/SafeERC20BulkTransfer.sol @@ -30,8 +30,8 @@ library SafeERC20BulkTransfer { function safeTransfer( IERC20 currency, uint256 amount, - address[] calldata receivers, - uint256[] calldata values + address[] memory receivers, + uint256[] memory values ) internal { uint256 receiversCount = receivers.length; diff --git a/hardhat.config.ts b/hardhat.config.ts index b6ea269..1d7ec1e 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -1,6 +1,5 @@ import fs from 'fs'; import yaml from 'js-yaml'; -import dotenv from 'dotenv'; import { parseEther } from 'ethers'; import '@nomicfoundation/hardhat-toolbox'; @@ -10,43 +9,24 @@ import './tasks'; import type { HardhatUserConfig } from 'hardhat/config'; import type { NetworksUserConfig } from 'hardhat/types'; import type { - ChainConfigTop, + ChainConfigYaml, CollectionConfig, - CollectionConfigTop, + CollectionConfigYaml, + EnvConfigYaml, MarketConfig, - MarketConfigTop, + MarketConfigYaml, ProtocolConfig, } from './types/environment'; -dotenv.config(); // TODO: Migrate params from `.env` to `config.env.yaml` - -const ENV_MODE = String(process.env.ENV_MODE); -const COLLECTION = <'do' | 'dn'>String(process.env.COLLECTION); -const CHAIN_TO_FORK = String(process.env.CHAIN_TO_FORK); -const FORKED_CHAIN = String(process.env.FORKED_CHAIN); -const FORKED_CHAIN_URL = String(process.env.FORKED_CHAIN_URL); -const FORKED_CHAIN_ID = Number(process.env.FORKED_CHAIN_ID); -const REPORT_GAS = Boolean(process.env.REPORT_GAS === 'true'); -const ETHERSCAN_API_KEY = String(process.env.ETHERSCAN_API_KEY); -const COINMARKETCAP_API_KEY = String(process.env.COINMARKETCAP_API_KEY); - -const chainConfigTop = yaml.load(fs.readFileSync('./config.env.yaml', 'utf8')); -const marketConfigTop = yaml.load(fs.readFileSync('./config.market.yaml', 'utf8')); -let collectionConfigTop: CollectionConfigTop; - -if (COLLECTION == 'do') { - collectionConfigTop = ( - yaml.load(fs.readFileSync('./config.do.yaml', 'utf8')) - ); -} else if (COLLECTION == 'dn') { - collectionConfigTop = ( - yaml.load(fs.readFileSync('./config.dn.yaml', 'utf8')) - ); -} else if (ENV_MODE === 'test') { - // skip -} else { - throw new Error(`Invalid 'COLLECTION' value: ${COLLECTION}`); -} +const envConfigYaml = yaml.load(fs.readFileSync('./config.env.yaml', 'utf8')); +const chainConfigYaml = yaml.load(fs.readFileSync('./config.chain.yaml', 'utf8')); + +const collectionConfigYaml = ( + yaml.load(fs.readFileSync('./config.collection.yaml', 'utf8')) +); +const marketConfigYaml = ( + yaml.load(fs.readFileSync('./config.market.yaml', 'utf8')) +); const hardhatBaseConfig: HardhatUserConfig = { solidity: { @@ -69,11 +49,11 @@ const hardhatBaseConfig: HardhatUserConfig = { artifacts: './artifacts', }, gasReporter: { - enabled: REPORT_GAS, + enabled: envConfigYaml.reportGas, token: 'eth', currency: 'usd', gasPrice: 10, - coinmarketcap: COINMARKETCAP_API_KEY, + coinmarketcap: envConfigYaml.coinmarketcapApiKey, }, }; @@ -86,27 +66,25 @@ const hardhatTestConfig: HardhatUserConfig = { }; const hardhatEtherscanConfig: HardhatUserConfig = { - etherscan: { apiKey: ETHERSCAN_API_KEY }, + etherscan: { apiKey: envConfigYaml.etherscanApiKey }, }; function buildHardhatConfig(): HardhatUserConfig { - if (ENV_MODE === 'test') { + if (String(process.env.ENV_MODE) === 'test') { return { ...hardhatBaseConfig, ...hardhatTestConfig }; } const hardhatNetworksConfig: NetworksUserConfig = {}; - for (const [chainName, chainConfig] of Object.entries(chainConfigTop)) { - const collectionConfig = collectionConfigTop[chainName]; - const marketConfig = marketConfigTop[chainName]; + for (const [chainName, chainConfig] of Object.entries(chainConfigYaml)) { + const collectionConfig = collectionConfigYaml[chainName]; + const marketConfig = marketConfigYaml[chainName]; - const { chainId, url, deployerPrivateKey, usdc, main } = chainConfig; + const { chainId, url, deployerPrivateKey, main } = chainConfig; const collection: CollectionConfig = { - name: collectionConfigTop.name, - symbol: collectionConfigTop.symbol, - minPriceUsd: collectionConfig.minPriceUsd, - minFeeUsd: collectionConfig.minFeeUsd, + name: collectionConfigYaml.name, + symbol: collectionConfigYaml.symbol, minAuctionDurationHours: collectionConfig.minAuctionDurationHours, artToken: collectionConfig.artToken, auctionHouse: collectionConfig.auctionHouse, @@ -118,7 +96,6 @@ function buildHardhatConfig(): HardhatUserConfig { const protocolConfig: ProtocolConfig = { main, - usdc, collection, market, }; @@ -131,20 +108,20 @@ function buildHardhatConfig(): HardhatUserConfig { }; } - if (FORKED_CHAIN_ID && FORKED_CHAIN_URL && FORKED_CHAIN) { + if (envConfigYaml.fork.name && envConfigYaml.fork.chainId && envConfigYaml.fork.url) { hardhatNetworksConfig['fork'] = { - ...hardhatNetworksConfig[FORKED_CHAIN], - chainId: FORKED_CHAIN_ID, - url: FORKED_CHAIN_URL, + ...hardhatNetworksConfig[envConfigYaml.fork.name], + chainId: envConfigYaml.fork.chainId, + url: envConfigYaml.fork.url, }; } - if (CHAIN_TO_FORK) { + if (envConfigYaml.fork.name) { hardhatNetworksConfig['hardhat'] = { - forking: { url: chainConfigTop[CHAIN_TO_FORK].url }, + forking: { url: chainConfigYaml[envConfigYaml.fork.name].url }, accounts: [ { - privateKey: chainConfigTop[CHAIN_TO_FORK].deployerPrivateKey, + privateKey: chainConfigYaml[envConfigYaml.fork.name].deployerPrivateKey, balance: parseEther('100').toString(), }, ], diff --git a/init.sh b/init.sh new file mode 100644 index 0000000..2ef226e --- /dev/null +++ b/init.sh @@ -0,0 +1,4 @@ +test -f config.env.yaml || cp config.env.example.yaml config.env.yaml && +test -f config.chain.yaml || cp config.chain.example.yaml config.chain.yaml && +test -f config.collection.yaml || cp config.collections.example.yaml config.collections.yaml && +test -f config.market.yaml || cp config.markets.example.yaml config.markets.yaml diff --git a/package-lock.json b/package-lock.json index b19c2ab..ae60b56 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,15 +13,14 @@ "@openzeppelin/contracts": "^5.0.2", "@openzeppelin/contracts-upgradeable": "^5.0.2", "@types/js-yaml": "^4.0.9", - "dotenv": "^16.5.0", - "ethers": "^6.15.0", - "hardhat": "^2.26.3", + "ethers": "^6.16.0", + "hardhat": "^2.28.0", "husky": "^9.1.7", - "js-yaml": "^4.1.0", - "lint-staged": "^16.1.2", - "prettier": "^3.6.0", - "prettier-plugin-solidity": "^2.0.0", - "solhint": "^5.1.0" + "js-yaml": "^4.1.1", + "lint-staged": "^16.2.7", + "prettier": "^3.7.4", + "prettier-plugin-solidity": "^2.2.1", + "solhint": "^6.0.2" } }, "node_modules/@adraffy/ens-normalize": { @@ -30,42 +29,32 @@ "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==" }, "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@bytecodealliance/preview2-shim": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.2.tgz", - "integrity": "sha512-mNm/lblgES8UkVle8rGImXOz4TtL3eU3inHay/7TVchkKrb/lgcVvTK0+VAw8p5zQ0rgQsXm1j5dOlAAd+MeoA==", + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.5.tgz", + "integrity": "sha512-F4WYVC6aHOiOXSsG3WDGFALrkpb952+9/EIX119qIzDtYgE5tvbOnKeBb0Y+NMzGEsu3334GdHIRXQ6wibY0MA==", "license": "(Apache-2.0 WITH LLVM-exception)" }, "node_modules/@cspotcode/source-map-support": { @@ -564,6 +553,15 @@ "node": ">=14" } }, + "node_modules/@humanwhocodes/momoa": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@humanwhocodes/momoa/-/momoa-2.0.4.tgz", + "integrity": "sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.10.0" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -774,84 +772,84 @@ } }, "node_modules/@nomicfoundation/edr": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.11.3.tgz", - "integrity": "sha512-kqILRkAd455Sd6v8mfP3C1/0tCOynJWY+Ir+k/9Boocu2kObCrsFgG+ZWB7fSBVdd9cPVSNrnhWS+V+PEo637g==", + "version": "0.12.0-next.17", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.12.0-next.17.tgz", + "integrity": "sha512-Y8Kwqd5JpBmI/Kst6NJ/bZ81FeJea9J6WEwoSRTZnEvwfqW9dk9PI8zJs2UJpOACL1fXEPvN+doETbxT9EhwXA==", "license": "MIT", "dependencies": { - "@nomicfoundation/edr-darwin-arm64": "0.11.3", - "@nomicfoundation/edr-darwin-x64": "0.11.3", - "@nomicfoundation/edr-linux-arm64-gnu": "0.11.3", - "@nomicfoundation/edr-linux-arm64-musl": "0.11.3", - "@nomicfoundation/edr-linux-x64-gnu": "0.11.3", - "@nomicfoundation/edr-linux-x64-musl": "0.11.3", - "@nomicfoundation/edr-win32-x64-msvc": "0.11.3" + "@nomicfoundation/edr-darwin-arm64": "0.12.0-next.17", + "@nomicfoundation/edr-darwin-x64": "0.12.0-next.17", + "@nomicfoundation/edr-linux-arm64-gnu": "0.12.0-next.17", + "@nomicfoundation/edr-linux-arm64-musl": "0.12.0-next.17", + "@nomicfoundation/edr-linux-x64-gnu": "0.12.0-next.17", + "@nomicfoundation/edr-linux-x64-musl": "0.12.0-next.17", + "@nomicfoundation/edr-win32-x64-msvc": "0.12.0-next.17" }, "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@nomicfoundation/edr-darwin-arm64": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.11.3.tgz", - "integrity": "sha512-w0tksbdtSxz9nuzHKsfx4c2mwaD0+l5qKL2R290QdnN9gi9AV62p9DHkOgfBdyg6/a6ZlnQqnISi7C9avk/6VA==", + "version": "0.12.0-next.17", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.12.0-next.17.tgz", + "integrity": "sha512-gI9/9ysLeAid0+VSTBeutxOJ0/Rrh00niGkGL9+4lR577igDY+v55XGN0oBMST49ILS0f12J6ZY90LG8sxPXmQ==", "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@nomicfoundation/edr-darwin-x64": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.11.3.tgz", - "integrity": "sha512-QR4jAFrPbOcrO7O2z2ESg+eUeIZPe2bPIlQYgiJ04ltbSGW27FblOzdd5+S3RoOD/dsZGKAvvy6dadBEl0NgoA==", + "version": "0.12.0-next.17", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.12.0-next.17.tgz", + "integrity": "sha512-zSZtwf584RkIyb8awELDt7ctskogH0p4pmqOC4vhykc8ODOv2XLuG1IgeE4WgYhWGZOufbCtgLfpJQrWqN6mmw==", "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.11.3.tgz", - "integrity": "sha512-Ktjv89RZZiUmOFPspuSBVJ61mBZQ2+HuLmV67InNlh9TSUec/iDjGIwAn59dx0bF/LOSrM7qg5od3KKac4LJDQ==", + "version": "0.12.0-next.17", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.12.0-next.17.tgz", + "integrity": "sha512-WjdfgV6B7gT5Q0NXtSIWyeK8gzaJX5HK6/jclYVHarWuEtS1LFgePYgMjK8rmm7IRTkM9RsE/PCuQEP1nrSsuA==", "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@nomicfoundation/edr-linux-arm64-musl": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.11.3.tgz", - "integrity": "sha512-B3sLJx1rL2E9pfdD4mApiwOZSrX0a/KQSBWdlq1uAhFKqkl00yZaY4LejgZndsJAa4iKGQJlGnw4HCGeVt0+jA==", + "version": "0.12.0-next.17", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.12.0-next.17.tgz", + "integrity": "sha512-26rObKhhCDb9JkZbToyr7JVZo4tSVAFvzoJSJVmvpOl0LOHrfFsgVQu2n/8cNkwMAqulPubKL2E0jdnmEoZjWA==", "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@nomicfoundation/edr-linux-x64-gnu": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.11.3.tgz", - "integrity": "sha512-D/4cFKDXH6UYyKPu6J3Y8TzW11UzeQI0+wS9QcJzjlrrfKj0ENW7g9VihD1O2FvXkdkTjcCZYb6ai8MMTCsaVw==", + "version": "0.12.0-next.17", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.12.0-next.17.tgz", + "integrity": "sha512-dPkHScIf/CU6h6k3k4HNUnQyQcVSLKanviHCAcs5HkviiJPxvVtOMMvtNBxoIvKZRxGFxf2eutcqQW4ZV1wRQQ==", "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@nomicfoundation/edr-linux-x64-musl": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.11.3.tgz", - "integrity": "sha512-ergXuIb4nIvmf+TqyiDX5tsE49311DrBky6+jNLgsGDTBaN1GS3OFwFS8I6Ri/GGn6xOaT8sKu3q7/m+WdlFzg==", + "version": "0.12.0-next.17", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.12.0-next.17.tgz", + "integrity": "sha512-5Ixe/bpyWZxC3AjIb8EomAOK44ajemBVx/lZRHZiWSBlwQpbSWriYAtKjKcReQQPwuYVjnFpAD2AtuCvseIjHw==", "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@nomicfoundation/edr-win32-x64-msvc": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.11.3.tgz", - "integrity": "sha512-snvEf+WB3OV0wj2A7kQ+ZQqBquMcrozSLXcdnMdEl7Tmn+KDCbmFKBt3Tk0X3qOU4RKQpLPnTxdM07TJNVtung==", + "version": "0.12.0-next.17", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.12.0-next.17.tgz", + "integrity": "sha512-29YlvdgofSdXG1mUzIuH4kMXu1lmVc1hvYWUGWEH59L+LaakdhfJ/Wu5izeclKkrTh729Amtk/Hk1m29kFOO8A==", "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@nomicfoundation/hardhat-chai-matchers": { @@ -1150,12 +1148,12 @@ "peer": true }, "node_modules/@nomicfoundation/slang": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/slang/-/slang-1.1.0.tgz", - "integrity": "sha512-g2BofMUq1qCP22L/ksOftScrCxjdHTxgg8ch5PYon2zfSSKGCMwE4TgIC64CuorMcSsvCmqNNFEWR/fwFcMeTw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang/-/slang-1.3.1.tgz", + "integrity": "sha512-gh0+JDjazmevEYCcwVgtuyfBJcV1209gIORZNRjUxbGzbQN0MOhQO9T0ptkzHKCf854gUy27SMxPbAyAu63fvQ==", "license": "MIT", "dependencies": { - "@bytecodealliance/preview2-shim": "0.17.2" + "@bytecodealliance/preview2-shim": "^0.17.2" } }, "node_modules/@nomicfoundation/solidity-analyzer": { @@ -1575,9 +1573,9 @@ } }, "node_modules/@solidity-parser/parser": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.20.1.tgz", - "integrity": "sha512-58I2sRpzaQUN+jJmWbHfbWf9AKfzqCI8JAdFB0vbyY+u8tBRcuTt9LxzasvR0LGQpcRv97eyV7l61FQ3Ib7zVw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.20.2.tgz", + "integrity": "sha512-rbu0bzwNvMcwAjH86hiEAcOeRI2EeK8zCkHDrFykh/Al8mvJeFmjy3UrE7GYQjNwOgbGUUtCn5/k8CB8zIu7QA==", "license": "MIT" }, "node_modules/@szmarczak/http-timer": { @@ -1839,6 +1837,15 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "license": "MIT", + "peerDependencies": { + "ajv": ">=5.0.0" + } + }, "node_modules/ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", @@ -1881,6 +1888,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "peer": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -2025,6 +2033,95 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/better-ajv-errors": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/better-ajv-errors/-/better-ajv-errors-2.0.2.tgz", + "integrity": "sha512-1cLrJXEq46n0hjV8dDYwg9LKYjDb3KbeW7nZTv4kvfoDD9c2DXHIE31nxM+Y/cIfXMggLUfmxbm6h/JoM/yotA==", + "license": "Apache-2.0", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@humanwhocodes/momoa": "^2.0.4", + "chalk": "^4.1.2", + "jsonpointer": "^5.0.1", + "leven": "^3.1.0 < 4" + }, + "engines": { + "node": ">= 18.20.6" + }, + "peerDependencies": { + "ajv": "4.11.8 - 8" + } + }, + "node_modules/better-ajv-errors/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/better-ajv-errors/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/better-ajv-errors/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/better-ajv-errors/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/better-ajv-errors/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/better-ajv-errors/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -2391,6 +2488,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "peer": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -2519,25 +2617,25 @@ } }, "node_modules/cli-truncate": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", - "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz", + "integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==", "license": "MIT", "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^7.0.0" + "slice-ansi": "^7.1.0", + "string-width": "^8.0.0" }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -2547,9 +2645,9 @@ } }, "node_modules/cli-truncate/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", "engines": { "node": ">=12" @@ -2558,61 +2656,57 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/cli-truncate/node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "license": "MIT" - }, "node_modules/cli-truncate/node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cli-truncate/node_modules/slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", "license": "MIT", "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, "node_modules/cli-truncate/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", + "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", "license": "MIT", "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", + "get-east-asian-width": "^1.3.0", "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cli-truncate/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -2638,6 +2732,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "peer": true, "dependencies": { "color-name": "1.1.3" } @@ -2645,7 +2740,8 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "peer": true }, "node_modules/colorette": { "version": "2.0.20", @@ -3014,18 +3110,6 @@ "node": ">=8" } }, - "node_modules/dotenv": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", - "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -3175,6 +3259,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "peer": true, "engines": { "node": ">=0.8.0" } @@ -3283,9 +3368,9 @@ } }, "node_modules/ethers": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.15.0.tgz", - "integrity": "sha512-Kf/3ZW54L4UT0pZtsY/rf+EkBU7Qi5nnhonjUb8yTXcxH3cdcWrV2cRyk0Xk/4jK6OoHhxxZHriyhje20If2hQ==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.16.0.tgz", + "integrity": "sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==", "funding": [ { "type": "individual", @@ -3574,9 +3659,9 @@ } }, "node_modules/get-east-asian-width": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", - "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", "license": "MIT", "engines": { "node": ">=18" @@ -3807,14 +3892,14 @@ } }, "node_modules/hardhat": { - "version": "2.26.3", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.26.3.tgz", - "integrity": "sha512-gBfjbxCCEaRgMCRgTpjo1CEoJwqNPhyGMMVHYZJxoQ3LLftp2erSVf8ZF6hTQC0r2wst4NcqNmLWqMnHg1quTw==", + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.28.0.tgz", + "integrity": "sha512-A3yBISI18EcnY2IR7Ny2xZF33Q3qH01yrWapeWbyGOiJm/386SasWjbHRHYgUlZ3YWJETIMh7wYfMUaXrofTDQ==", "license": "MIT", "dependencies": { "@ethereumjs/util": "^9.1.0", "@ethersproject/abi": "^5.1.2", - "@nomicfoundation/edr": "^0.11.3", + "@nomicfoundation/edr": "0.12.0-next.17", "@nomicfoundation/solidity-analyzer": "^0.1.0", "@sentry/node": "^5.18.1", "adm-zip": "^0.4.16", @@ -4319,6 +4404,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "peer": true, "engines": { "node": ">=4" } @@ -4750,12 +4836,13 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -4819,6 +4906,15 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/jsonschema": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", @@ -4883,6 +4979,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -4896,38 +5001,24 @@ "node": ">= 0.8.0" } }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/lint-staged": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.1.2.tgz", - "integrity": "sha512-sQKw2Si2g9KUZNY3XNvRuDq4UJqpHwF0/FQzZR2M7I5MvtpWvibikCjUVJzZdGE0ByurEl3KQNvsGetd1ty1/Q==", + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz", + "integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==", "license": "MIT", "dependencies": { - "chalk": "^5.4.1", - "commander": "^14.0.0", - "debug": "^4.4.1", - "lilconfig": "^3.1.3", - "listr2": "^8.3.3", + "commander": "^14.0.2", + "listr2": "^9.0.5", "micromatch": "^4.0.8", - "nano-spawn": "^1.0.2", + "nano-spawn": "^2.0.0", "pidtree": "^0.6.0", "string-argv": "^0.3.2", - "yaml": "^2.8.0" + "yaml": "^2.8.1" }, "bin": { "lint-staged": "bin/lint-staged.js" @@ -4939,33 +5030,22 @@ "url": "https://opencollective.com/lint-staged" } }, - "node_modules/lint-staged/node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/lint-staged/node_modules/commander": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.0.tgz", - "integrity": "sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", "license": "MIT", "engines": { "node": ">=20" } }, "node_modules/listr2": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", - "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", "license": "MIT", "dependencies": { - "cli-truncate": "^4.0.0", + "cli-truncate": "^5.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.1.0", @@ -4973,13 +5053,13 @@ "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } }, "node_modules/listr2/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -4989,9 +5069,9 @@ } }, "node_modules/listr2/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", "engines": { "node": ">=12" @@ -5001,9 +5081,9 @@ } }, "node_modules/listr2/node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "license": "MIT" }, "node_modules/listr2/node_modules/string-width": { @@ -5024,9 +5104,9 @@ } }, "node_modules/listr2/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -5039,9 +5119,9 @@ } }, "node_modules/listr2/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", @@ -5199,9 +5279,9 @@ } }, "node_modules/log-update/node_modules/ansi-escapes": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", - "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", + "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", "license": "MIT", "dependencies": { "environment": "^1.0.0" @@ -5214,9 +5294,9 @@ } }, "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -5226,9 +5306,9 @@ } }, "node_modules/log-update/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", "engines": { "node": ">=12" @@ -5238,18 +5318,18 @@ } }, "node_modules/log-update/node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "license": "MIT" }, "node_modules/log-update/node_modules/is-fullwidth-code-point": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", - "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", "license": "MIT", "dependencies": { - "get-east-asian-width": "^1.0.0" + "get-east-asian-width": "^1.3.1" }, "engines": { "node": ">=18" @@ -5259,9 +5339,9 @@ } }, "node_modules/log-update/node_modules/slice-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", - "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", @@ -5292,9 +5372,9 @@ } }, "node_modules/log-update/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -5307,9 +5387,9 @@ } }, "node_modules/log-update/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", @@ -5714,9 +5794,9 @@ "license": "MIT" }, "node_modules/nano-spawn": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-1.0.2.tgz", - "integrity": "sha512-21t+ozMQDAL/UGgQVBbZ/xXvNO10++ZPuTmKRO8k9V3AClVRht49ahtDjfY8l1q6nSHOrE5ASfthzH3ol6R/hg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz", + "integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==", "license": "MIT", "engines": { "node": ">=20.17" @@ -6317,9 +6397,9 @@ } }, "node_modules/prettier": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.0.tgz", - "integrity": "sha512-ujSB9uXHJKzM/2GBuE0hBOUgC77CN3Bnpqa+g80bkv3T3A93wL/xlzDATHhnhkzifz/UE2SNOvmbTz5hSkDlHw==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", + "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" @@ -6332,26 +6412,27 @@ } }, "node_modules/prettier-plugin-solidity": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-2.0.0.tgz", - "integrity": "sha512-tis3SwLSrYKDzzRFle48fjPM4GQKBtkVBUajAkt4b75/cc6zojFP7qjz6fDxKfup+34q0jKeSM3QeP9flJFXWw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-2.2.1.tgz", + "integrity": "sha512-LOHfxECJ/gHsY7qi4D7vanz8cVsCf6yFotBapJ5O0qaX0ZR1sGUzbWfMd4JeQYOItFl+wXW9IcjZOdfr6bmSvQ==", "license": "MIT", "dependencies": { - "@nomicfoundation/slang": "1.1.0", - "@solidity-parser/parser": "^0.20.1", - "semver": "^7.7.1" + "@nomicfoundation/slang": "1.3.1", + "@solidity-parser/parser": "^0.20.2", + "semver": "^7.7.3" }, "engines": { - "node": ">=18" + "node": ">=20" }, "peerDependencies": { "prettier": ">=3.0.0" } }, "node_modules/prettier-plugin-solidity/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -7067,15 +7148,17 @@ } }, "node_modules/solhint": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.1.0.tgz", - "integrity": "sha512-KWg4gnOnznxHXzH0fUvnhnxnk+1R50GiPChcPeQgA7SKQTSF1LLIEh8R1qbkCEn/fFzz4CfJs+Gh7Rl9uhHy+g==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-6.0.2.tgz", + "integrity": "sha512-RInN0tz9FVR4eYlyLS0Pk8iJP3WdfVmmMJR9FIUxe9bKHgAPE8OYUXcMd5PGi5fO5BnZw32e0qMYcJZgH9MiBg==", "license": "MIT", "dependencies": { - "@solidity-parser/parser": "^0.20.0", + "@solidity-parser/parser": "^0.20.2", "ajv": "^6.12.6", + "ajv-errors": "^1.0.1", "antlr4": "^4.13.1-patch-1", "ast-parents": "^0.0.1", + "better-ajv-errors": "^2.0.2", "chalk": "^4.1.2", "commander": "^10.0.0", "cosmiconfig": "^8.0.0", @@ -7087,7 +7170,6 @@ "lodash": "^4.17.21", "pluralize": "^8.0.0", "semver": "^7.5.2", - "strip-ansi": "^6.0.1", "table": "^6.8.1", "text-table": "^0.2.0" }, @@ -7537,6 +7619,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "peer": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -8487,15 +8570,18 @@ } }, "node_modules/yaml": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", - "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yargs": { diff --git a/package.json b/package.json index 3713e14..3881e19 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "fork": "hardhat node", "lint": "solhint 'contracts/**'", "format": "prettier --write .", - "prepare": "husky && test -f config.env.yaml || cp config.env.example.yaml config.env.yaml", + "prepare": "husky && source ./init.sh", "est": "docker run -it --rm -v $PWD:/src trailofbits/eth-security-toolbox", "slither": "ENV_MODE=test slither ./ --config-file ./slither.config.json" }, @@ -17,14 +17,13 @@ "@openzeppelin/contracts": "^5.0.2", "@openzeppelin/contracts-upgradeable": "^5.0.2", "@types/js-yaml": "^4.0.9", - "dotenv": "^16.5.0", - "ethers": "^6.15.0", - "hardhat": "^2.26.3", + "ethers": "^6.16.0", + "hardhat": "^2.28.0", "husky": "^9.1.7", - "js-yaml": "^4.1.0", - "lint-staged": "^16.1.2", - "prettier": "^3.6.0", - "prettier-plugin-solidity": "^2.0.0", - "solhint": "^5.1.0" + "js-yaml": "^4.1.1", + "lint-staged": "^16.2.7", + "prettier": "^3.7.4", + "prettier-plugin-solidity": "^2.2.1", + "solhint": "^6.0.2" } } diff --git a/requirements.txt b/requirements.txt index b19225e..9377a4c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,46 +1,46 @@ aiohappyeyeballs==2.6.1 -aiohttp==3.12.13 -aiosignal==1.3.2 +aiohttp==3.13.2 +aiosignal==1.4.0 annotated-types==0.7.0 -attrs==25.3.0 -bitarray==3.4.3 -cbor2==5.6.5 -certifi==2025.6.15 -charset-normalizer==3.4.2 -ckzg==2.1.1 -crytic-compile==0.3.10 -cytoolz==1.0.1 +attrs==25.4.0 +bitarray==3.8.0 +cbor2==5.7.1 +certifi==2025.11.12 +charset-normalizer==3.4.4 +ckzg==2.1.5 +crytic-compile==0.3.11 +cytoolz==1.1.0 eth-account==0.13.7 eth-hash==0.7.1 eth-keyfile==0.8.1 eth-keys==0.7.0 eth-rlp==2.2.0 eth-typing==5.2.1 -eth-utils==5.3.0 +eth-utils==5.3.1 eth_abi==5.2.0 -frozenlist==1.7.0 +frozenlist==1.8.0 hexbytes==1.3.1 -idna==3.10 -multidict==6.5.0 +idna==3.11 +multidict==6.7.0 packaging==25.0 parsimonious==0.10.0 -prettytable==3.16.0 -propcache==0.3.2 +prettytable==3.17.0 +propcache==0.4.1 pycryptodome==3.23.0 -pydantic==2.11.7 -pydantic_core==2.33.2 -pyunormalize==16.0.0 -regex==2024.11.6 -requests==2.32.4 +pydantic==2.12.4 +pydantic_core==2.41.5 +pyunormalize==17.0.0 +regex==2025.11.3 +requests==2.32.5 rlp==4.1.0 slither-analyzer==0.11.3 solc-select==1.1.0 -toolz==1.0.0 -types-requests==2.32.4.20250611 -typing-inspection==0.4.1 -typing_extensions==4.14.0 +toolz==1.1.0 +types-requests==2.32.4.20250913 +typing-inspection==0.4.2 +typing_extensions==4.15.0 urllib3==2.5.0 -wcwidth==0.2.13 -web3==7.12.0 +wcwidth==0.2.14 +web3==7.14.0 websockets==15.0.1 -yarl==1.20.1 +yarl==1.22.0 diff --git a/scripts/deploy-collection.ts b/scripts/deploy-collection.ts index 516deab..74eb6c4 100644 --- a/scripts/deploy-collection.ts +++ b/scripts/deploy-collection.ts @@ -11,9 +11,6 @@ type Params = { name: string; symbol: string; main: AddressLike; - usdc: AddressLike; - minPrice: Numeric; - minFee: Numeric; minAuctionDuration: number; }; @@ -25,16 +22,13 @@ export async function deployCollection(params: Params, deployer?: Signer) { name, symbol, main, - usdc, - minPrice, - minFee, minAuctionDuration, } = params; const { receipt } = await deploy( { name: 'CollectionDeployer', - constructorArgs: [name, symbol, main, usdc, minPrice, minFee, minAuctionDuration], + constructorArgs: [name, symbol, main, minAuctionDuration], }, deployer, ); diff --git a/slither.db.json b/slither.db.json index 021d6cc..d32c7d0 100644 --- a/slither.db.json +++ b/slither.db.json @@ -5,13 +5,13 @@ "type": "function", "name": "auctionExists", "source_mapping": { - "start": 2155, + "start": 1914, "length": 183, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, - "lines": [49, 50, 51, 52, 53, 54, 55], + "lines": [40, 41, 42, 43, 44, 45, 46], "starting_column": 5, "ending_column": 6 }, @@ -20,81 +20,92 @@ "type": "contract", "name": "AuctionHouse", "source_mapping": { - "start": 1182, - "length": 12390, + "start": 1272, + "length": 13404, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, "lines": [ - 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, - 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, - 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, - 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, - 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, - 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, - 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, - 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, - 326, 327, 328, 329, 330, - 331, 332, 333, 334, 335, - 336, 337, 338, 339, 340, - 341, 342, 343, 344, 345, - 346, 347, 348, 349, 350, - 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, - 361, 362, 363, 364, 365, - 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, - 381, 382, 383, 384, 385 + 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, + 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, + 322, 323, 324, 325, 326, + 327, 328, 329, 330, 331, + 332, 333, 334, 335, 336, + 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, + 347, 348, 349, 350, 351, + 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, + 362, 363, 364, 365, 366, + 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, + 382, 383, 384, 385, 386, + 387, 388, 389, 390, 391, + 392, 393, 394, 395, 396, + 397, 398, 399, 400, 401, + 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, + 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, + 422, 423, 424, 425, 426, + 427, 428, 429, 430, 431, + 432, 433, 434, 435, 436, + 437, 438, 439, 440 ], "starting_column": 1, "ending_column": 2 @@ -104,9 +115,9 @@ } } ], - "description": "Modifier AuctionHouse.auctionExists(uint256) (contracts/auction-house/AuctionHouse.sol#49-55) does not always execute _; or revert\n", - "markdown": "Modifier [AuctionHouse.auctionExists(uint256)](contracts/auction-house/AuctionHouse.sol#L49-L55) does not always execute _; or revert\n", - "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L49-L55", + "description": "Modifier AuctionHouse.auctionExists(uint256) (contracts/auction-house/AuctionHouse.sol#40-46) does not always execute _; or revert\n", + "markdown": "Modifier [AuctionHouse.auctionExists(uint256)](contracts/auction-house/AuctionHouse.sol#L40-L46) does not always execute _; or revert\n", + "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L40-L46", "id": "df77d86e81ab2e43df564de9204b5e212fdb053cced7d8363e9cf429b00d05c3", "check": "incorrect-modifier", "impact": "Low", @@ -118,13 +129,13 @@ "type": "function", "name": "auctionEnded", "source_mapping": { - "start": 2801, + "start": 2560, "length": 180, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, - "lines": [69, 70, 71, 72, 73, 74, 75], + "lines": [60, 61, 62, 63, 64, 65, 66], "starting_column": 5, "ending_column": 6 }, @@ -133,81 +144,92 @@ "type": "contract", "name": "AuctionHouse", "source_mapping": { - "start": 1182, - "length": 12390, + "start": 1272, + "length": 13404, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, "lines": [ - 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, - 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, - 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, - 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, - 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, - 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, - 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, - 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, - 326, 327, 328, 329, 330, - 331, 332, 333, 334, 335, - 336, 337, 338, 339, 340, - 341, 342, 343, 344, 345, - 346, 347, 348, 349, 350, - 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, - 361, 362, 363, 364, 365, - 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, - 381, 382, 383, 384, 385 + 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, + 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, + 322, 323, 324, 325, 326, + 327, 328, 329, 330, 331, + 332, 333, 334, 335, 336, + 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, + 347, 348, 349, 350, 351, + 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, + 362, 363, 364, 365, 366, + 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, + 382, 383, 384, 385, 386, + 387, 388, 389, 390, 391, + 392, 393, 394, 395, 396, + 397, 398, 399, 400, 401, + 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, + 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, + 422, 423, 424, 425, 426, + 427, 428, 429, 430, 431, + 432, 433, 434, 435, 436, + 437, 438, 439, 440 ], "starting_column": 1, "ending_column": 2 @@ -217,9 +239,9 @@ } } ], - "description": "Modifier AuctionHouse.auctionEnded(uint256) (contracts/auction-house/AuctionHouse.sol#69-75) does not always execute _; or revert\n", - "markdown": "Modifier [AuctionHouse.auctionEnded(uint256)](contracts/auction-house/AuctionHouse.sol#L69-L75) does not always execute _; or revert\n", - "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L69-L75", + "description": "Modifier AuctionHouse.auctionEnded(uint256) (contracts/auction-house/AuctionHouse.sol#60-66) does not always execute _; or revert\n", + "markdown": "Modifier [AuctionHouse.auctionEnded(uint256)](contracts/auction-house/AuctionHouse.sol#L60-L66) does not always execute _; or revert\n", + "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L60-L66", "id": "231e15bbc53bb317ba18ba7a532fc08f0aeab95b6e8a391e84eefe681b37b13e", "check": "incorrect-modifier", "impact": "Low", @@ -231,13 +253,13 @@ "type": "function", "name": "withBuyer", "source_mapping": { - "start": 3458, + "start": 3217, "length": 180, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, - "lines": [89, 90, 91, 92, 93, 94, 95], + "lines": [80, 81, 82, 83, 84, 85, 86], "starting_column": 5, "ending_column": 6 }, @@ -246,81 +268,92 @@ "type": "contract", "name": "AuctionHouse", "source_mapping": { - "start": 1182, - "length": 12390, + "start": 1272, + "length": 13404, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, "lines": [ - 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, - 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, - 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, - 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, - 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, - 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, - 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, - 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, - 326, 327, 328, 329, 330, - 331, 332, 333, 334, 335, - 336, 337, 338, 339, 340, - 341, 342, 343, 344, 345, - 346, 347, 348, 349, 350, - 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, - 361, 362, 363, 364, 365, - 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, - 381, 382, 383, 384, 385 + 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, + 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, + 322, 323, 324, 325, 326, + 327, 328, 329, 330, 331, + 332, 333, 334, 335, 336, + 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, + 347, 348, 349, 350, 351, + 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, + 362, 363, 364, 365, 366, + 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, + 382, 383, 384, 385, 386, + 387, 388, 389, 390, 391, + 392, 393, 394, 395, 396, + 397, 398, 399, 400, 401, + 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, + 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, + 422, 423, 424, 425, 426, + 427, 428, 429, 430, 431, + 432, 433, 434, 435, 436, + 437, 438, 439, 440 ], "starting_column": 1, "ending_column": 2 @@ -330,9 +363,9 @@ } } ], - "description": "Modifier AuctionHouse.withBuyer(uint256) (contracts/auction-house/AuctionHouse.sol#89-95) does not always execute _; or revert\n", - "markdown": "Modifier [AuctionHouse.withBuyer(uint256)](contracts/auction-house/AuctionHouse.sol#L89-L95) does not always execute _; or revert\n", - "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L89-L95", + "description": "Modifier AuctionHouse.withBuyer(uint256) (contracts/auction-house/AuctionHouse.sol#80-86) does not always execute _; or revert\n", + "markdown": "Modifier [AuctionHouse.withBuyer(uint256)](contracts/auction-house/AuctionHouse.sol#L80-L86) does not always execute _; or revert\n", + "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L80-L86", "id": "128d5b812b57359a56062cf3a9b43628ab98d0de6b09df9fdaa3697aefe12bc7", "check": "incorrect-modifier", "impact": "Low", @@ -344,14 +377,14 @@ "type": "function", "name": "authorizedBuyer", "source_mapping": { - "start": 4121, + "start": 3880, "length": 206, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, "lines": [ - 109, 110, 111, 112, 113, 114, 115 + 100, 101, 102, 103, 104, 105, 106 ], "starting_column": 5, "ending_column": 6 @@ -361,81 +394,92 @@ "type": "contract", "name": "AuctionHouse", "source_mapping": { - "start": 1182, - "length": 12390, + "start": 1272, + "length": 13404, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, "lines": [ - 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, - 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, - 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, - 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, - 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, - 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, - 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, - 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, - 326, 327, 328, 329, 330, - 331, 332, 333, 334, 335, - 336, 337, 338, 339, 340, - 341, 342, 343, 344, 345, - 346, 347, 348, 349, 350, - 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, - 361, 362, 363, 364, 365, - 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, - 381, 382, 383, 384, 385 + 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, + 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, + 322, 323, 324, 325, 326, + 327, 328, 329, 330, 331, + 332, 333, 334, 335, 336, + 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, + 347, 348, 349, 350, 351, + 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, + 362, 363, 364, 365, 366, + 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, + 382, 383, 384, 385, 386, + 387, 388, 389, 390, 391, + 392, 393, 394, 395, 396, + 397, 398, 399, 400, 401, + 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, + 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, + 422, 423, 424, 425, 426, + 427, 428, 429, 430, 431, + 432, 433, 434, 435, 436, + 437, 438, 439, 440 ], "starting_column": 1, "ending_column": 2 @@ -445,9 +489,9 @@ } } ], - "description": "Modifier AuctionHouse.authorizedBuyer(address) (contracts/auction-house/AuctionHouse.sol#109-115) does not always execute _; or revert\n", - "markdown": "Modifier [AuctionHouse.authorizedBuyer(address)](contracts/auction-house/AuctionHouse.sol#L109-L115) does not always execute _; or revert\n", - "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L109-L115", + "description": "Modifier AuctionHouse.authorizedBuyer(address) (contracts/auction-house/AuctionHouse.sol#100-106) does not always execute _; or revert\n", + "markdown": "Modifier [AuctionHouse.authorizedBuyer(address)](contracts/auction-house/AuctionHouse.sol#L100-L106) does not always execute _; or revert\n", + "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L100-L106", "id": "44596abc779becc714ceca96ccacdc0a13e2cb26cde89bd96cbe5d21e7dc5f1b", "check": "incorrect-modifier", "impact": "Low", @@ -459,22 +503,22 @@ "type": "function", "name": "create", "source_mapping": { - "start": 5649, - "length": 1878, + "start": 4900, + "length": 1910, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, "lines": [ + 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, + 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, - 195, 196, 197, 198, 199, 200, 201, - 202, 203, 204, 205, 206, 207, 208, - 209, 210, 211, 212, 213 + 188, 189, 190, 191, 192, 193 ], "starting_column": 5, "ending_column": 6 @@ -484,81 +528,92 @@ "type": "contract", "name": "AuctionHouse", "source_mapping": { - "start": 1182, - "length": 12390, + "start": 1272, + "length": 13404, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, "lines": [ - 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, - 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, - 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, - 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, - 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, - 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, - 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, - 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, - 326, 327, 328, 329, 330, - 331, 332, 333, 334, 335, - 336, 337, 338, 339, 340, - 341, 342, 343, 344, 345, - 346, 347, 348, 349, 350, - 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, - 361, 362, 363, 364, 365, - 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, - 381, 382, 383, 384, 385 + 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, + 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, + 322, 323, 324, 325, 326, + 327, 328, 329, 330, 331, + 332, 333, 334, 335, 336, + 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, + 347, 348, 349, 350, 351, + 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, + 362, 363, 364, 365, 366, + 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, + 382, 383, 384, 385, 386, + 387, 388, 389, 390, 391, + 392, 393, 394, 395, 396, + 397, 398, 399, 400, 401, + 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, + 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, + 422, 423, 424, 425, 426, + 427, 428, 429, 430, 431, + 432, 433, 434, 435, 436, + 437, 438, 439, 440 ], "starting_column": 1, "ending_column": 2 @@ -571,13 +626,13 @@ "type": "node", "name": "permit.endTime < block.timestamp + MIN_DURATION", "source_mapping": { - "start": 6292, + "start": 5422, "length": 47, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, - "lines": [175], + "lines": [150], "starting_column": 13, "ending_column": 60 }, @@ -586,25 +641,26 @@ "type": "function", "name": "create", "source_mapping": { - "start": 5649, - "length": 1878, + "start": 4900, + "length": 1910, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, "lines": [ - 153, 154, 155, 156, 157, - 158, 159, 160, 161, 162, - 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, - 173, 174, 175, 176, 177, - 178, 179, 180, 181, 182, - 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, - 198, 199, 200, 201, 202, - 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213 + 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, + 192, 193 ], "starting_column": 5, "ending_column": 6 @@ -614,100 +670,113 @@ "type": "contract", "name": "AuctionHouse", "source_mapping": { - "start": 1182, - "length": 12390, + "start": 1272, + "length": 13404, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, "lines": [ - 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, - 100, 101, 102, 103, - 104, 105, 106, 107, - 108, 109, 110, 111, - 112, 113, 114, 115, - 116, 117, 118, 119, - 120, 121, 122, 123, - 124, 125, 126, 127, - 128, 129, 130, 131, - 132, 133, 134, 135, - 136, 137, 138, 139, - 140, 141, 142, 143, - 144, 145, 146, 147, - 148, 149, 150, 151, - 152, 153, 154, 155, - 156, 157, 158, 159, - 160, 161, 162, 163, - 164, 165, 166, 167, - 168, 169, 170, 171, - 172, 173, 174, 175, - 176, 177, 178, 179, - 180, 181, 182, 183, - 184, 185, 186, 187, - 188, 189, 190, 191, - 192, 193, 194, 195, - 196, 197, 198, 199, - 200, 201, 202, 203, - 204, 205, 206, 207, - 208, 209, 210, 211, - 212, 213, 214, 215, - 216, 217, 218, 219, - 220, 221, 222, 223, - 224, 225, 226, 227, - 228, 229, 230, 231, - 232, 233, 234, 235, - 236, 237, 238, 239, - 240, 241, 242, 243, - 244, 245, 246, 247, - 248, 249, 250, 251, - 252, 253, 254, 255, - 256, 257, 258, 259, - 260, 261, 262, 263, - 264, 265, 266, 267, - 268, 269, 270, 271, - 272, 273, 274, 275, - 276, 277, 278, 279, - 280, 281, 282, 283, - 284, 285, 286, 287, - 288, 289, 290, 291, - 292, 293, 294, 295, - 296, 297, 298, 299, - 300, 301, 302, 303, - 304, 305, 306, 307, - 308, 309, 310, 311, - 312, 313, 314, 315, - 316, 317, 318, 319, - 320, 321, 322, 323, - 324, 325, 326, 327, - 328, 329, 330, 331, - 332, 333, 334, 335, - 336, 337, 338, 339, - 340, 341, 342, 343, - 344, 345, 346, 347, - 348, 349, 350, 351, - 352, 353, 354, 355, - 356, 357, 358, 359, - 360, 361, 362, 363, - 364, 365, 366, 367, - 368, 369, 370, 371, - 372, 373, 374, 375, - 376, 377, 378, 379, - 380, 381, 382, 383, - 384, 385 + 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, + 101, 102, 103, 104, + 105, 106, 107, 108, + 109, 110, 111, 112, + 113, 114, 115, 116, + 117, 118, 119, 120, + 121, 122, 123, 124, + 125, 126, 127, 128, + 129, 130, 131, 132, + 133, 134, 135, 136, + 137, 138, 139, 140, + 141, 142, 143, 144, + 145, 146, 147, 148, + 149, 150, 151, 152, + 153, 154, 155, 156, + 157, 158, 159, 160, + 161, 162, 163, 164, + 165, 166, 167, 168, + 169, 170, 171, 172, + 173, 174, 175, 176, + 177, 178, 179, 180, + 181, 182, 183, 184, + 185, 186, 187, 188, + 189, 190, 191, 192, + 193, 194, 195, 196, + 197, 198, 199, 200, + 201, 202, 203, 204, + 205, 206, 207, 208, + 209, 210, 211, 212, + 213, 214, 215, 216, + 217, 218, 219, 220, + 221, 222, 223, 224, + 225, 226, 227, 228, + 229, 230, 231, 232, + 233, 234, 235, 236, + 237, 238, 239, 240, + 241, 242, 243, 244, + 245, 246, 247, 248, + 249, 250, 251, 252, + 253, 254, 255, 256, + 257, 258, 259, 260, + 261, 262, 263, 264, + 265, 266, 267, 268, + 269, 270, 271, 272, + 273, 274, 275, 276, + 277, 278, 279, 280, + 281, 282, 283, 284, + 285, 286, 287, 288, + 289, 290, 291, 292, + 293, 294, 295, 296, + 297, 298, 299, 300, + 301, 302, 303, 304, + 305, 306, 307, 308, + 309, 310, 311, 312, + 313, 314, 315, 316, + 317, 318, 319, 320, + 321, 322, 323, 324, + 325, 326, 327, 328, + 329, 330, 331, 332, + 333, 334, 335, 336, + 337, 338, 339, 340, + 341, 342, 343, 344, + 345, 346, 347, 348, + 349, 350, 351, 352, + 353, 354, 355, 356, + 357, 358, 359, 360, + 361, 362, 363, 364, + 365, 366, 367, 368, + 369, 370, 371, 372, + 373, 374, 375, 376, + 377, 378, 379, 380, + 381, 382, 383, 384, + 385, 386, 387, 388, + 389, 390, 391, 392, + 393, 394, 395, 396, + 397, 398, 399, 400, + 401, 402, 403, 404, + 405, 406, 407, 408, + 409, 410, 411, 412, + 413, 414, 415, 416, + 417, 418, 419, 420, + 421, 422, 423, 424, + 425, 426, 427, 428, + 429, 430, 431, 432, + 433, 434, 435, 436, + 437, 438, 439, 440 ], "starting_column": 1, "ending_column": 2 @@ -722,13 +791,13 @@ "type": "node", "name": "permit.endTime > block.timestamp + MAX_DURATION", "source_mapping": { - "start": 6415, + "start": 5545, "length": 47, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, - "lines": [179], + "lines": [154], "starting_column": 13, "ending_column": 60 }, @@ -737,25 +806,26 @@ "type": "function", "name": "create", "source_mapping": { - "start": 5649, - "length": 1878, + "start": 4900, + "length": 1910, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, "lines": [ - 153, 154, 155, 156, 157, - 158, 159, 160, 161, 162, - 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, - 173, 174, 175, 176, 177, - 178, 179, 180, 181, 182, - 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, - 198, 199, 200, 201, 202, - 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213 + 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, + 192, 193 ], "starting_column": 5, "ending_column": 6 @@ -765,100 +835,113 @@ "type": "contract", "name": "AuctionHouse", "source_mapping": { - "start": 1182, - "length": 12390, + "start": 1272, + "length": 13404, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, "lines": [ - 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, - 100, 101, 102, 103, - 104, 105, 106, 107, - 108, 109, 110, 111, - 112, 113, 114, 115, - 116, 117, 118, 119, - 120, 121, 122, 123, - 124, 125, 126, 127, - 128, 129, 130, 131, - 132, 133, 134, 135, - 136, 137, 138, 139, - 140, 141, 142, 143, - 144, 145, 146, 147, - 148, 149, 150, 151, - 152, 153, 154, 155, - 156, 157, 158, 159, - 160, 161, 162, 163, - 164, 165, 166, 167, - 168, 169, 170, 171, - 172, 173, 174, 175, - 176, 177, 178, 179, - 180, 181, 182, 183, - 184, 185, 186, 187, - 188, 189, 190, 191, - 192, 193, 194, 195, - 196, 197, 198, 199, - 200, 201, 202, 203, - 204, 205, 206, 207, - 208, 209, 210, 211, - 212, 213, 214, 215, - 216, 217, 218, 219, - 220, 221, 222, 223, - 224, 225, 226, 227, - 228, 229, 230, 231, - 232, 233, 234, 235, - 236, 237, 238, 239, - 240, 241, 242, 243, - 244, 245, 246, 247, - 248, 249, 250, 251, - 252, 253, 254, 255, - 256, 257, 258, 259, - 260, 261, 262, 263, - 264, 265, 266, 267, - 268, 269, 270, 271, - 272, 273, 274, 275, - 276, 277, 278, 279, - 280, 281, 282, 283, - 284, 285, 286, 287, - 288, 289, 290, 291, - 292, 293, 294, 295, - 296, 297, 298, 299, - 300, 301, 302, 303, - 304, 305, 306, 307, - 308, 309, 310, 311, - 312, 313, 314, 315, - 316, 317, 318, 319, - 320, 321, 322, 323, - 324, 325, 326, 327, - 328, 329, 330, 331, - 332, 333, 334, 335, - 336, 337, 338, 339, - 340, 341, 342, 343, - 344, 345, 346, 347, - 348, 349, 350, 351, - 352, 353, 354, 355, - 356, 357, 358, 359, - 360, 361, 362, 363, - 364, 365, 366, 367, - 368, 369, 370, 371, - 372, 373, 374, 375, - 376, 377, 378, 379, - 380, 381, 382, 383, - 384, 385 + 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, + 101, 102, 103, 104, + 105, 106, 107, 108, + 109, 110, 111, 112, + 113, 114, 115, 116, + 117, 118, 119, 120, + 121, 122, 123, 124, + 125, 126, 127, 128, + 129, 130, 131, 132, + 133, 134, 135, 136, + 137, 138, 139, 140, + 141, 142, 143, 144, + 145, 146, 147, 148, + 149, 150, 151, 152, + 153, 154, 155, 156, + 157, 158, 159, 160, + 161, 162, 163, 164, + 165, 166, 167, 168, + 169, 170, 171, 172, + 173, 174, 175, 176, + 177, 178, 179, 180, + 181, 182, 183, 184, + 185, 186, 187, 188, + 189, 190, 191, 192, + 193, 194, 195, 196, + 197, 198, 199, 200, + 201, 202, 203, 204, + 205, 206, 207, 208, + 209, 210, 211, 212, + 213, 214, 215, 216, + 217, 218, 219, 220, + 221, 222, 223, 224, + 225, 226, 227, 228, + 229, 230, 231, 232, + 233, 234, 235, 236, + 237, 238, 239, 240, + 241, 242, 243, 244, + 245, 246, 247, 248, + 249, 250, 251, 252, + 253, 254, 255, 256, + 257, 258, 259, 260, + 261, 262, 263, 264, + 265, 266, 267, 268, + 269, 270, 271, 272, + 273, 274, 275, 276, + 277, 278, 279, 280, + 281, 282, 283, 284, + 285, 286, 287, 288, + 289, 290, 291, 292, + 293, 294, 295, 296, + 297, 298, 299, 300, + 301, 302, 303, 304, + 305, 306, 307, 308, + 309, 310, 311, 312, + 313, 314, 315, 316, + 317, 318, 319, 320, + 321, 322, 323, 324, + 325, 326, 327, 328, + 329, 330, 331, 332, + 333, 334, 335, 336, + 337, 338, 339, 340, + 341, 342, 343, 344, + 345, 346, 347, 348, + 349, 350, 351, 352, + 353, 354, 355, 356, + 357, 358, 359, 360, + 361, 362, 363, 364, + 365, 366, 367, 368, + 369, 370, 371, 372, + 373, 374, 375, 376, + 377, 378, 379, 380, + 381, 382, 383, 384, + 385, 386, 387, 388, + 389, 390, 391, 392, + 393, 394, 395, 396, + 397, 398, 399, 400, + 401, 402, 403, 404, + 405, 406, 407, 408, + 409, 410, 411, 412, + 413, 414, 415, 416, + 417, 418, 419, 420, + 421, 422, 423, 424, + 425, 426, 427, 428, + 429, 430, 431, 432, + 433, 434, 435, 436, + 437, 438, 439, 440 ], "starting_column": 1, "ending_column": 2 @@ -870,10 +953,10 @@ } } ], - "description": "AuctionHouse.create(AuctionCreationPermit.Type,bytes) (contracts/auction-house/AuctionHouse.sol#153-213) uses timestamp for comparisons\n\tDangerous comparisons:\n\t- permit.endTime < block.timestamp + MIN_DURATION (contracts/auction-house/AuctionHouse.sol#175)\n\t- permit.endTime > block.timestamp + MAX_DURATION (contracts/auction-house/AuctionHouse.sol#179)\n", - "markdown": "[AuctionHouse.create(AuctionCreationPermit.Type,bytes)](contracts/auction-house/AuctionHouse.sol#L153-L213) uses timestamp for comparisons\n\tDangerous comparisons:\n\t- [permit.endTime < block.timestamp + MIN_DURATION](contracts/auction-house/AuctionHouse.sol#L175)\n\t- [permit.endTime > block.timestamp + MAX_DURATION](contracts/auction-house/AuctionHouse.sol#L179)\n", - "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L153-L213", - "id": "6fe7a18f2a9c0faccbdf2800001c56cd001141244c190d7154d050b4a4b3da98", + "description": "AuctionHouse.create(AuctionCreationPermit.Type,bytes) (contracts/auction-house/AuctionHouse.sol#132-193) uses timestamp for comparisons\n\tDangerous comparisons:\n\t- permit.endTime < block.timestamp + MIN_DURATION (contracts/auction-house/AuctionHouse.sol#150)\n\t- permit.endTime > block.timestamp + MAX_DURATION (contracts/auction-house/AuctionHouse.sol#154)\n", + "markdown": "[AuctionHouse.create(AuctionCreationPermit.Type,bytes)](contracts/auction-house/AuctionHouse.sol#L132-L193) uses timestamp for comparisons\n\tDangerous comparisons:\n\t- [permit.endTime < block.timestamp + MIN_DURATION](contracts/auction-house/AuctionHouse.sol#L150)\n\t- [permit.endTime > block.timestamp + MAX_DURATION](contracts/auction-house/AuctionHouse.sol#L154)\n", + "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L132-L193", + "id": "d4a899dd14eada97e5a88abc4bd21ff91eb1ce77b34ad425143c4df5f40997f9", "check": "timestamp", "impact": "Low", "confidence": "Medium" @@ -884,13 +967,13 @@ "type": "function", "name": "_auctionEnded", "source_mapping": { - "start": 12745, + "start": 13566, "length": 219, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, - "lines": [366, 367, 368, 369, 370], + "lines": [413, 414, 415, 416, 417], "starting_column": 5, "ending_column": 6 }, @@ -899,81 +982,92 @@ "type": "contract", "name": "AuctionHouse", "source_mapping": { - "start": 1182, - "length": 12390, + "start": 1272, + "length": 13404, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, "lines": [ - 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, - 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, - 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, - 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, - 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, - 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, - 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, - 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, - 326, 327, 328, 329, 330, - 331, 332, 333, 334, 335, - 336, 337, 338, 339, 340, - 341, 342, 343, 344, 345, - 346, 347, 348, 349, 350, - 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, - 361, 362, 363, 364, 365, - 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, - 381, 382, 383, 384, 385 + 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, + 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, + 322, 323, 324, 325, 326, + 327, 328, 329, 330, 331, + 332, 333, 334, 335, 336, + 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, + 347, 348, 349, 350, 351, + 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, + 362, 363, 364, 365, 366, + 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, + 382, 383, 384, 385, 386, + 387, 388, 389, 390, 391, + 392, 393, 394, 395, 396, + 397, 398, 399, 400, 401, + 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, + 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, + 422, 423, 424, 425, 426, + 427, 428, 429, 430, 431, + 432, 433, 434, 435, 436, + 437, 438, 439, 440 ], "starting_column": 1, "ending_column": 2 @@ -986,13 +1080,13 @@ "type": "node", "name": "$.auction[auctionId].endTime <= block.timestamp", "source_mapping": { - "start": 12903, + "start": 13724, "length": 54, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, - "lines": [369], + "lines": [416], "starting_column": 9, "ending_column": 63 }, @@ -1001,14 +1095,14 @@ "type": "function", "name": "_auctionEnded", "source_mapping": { - "start": 12745, + "start": 13566, "length": 219, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, "lines": [ - 366, 367, 368, 369, 370 + 413, 414, 415, 416, 417 ], "starting_column": 5, "ending_column": 6 @@ -1018,100 +1112,113 @@ "type": "contract", "name": "AuctionHouse", "source_mapping": { - "start": 1182, - "length": 12390, + "start": 1272, + "length": 13404, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, "lines": [ - 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, - 100, 101, 102, 103, - 104, 105, 106, 107, - 108, 109, 110, 111, - 112, 113, 114, 115, - 116, 117, 118, 119, - 120, 121, 122, 123, - 124, 125, 126, 127, - 128, 129, 130, 131, - 132, 133, 134, 135, - 136, 137, 138, 139, - 140, 141, 142, 143, - 144, 145, 146, 147, - 148, 149, 150, 151, - 152, 153, 154, 155, - 156, 157, 158, 159, - 160, 161, 162, 163, - 164, 165, 166, 167, - 168, 169, 170, 171, - 172, 173, 174, 175, - 176, 177, 178, 179, - 180, 181, 182, 183, - 184, 185, 186, 187, - 188, 189, 190, 191, - 192, 193, 194, 195, - 196, 197, 198, 199, - 200, 201, 202, 203, - 204, 205, 206, 207, - 208, 209, 210, 211, - 212, 213, 214, 215, - 216, 217, 218, 219, - 220, 221, 222, 223, - 224, 225, 226, 227, - 228, 229, 230, 231, - 232, 233, 234, 235, - 236, 237, 238, 239, - 240, 241, 242, 243, - 244, 245, 246, 247, - 248, 249, 250, 251, - 252, 253, 254, 255, - 256, 257, 258, 259, - 260, 261, 262, 263, - 264, 265, 266, 267, - 268, 269, 270, 271, - 272, 273, 274, 275, - 276, 277, 278, 279, - 280, 281, 282, 283, - 284, 285, 286, 287, - 288, 289, 290, 291, - 292, 293, 294, 295, - 296, 297, 298, 299, - 300, 301, 302, 303, - 304, 305, 306, 307, - 308, 309, 310, 311, - 312, 313, 314, 315, - 316, 317, 318, 319, - 320, 321, 322, 323, - 324, 325, 326, 327, - 328, 329, 330, 331, - 332, 333, 334, 335, - 336, 337, 338, 339, - 340, 341, 342, 343, - 344, 345, 346, 347, - 348, 349, 350, 351, - 352, 353, 354, 355, - 356, 357, 358, 359, - 360, 361, 362, 363, - 364, 365, 366, 367, - 368, 369, 370, 371, - 372, 373, 374, 375, - 376, 377, 378, 379, - 380, 381, 382, 383, - 384, 385 + 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, + 101, 102, 103, 104, + 105, 106, 107, 108, + 109, 110, 111, 112, + 113, 114, 115, 116, + 117, 118, 119, 120, + 121, 122, 123, 124, + 125, 126, 127, 128, + 129, 130, 131, 132, + 133, 134, 135, 136, + 137, 138, 139, 140, + 141, 142, 143, 144, + 145, 146, 147, 148, + 149, 150, 151, 152, + 153, 154, 155, 156, + 157, 158, 159, 160, + 161, 162, 163, 164, + 165, 166, 167, 168, + 169, 170, 171, 172, + 173, 174, 175, 176, + 177, 178, 179, 180, + 181, 182, 183, 184, + 185, 186, 187, 188, + 189, 190, 191, 192, + 193, 194, 195, 196, + 197, 198, 199, 200, + 201, 202, 203, 204, + 205, 206, 207, 208, + 209, 210, 211, 212, + 213, 214, 215, 216, + 217, 218, 219, 220, + 221, 222, 223, 224, + 225, 226, 227, 228, + 229, 230, 231, 232, + 233, 234, 235, 236, + 237, 238, 239, 240, + 241, 242, 243, 244, + 245, 246, 247, 248, + 249, 250, 251, 252, + 253, 254, 255, 256, + 257, 258, 259, 260, + 261, 262, 263, 264, + 265, 266, 267, 268, + 269, 270, 271, 272, + 273, 274, 275, 276, + 277, 278, 279, 280, + 281, 282, 283, 284, + 285, 286, 287, 288, + 289, 290, 291, 292, + 293, 294, 295, 296, + 297, 298, 299, 300, + 301, 302, 303, 304, + 305, 306, 307, 308, + 309, 310, 311, 312, + 313, 314, 315, 316, + 317, 318, 319, 320, + 321, 322, 323, 324, + 325, 326, 327, 328, + 329, 330, 331, 332, + 333, 334, 335, 336, + 337, 338, 339, 340, + 341, 342, 343, 344, + 345, 346, 347, 348, + 349, 350, 351, 352, + 353, 354, 355, 356, + 357, 358, 359, 360, + 361, 362, 363, 364, + 365, 366, 367, 368, + 369, 370, 371, 372, + 373, 374, 375, 376, + 377, 378, 379, 380, + 381, 382, 383, 384, + 385, 386, 387, 388, + 389, 390, 391, 392, + 393, 394, 395, 396, + 397, 398, 399, 400, + 401, 402, 403, 404, + 405, 406, 407, 408, + 409, 410, 411, 412, + 413, 414, 415, 416, + 417, 418, 419, 420, + 421, 422, 423, 424, + 425, 426, 427, 428, + 429, 430, 431, 432, + 433, 434, 435, 436, + 437, 438, 439, 440 ], "starting_column": 1, "ending_column": 2 @@ -1123,10 +1230,10 @@ } } ], - "description": "AuctionHouse._auctionEnded(uint256) (contracts/auction-house/AuctionHouse.sol#366-370) uses timestamp for comparisons\n\tDangerous comparisons:\n\t- $.auction[auctionId].endTime <= block.timestamp (contracts/auction-house/AuctionHouse.sol#369)\n", - "markdown": "[AuctionHouse._auctionEnded(uint256)](contracts/auction-house/AuctionHouse.sol#L366-L370) uses timestamp for comparisons\n\tDangerous comparisons:\n\t- [$.auction[auctionId].endTime <= block.timestamp](contracts/auction-house/AuctionHouse.sol#L369)\n", - "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L366-L370", - "id": "6ec80059bef1a4cafd32aa39f10fb8fc7dffe2f8ec5092fb34a85fbc6d1089d4", + "description": "AuctionHouse._auctionEnded(uint256) (contracts/auction-house/AuctionHouse.sol#413-417) uses timestamp for comparisons\n\tDangerous comparisons:\n\t- $.auction[auctionId].endTime <= block.timestamp (contracts/auction-house/AuctionHouse.sol#416)\n", + "markdown": "[AuctionHouse._auctionEnded(uint256)](contracts/auction-house/AuctionHouse.sol#L413-L417) uses timestamp for comparisons\n\tDangerous comparisons:\n\t- [$.auction[auctionId].endTime <= block.timestamp](contracts/auction-house/AuctionHouse.sol#L416)\n", + "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L413-L417", + "id": "fd4ce76ff64a76aa5cb09ee731e85bcd767955a8f013ef4beef10155084fd83b", "check": "timestamp", "impact": "Low", "confidence": "Medium" @@ -1137,7 +1244,7 @@ "type": "function", "name": "_requireAuthorizedOrder", "source_mapping": { - "start": 8864, + "start": 8872, "length": 568, "filename_relative": "contracts/market/Market.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/market/Market.sol", @@ -1157,7 +1264,7 @@ "name": "Market", "source_mapping": { "start": 1221, - "length": 8213, + "length": 8221, "filename_relative": "contracts/market/Market.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/market/Market.sol", "filename_short": "contracts/market/Market.sol", @@ -1223,7 +1330,7 @@ "type": "node", "name": "startTime > block.timestamp || endTime < block.timestamp", "source_mapping": { - "start": 9072, + "start": 9080, "length": 56, "filename_relative": "contracts/market/Market.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/market/Market.sol", @@ -1238,7 +1345,7 @@ "type": "function", "name": "_requireAuthorizedOrder", "source_mapping": { - "start": 8864, + "start": 8872, "length": 568, "filename_relative": "contracts/market/Market.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/market/Market.sol", @@ -1259,7 +1366,7 @@ "name": "Market", "source_mapping": { "start": 1221, - "length": 8213, + "length": 8221, "filename_relative": "contracts/market/Market.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/market/Market.sol", "filename_short": "contracts/market/Market.sol", @@ -1800,7 +1907,7 @@ "type": "function", "name": "layout", "source_mapping": { - "start": 901, + "start": 914, "length": 197, "filename_relative": "contracts/utils/currency-manager/CurrencyManagerStorage.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/utils/currency-manager/CurrencyManagerStorage.sol", @@ -1817,7 +1924,7 @@ "type": "contract", "name": "CurrencyManagerStorage", "source_mapping": { - "start": 290, + "start": 303, "length": 810, "filename_relative": "contracts/utils/currency-manager/CurrencyManagerStorage.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/utils/currency-manager/CurrencyManagerStorage.sol", @@ -1840,7 +1947,7 @@ "type": "node", "name": "", "source_mapping": { - "start": 1045, + "start": 1058, "length": 47, "filename_relative": "contracts/utils/currency-manager/CurrencyManagerStorage.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/utils/currency-manager/CurrencyManagerStorage.sol", @@ -1855,7 +1962,7 @@ "type": "function", "name": "layout", "source_mapping": { - "start": 901, + "start": 914, "length": 197, "filename_relative": "contracts/utils/currency-manager/CurrencyManagerStorage.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/utils/currency-manager/CurrencyManagerStorage.sol", @@ -1873,7 +1980,7 @@ "type": "contract", "name": "CurrencyManagerStorage", "source_mapping": { - "start": 290, + "start": 303, "length": 810, "filename_relative": "contracts/utils/currency-manager/CurrencyManagerStorage.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/utils/currency-manager/CurrencyManagerStorage.sol", @@ -2022,13 +2129,13 @@ "type": "function", "name": "_beforeApprove", "source_mapping": { - "start": 4664, + "start": 4983, "length": 72, "filename_relative": "contracts/art-token/ArtTokenBase.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", "filename_short": "contracts/art-token/ArtTokenBase.sol", "is_dependency": false, - "lines": [127], + "lines": [126], "starting_column": 5, "ending_column": 77 }, @@ -2037,32 +2144,32 @@ "type": "contract", "name": "ArtTokenBase", "source_mapping": { - "start": 842, - "length": 4254, + "start": 976, + "length": 4439, "filename_relative": "contracts/art-token/ArtTokenBase.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", "filename_short": "contracts/art-token/ArtTokenBase.sol", "is_dependency": false, "lines": [ - 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, - 118, 119, 120, 121, 122, - 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, - 133, 134, 135, 136 + 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135 ], "starting_column": 1, "ending_column": 2 @@ -2072,9 +2179,9 @@ } } ], - "description": "ArtTokenBase._beforeApprove(address,uint256) (contracts/art-token/ArtTokenBase.sol#127) is never used and should be removed\n", - "markdown": "[ArtTokenBase._beforeApprove(address,uint256)](contracts/art-token/ArtTokenBase.sol#L127) is never used and should be removed\n", - "first_markdown_element": "contracts/art-token/ArtTokenBase.sol#L127", + "description": "ArtTokenBase._beforeApprove(address,uint256) (contracts/art-token/ArtTokenBase.sol#126) is never used and should be removed\n", + "markdown": "[ArtTokenBase._beforeApprove(address,uint256)](contracts/art-token/ArtTokenBase.sol#L126) is never used and should be removed\n", + "first_markdown_element": "contracts/art-token/ArtTokenBase.sol#L126", "id": "5f92f43cb8301f0cfb6f065cce61d7ef313093cc529cd8c8fe8f4cd4faf86348", "check": "dead-code", "impact": "Informational", @@ -2086,13 +2193,13 @@ "type": "function", "name": "_beforeSetApprovalForAll", "source_mapping": { - "start": 5008, + "start": 5327, "length": 86, "filename_relative": "contracts/art-token/ArtTokenBase.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", "filename_short": "contracts/art-token/ArtTokenBase.sol", "is_dependency": false, - "lines": [135], + "lines": [134], "starting_column": 5, "ending_column": 91 }, @@ -2101,32 +2208,32 @@ "type": "contract", "name": "ArtTokenBase", "source_mapping": { - "start": 842, - "length": 4254, + "start": 976, + "length": 4439, "filename_relative": "contracts/art-token/ArtTokenBase.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", "filename_short": "contracts/art-token/ArtTokenBase.sol", "is_dependency": false, "lines": [ - 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, - 118, 119, 120, 121, 122, - 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, - 133, 134, 135, 136 + 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135 ], "starting_column": 1, "ending_column": 2 @@ -2136,9 +2243,9 @@ } } ], - "description": "ArtTokenBase._beforeSetApprovalForAll(address,bool) (contracts/art-token/ArtTokenBase.sol#135) is never used and should be removed\n", - "markdown": "[ArtTokenBase._beforeSetApprovalForAll(address,bool)](contracts/art-token/ArtTokenBase.sol#L135) is never used and should be removed\n", - "first_markdown_element": "contracts/art-token/ArtTokenBase.sol#L135", + "description": "ArtTokenBase._beforeSetApprovalForAll(address,bool) (contracts/art-token/ArtTokenBase.sol#134) is never used and should be removed\n", + "markdown": "[ArtTokenBase._beforeSetApprovalForAll(address,bool)](contracts/art-token/ArtTokenBase.sol#L134) is never used and should be removed\n", + "first_markdown_element": "contracts/art-token/ArtTokenBase.sol#L134", "id": "a420cad121b9863c5420ce936be50fdafcc2fed508ef19dcffff8371fe270809", "check": "dead-code", "impact": "Informational", @@ -2150,13 +2257,13 @@ "type": "function", "name": "_beforeTransfer", "source_mapping": { - "start": 4334, + "start": 4653, "length": 87, "filename_relative": "contracts/art-token/ArtTokenBase.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", "filename_short": "contracts/art-token/ArtTokenBase.sol", "is_dependency": false, - "lines": [119], + "lines": [118], "starting_column": 5, "ending_column": 92 }, @@ -2165,32 +2272,32 @@ "type": "contract", "name": "ArtTokenBase", "source_mapping": { - "start": 842, - "length": 4254, + "start": 976, + "length": 4439, "filename_relative": "contracts/art-token/ArtTokenBase.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", "filename_short": "contracts/art-token/ArtTokenBase.sol", "is_dependency": false, "lines": [ - 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, - 118, 119, 120, 121, 122, - 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, - 133, 134, 135, 136 + 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135 ], "starting_column": 1, "ending_column": 2 @@ -2200,9 +2307,9 @@ } } ], - "description": "ArtTokenBase._beforeTransfer(address,uint256,address) (contracts/art-token/ArtTokenBase.sol#119) is never used and should be removed\n", - "markdown": "[ArtTokenBase._beforeTransfer(address,uint256,address)](contracts/art-token/ArtTokenBase.sol#L119) is never used and should be removed\n", - "first_markdown_element": "contracts/art-token/ArtTokenBase.sol#L119", + "description": "ArtTokenBase._beforeTransfer(address,uint256,address) (contracts/art-token/ArtTokenBase.sol#118) is never used and should be removed\n", + "markdown": "[ArtTokenBase._beforeTransfer(address,uint256,address)](contracts/art-token/ArtTokenBase.sol#L118) is never used and should be removed\n", + "first_markdown_element": "contracts/art-token/ArtTokenBase.sol#L118", "id": "ad65513af2c3915ae9fabe63dd9779aed68f1f812699652736ac1b68a790ddd6", "check": "dead-code", "impact": "Informational", @@ -2214,13 +2321,13 @@ "type": "function", "name": "_increaseBalance", "source_mapping": { - "start": 3854, + "start": 4173, "length": 203, "filename_relative": "contracts/art-token/ArtTokenBase.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", "filename_short": "contracts/art-token/ArtTokenBase.sol", "is_dependency": false, - "lines": [105, 106, 107, 108, 109, 110], + "lines": [104, 105, 106, 107, 108, 109], "starting_column": 5, "ending_column": 6 }, @@ -2229,32 +2336,32 @@ "type": "contract", "name": "ArtTokenBase", "source_mapping": { - "start": 842, - "length": 4254, + "start": 976, + "length": 4439, "filename_relative": "contracts/art-token/ArtTokenBase.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", "filename_short": "contracts/art-token/ArtTokenBase.sol", "is_dependency": false, "lines": [ - 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, - 118, 119, 120, 121, 122, - 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, - 133, 134, 135, 136 + 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135 ], "starting_column": 1, "ending_column": 2 @@ -2264,84 +2371,27 @@ } } ], - "description": "ArtTokenBase._increaseBalance(address,uint128) (contracts/art-token/ArtTokenBase.sol#105-110) is never used and should be removed\n", - "markdown": "[ArtTokenBase._increaseBalance(address,uint128)](contracts/art-token/ArtTokenBase.sol#L105-L110) is never used and should be removed\n", - "first_markdown_element": "contracts/art-token/ArtTokenBase.sol#L105-L110", + "description": "ArtTokenBase._increaseBalance(address,uint128) (contracts/art-token/ArtTokenBase.sol#104-109) is never used and should be removed\n", + "markdown": "[ArtTokenBase._increaseBalance(address,uint128)](contracts/art-token/ArtTokenBase.sol#L104-L109) is never used and should be removed\n", + "first_markdown_element": "contracts/art-token/ArtTokenBase.sol#L104-L109", "id": "a548e9dd0856e89fbbade6fefa791dda22cc4edc39e8e8cbd15b1a088281bdf8", "check": "dead-code", "impact": "Informational", "confidence": "Medium" }, - { - "elements": [ - { - "type": "function", - "name": "_tokenCreator", - "source_mapping": { - "start": 3032, - "length": 279, - "filename_relative": "contracts/art-token/art-token-config-manager/ArtTokenConfigManager.sol", - "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/art-token-config-manager/ArtTokenConfigManager.sol", - "filename_short": "contracts/art-token/art-token-config-manager/ArtTokenConfigManager.sol", - "is_dependency": false, - "lines": [79, 80, 81, 82, 83, 84, 85], - "starting_column": 5, - "ending_column": 6 - }, - "type_specific_fields": { - "parent": { - "type": "contract", - "name": "ArtTokenConfigManager", - "source_mapping": { - "start": 720, - "length": 3240, - "filename_relative": "contracts/art-token/art-token-config-manager/ArtTokenConfigManager.sol", - "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/art-token-config-manager/ArtTokenConfigManager.sol", - "filename_short": "contracts/art-token/art-token-config-manager/ArtTokenConfigManager.sol", - "is_dependency": false, - "lines": [ - 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, - 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100 - ], - "starting_column": 1, - "ending_column": 2 - } - }, - "signature": "_tokenCreator(uint256)" - } - } - ], - "description": "ArtTokenConfigManager._tokenCreator(uint256) (contracts/art-token/art-token-config-manager/ArtTokenConfigManager.sol#79-85) is never used and should be removed\n", - "markdown": "[ArtTokenConfigManager._tokenCreator(uint256)](contracts/art-token/art-token-config-manager/ArtTokenConfigManager.sol#L79-L85) is never used and should be removed\n", - "first_markdown_element": "contracts/art-token/art-token-config-manager/ArtTokenConfigManager.sol#L79-L85", - "id": "720f7d00df031fde6641196ccb96653ea20b902aa30ed865028bba3e2d72cd52", - "check": "dead-code", - "impact": "Informational", - "confidence": "Medium" - }, { "elements": [ { "type": "variable", "name": "_tokenURI", "source_mapping": { - "start": 3116, + "start": 2407, "length": 25, "filename_relative": "contracts/art-token/ArtToken.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtToken.sol", "filename_short": "contracts/art-token/ArtToken.sol", "is_dependency": false, - "lines": [78], + "lines": [66], "starting_column": 9, "ending_column": 34 }, @@ -2350,15 +2400,15 @@ "type": "function", "name": "mintFromAuctionHouse", "source_mapping": { - "start": 3032, + "start": 2323, "length": 354, "filename_relative": "contracts/art-token/ArtToken.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtToken.sol", "filename_short": "contracts/art-token/ArtToken.sol", "is_dependency": false, "lines": [ - 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86 + 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74 ], "starting_column": 5, "ending_column": 6 @@ -2368,53 +2418,55 @@ "type": "contract", "name": "ArtToken", "source_mapping": { - "start": 1142, - "length": 6070, + "start": 1290, + "length": 5798, "filename_relative": "contracts/art-token/ArtToken.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtToken.sol", "filename_short": "contracts/art-token/ArtToken.sol", "is_dependency": false, "lines": [ - 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, - 100, 101, 102, 103, - 104, 105, 106, 107, - 108, 109, 110, 111, - 112, 113, 114, 115, - 116, 117, 118, 119, - 120, 121, 122, 123, - 124, 125, 126, 127, - 128, 129, 130, 131, - 132, 133, 134, 135, - 136, 137, 138, 139, - 140, 141, 142, 143, - 144, 145, 146, 147, - 148, 149, 150, 151, - 152, 153, 154, 155, - 156, 157, 158, 159, - 160, 161, 162, 163, - 164, 165, 166, 167, - 168, 169, 170, 171, - 172, 173, 174, 175, - 176, 177, 178, 179, - 180, 181, 182, 183, - 184, 185, 186, 187, - 188, 189, 190, 191, - 192, 193, 194, 195, - 196, 197, 198, 199 + 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, + 97, 98, 99, 100, + 101, 102, 103, 104, + 105, 106, 107, 108, + 109, 110, 111, 112, + 113, 114, 115, 116, + 117, 118, 119, 120, + 121, 122, 123, 124, + 125, 126, 127, 128, + 129, 130, 131, 132, + 133, 134, 135, 136, + 137, 138, 139, 140, + 141, 142, 143, 144, + 145, 146, 147, 148, + 149, 150, 151, 152, + 153, 154, 155, 156, + 157, 158, 159, 160, + 161, 162, 163, 164, + 165, 166, 167, 168, + 169, 170, 171, 172, + 173, 174, 175, 176, + 177, 178, 179, 180, + 181, 182, 183, 184, + 185, 186, 187, 188, + 189, 190, 191, 192, + 193, 194, 195, 196, + 197, 198, 199, 200, + 201, 202, 203, 204, + 205, 206, 207, 208 ], "starting_column": 1, "ending_column": 2 @@ -2430,9 +2482,9 @@ } } ], - "description": "Parameter ArtToken.mintFromAuctionHouse(address,uint256,string,TokenConfig.Type)._tokenURI (contracts/art-token/ArtToken.sol#78) is not in mixedCase\n", - "markdown": "Parameter [ArtToken.mintFromAuctionHouse(address,uint256,string,TokenConfig.Type)._tokenURI](contracts/art-token/ArtToken.sol#L78) is not in mixedCase\n", - "first_markdown_element": "contracts/art-token/ArtToken.sol#L78", + "description": "Parameter ArtToken.mintFromAuctionHouse(address,uint256,string,TokenConfig.Type)._tokenURI (contracts/art-token/ArtToken.sol#66) is not in mixedCase\n", + "markdown": "Parameter [ArtToken.mintFromAuctionHouse(address,uint256,string,TokenConfig.Type)._tokenURI](contracts/art-token/ArtToken.sol#L66) is not in mixedCase\n", + "first_markdown_element": "contracts/art-token/ArtToken.sol#L66", "id": "994a4ee42975f133797b06f9bd977a795da1befda9fb3a5621eb71c3f8b23046", "check": "naming-convention", "impact": "Informational", @@ -2442,77 +2494,109 @@ "elements": [ { "type": "variable", - "name": "AUCTION_HOUSE", + "name": "_tokenURI", "source_mapping": { - "start": 1512, - "length": 44, + "start": 3952, + "length": 23, "filename_relative": "contracts/art-token/ArtToken.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtToken.sol", "filename_short": "contracts/art-token/ArtToken.sol", "is_dependency": false, - "lines": [31], - "starting_column": 5, - "ending_column": 49 + "lines": [116], + "starting_column": 43, + "ending_column": 66 }, "type_specific_fields": { "parent": { - "type": "contract", - "name": "ArtToken", + "type": "function", + "name": "setTokenURI", "source_mapping": { - "start": 1142, - "length": 6070, + "start": 3914, + "length": 260, "filename_relative": "contracts/art-token/ArtToken.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtToken.sol", "filename_short": "contracts/art-token/ArtToken.sol", "is_dependency": false, "lines": [ - 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, - 196, 197, 198, 199 + 121, 122 ], - "starting_column": 1, - "ending_column": 2 + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ArtToken", + "source_mapping": { + "start": 1290, + "length": 5798, + "filename_relative": "contracts/art-token/ArtToken.sol", + "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtToken.sol", + "filename_short": "contracts/art-token/ArtToken.sol", + "is_dependency": false, + "lines": [ + 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, + 97, 98, 99, 100, + 101, 102, 103, 104, + 105, 106, 107, 108, + 109, 110, 111, 112, + 113, 114, 115, 116, + 117, 118, 119, 120, + 121, 122, 123, 124, + 125, 126, 127, 128, + 129, 130, 131, 132, + 133, 134, 135, 136, + 137, 138, 139, 140, + 141, 142, 143, 144, + 145, 146, 147, 148, + 149, 150, 151, 152, + 153, 154, 155, 156, + 157, 158, 159, 160, + 161, 162, 163, 164, + 165, 166, 167, 168, + 169, 170, 171, 172, + 173, 174, 175, 176, + 177, 178, 179, 180, + 181, 182, 183, 184, + 185, 186, 187, 188, + 189, 190, 191, 192, + 193, 194, 195, 196, + 197, 198, 199, 200, + 201, 202, 203, 204, + 205, 206, 207, 208 + ], + "starting_column": 1, + "ending_column": 2 + } + }, + "signature": "setTokenURI(uint256,string)" } } }, "additional_fields": { - "target": "variable", + "target": "parameter", "convention": "mixedCase" } } ], - "description": "Variable ArtToken.AUCTION_HOUSE (contracts/art-token/ArtToken.sol#31) is not in mixedCase\n", - "markdown": "Variable [ArtToken.AUCTION_HOUSE](contracts/art-token/ArtToken.sol#L31) is not in mixedCase\n", - "first_markdown_element": "contracts/art-token/ArtToken.sol#L31", - "id": "801381de76b3547f4627bb52efb1b320f8a4d03e2f2b03504b027686906d7cac", + "description": "Parameter ArtToken.setTokenURI(uint256,string)._tokenURI (contracts/art-token/ArtToken.sol#116) is not in mixedCase\n", + "markdown": "Parameter [ArtToken.setTokenURI(uint256,string)._tokenURI](contracts/art-token/ArtToken.sol#L116) is not in mixedCase\n", + "first_markdown_element": "contracts/art-token/ArtToken.sol#L116", + "id": "a99b1d93ad15fdf04c05a364d4508213d9830f4e529d47ae911e53e28c675106", "check": "naming-convention", "impact": "Informational", "confidence": "High" @@ -2521,61 +2605,62 @@ "elements": [ { "type": "variable", - "name": "USDC", + "name": "AUCTION_HOUSE", "source_mapping": { - "start": 1597, - "length": 28, + "start": 1604, + "length": 44, "filename_relative": "contracts/art-token/ArtToken.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtToken.sol", "filename_short": "contracts/art-token/ArtToken.sol", "is_dependency": false, - "lines": [34], + "lines": [40], "starting_column": 5, - "ending_column": 33 + "ending_column": 49 }, "type_specific_fields": { "parent": { "type": "contract", "name": "ArtToken", "source_mapping": { - "start": 1142, - "length": 6070, + "start": 1290, + "length": 5798, "filename_relative": "contracts/art-token/ArtToken.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtToken.sol", "filename_short": "contracts/art-token/ArtToken.sol", "is_dependency": false, "lines": [ - 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, - 196, 197, 198, 199 + 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, + 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, + 158, 159, 160, 161, 162, + 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, + 178, 179, 180, 181, 182, + 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, + 198, 199, 200, 201, 202, + 203, 204, 205, 206, 207, 208 ], "starting_column": 1, "ending_column": 2 @@ -2588,10 +2673,10 @@ } } ], - "description": "Variable ArtToken.USDC (contracts/art-token/ArtToken.sol#34) is not in mixedCase\n", - "markdown": "Variable [ArtToken.USDC](contracts/art-token/ArtToken.sol#L34) is not in mixedCase\n", - "first_markdown_element": "contracts/art-token/ArtToken.sol#L34", - "id": "533aec464a8673be69fd3428a36229ead71e6241db166f57125b607c1865ee95", + "description": "Variable ArtToken.AUCTION_HOUSE (contracts/art-token/ArtToken.sol#40) is not in mixedCase\n", + "markdown": "Variable [ArtToken.AUCTION_HOUSE](contracts/art-token/ArtToken.sol#L40) is not in mixedCase\n", + "first_markdown_element": "contracts/art-token/ArtToken.sol#L40", + "id": "801381de76b3547f4627bb52efb1b320f8a4d03e2f2b03504b027686906d7cac", "check": "naming-convention", "impact": "Informational", "confidence": "High" @@ -2600,247 +2685,89 @@ "elements": [ { "type": "variable", - "name": "MIN_PRICE", + "name": "_name", "source_mapping": { - "start": 1684, - "length": 34, - "filename_relative": "contracts/art-token/ArtToken.sol", - "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtToken.sol", - "filename_short": "contracts/art-token/ArtToken.sol", + "start": 1283, + "length": 19, + "filename_relative": "contracts/art-token/ArtTokenBase.sol", + "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", + "filename_short": "contracts/art-token/ArtTokenBase.sol", "is_dependency": false, - "lines": [37], - "starting_column": 5, - "ending_column": 39 + "lines": [25], + "starting_column": 25, + "ending_column": 44 }, "type_specific_fields": { "parent": { - "type": "contract", - "name": "ArtToken", + "type": "function", + "name": "initialize", "source_mapping": { - "start": 1142, - "length": 6070, - "filename_relative": "contracts/art-token/ArtToken.sol", - "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtToken.sol", - "filename_short": "contracts/art-token/ArtToken.sol", + "start": 1263, + "length": 131, + "filename_relative": "contracts/art-token/ArtTokenBase.sol", + "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", + "filename_short": "contracts/art-token/ArtTokenBase.sol", "is_dependency": false, - "lines": [ - 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, - 196, 197, 198, 199 - ], - "starting_column": 1, - "ending_column": 2 + "lines": [25, 26, 27], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ArtTokenBase", + "source_mapping": { + "start": 976, + "length": 4439, + "filename_relative": "contracts/art-token/ArtTokenBase.sol", + "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", + "filename_short": "contracts/art-token/ArtTokenBase.sol", + "is_dependency": false, + "lines": [ + 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, + 98, 99, 100, 101, + 102, 103, 104, 105, + 106, 107, 108, 109, + 110, 111, 112, 113, + 114, 115, 116, 117, + 118, 119, 120, 121, + 122, 123, 124, 125, + 126, 127, 128, 129, + 130, 131, 132, 133, + 134, 135 + ], + "starting_column": 1, + "ending_column": 2 + } + }, + "signature": "initialize(string,string)" } } }, "additional_fields": { - "target": "variable", + "target": "parameter", "convention": "mixedCase" } } ], - "description": "Variable ArtToken.MIN_PRICE (contracts/art-token/ArtToken.sol#37) is not in mixedCase\n", - "markdown": "Variable [ArtToken.MIN_PRICE](contracts/art-token/ArtToken.sol#L37) is not in mixedCase\n", - "first_markdown_element": "contracts/art-token/ArtToken.sol#L37", - "id": "d9b31fc446a93138a5cb36fd814b853d3a985ba746b98d7f13c7941d3c0b0cfe", - "check": "naming-convention", - "impact": "Informational", - "confidence": "High" - }, - { - "elements": [ - { - "type": "variable", - "name": "MIN_FEE", - "source_mapping": { - "start": 1771, - "length": 32, - "filename_relative": "contracts/art-token/ArtToken.sol", - "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtToken.sol", - "filename_short": "contracts/art-token/ArtToken.sol", - "is_dependency": false, - "lines": [40], - "starting_column": 5, - "ending_column": 37 - }, - "type_specific_fields": { - "parent": { - "type": "contract", - "name": "ArtToken", - "source_mapping": { - "start": 1142, - "length": 6070, - "filename_relative": "contracts/art-token/ArtToken.sol", - "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtToken.sol", - "filename_short": "contracts/art-token/ArtToken.sol", - "is_dependency": false, - "lines": [ - 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, - 196, 197, 198, 199 - ], - "starting_column": 1, - "ending_column": 2 - } - } - }, - "additional_fields": { - "target": "variable", - "convention": "mixedCase" - } - } - ], - "description": "Variable ArtToken.MIN_FEE (contracts/art-token/ArtToken.sol#40) is not in mixedCase\n", - "markdown": "Variable [ArtToken.MIN_FEE](contracts/art-token/ArtToken.sol#L40) is not in mixedCase\n", - "first_markdown_element": "contracts/art-token/ArtToken.sol#L40", - "id": "66c310607e40582d4796f687535a9af2760b01c0c255e2b501000404d3f30f54", - "check": "naming-convention", - "impact": "Informational", - "confidence": "High" - }, - { - "elements": [ - { - "type": "variable", - "name": "_name", - "source_mapping": { - "start": 1139, - "length": 19, - "filename_relative": "contracts/art-token/ArtTokenBase.sol", - "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", - "filename_short": "contracts/art-token/ArtTokenBase.sol", - "is_dependency": false, - "lines": [27], - "starting_column": 25, - "ending_column": 44 - }, - "type_specific_fields": { - "parent": { - "type": "function", - "name": "initialize", - "source_mapping": { - "start": 1119, - "length": 131, - "filename_relative": "contracts/art-token/ArtTokenBase.sol", - "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", - "filename_short": "contracts/art-token/ArtTokenBase.sol", - "is_dependency": false, - "lines": [27, 28, 29], - "starting_column": 5, - "ending_column": 6 - }, - "type_specific_fields": { - "parent": { - "type": "contract", - "name": "ArtTokenBase", - "source_mapping": { - "start": 842, - "length": 4254, - "filename_relative": "contracts/art-token/ArtTokenBase.sol", - "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", - "filename_short": "contracts/art-token/ArtTokenBase.sol", - "is_dependency": false, - "lines": [ - 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, - 100, 101, 102, 103, - 104, 105, 106, 107, - 108, 109, 110, 111, - 112, 113, 114, 115, - 116, 117, 118, 119, - 120, 121, 122, 123, - 124, 125, 126, 127, - 128, 129, 130, 131, - 132, 133, 134, 135, - 136 - ], - "starting_column": 1, - "ending_column": 2 - } - }, - "signature": "initialize(string,string)" - } - } - }, - "additional_fields": { - "target": "parameter", - "convention": "mixedCase" - } - } - ], - "description": "Parameter ArtTokenBase.initialize(string,string)._name (contracts/art-token/ArtTokenBase.sol#27) is not in mixedCase\n", - "markdown": "Parameter [ArtTokenBase.initialize(string,string)._name](contracts/art-token/ArtTokenBase.sol#L27) is not in mixedCase\n", - "first_markdown_element": "contracts/art-token/ArtTokenBase.sol#L27", + "description": "Parameter ArtTokenBase.initialize(string,string)._name (contracts/art-token/ArtTokenBase.sol#25) is not in mixedCase\n", + "markdown": "Parameter [ArtTokenBase.initialize(string,string)._name](contracts/art-token/ArtTokenBase.sol#L25) is not in mixedCase\n", + "first_markdown_element": "contracts/art-token/ArtTokenBase.sol#L25", "id": "0d6536aff27f992204afb08494fd56ce453268a0d6d7f76954870ce15454efdd", "check": "naming-convention", "impact": "Informational", @@ -2852,13 +2779,13 @@ "type": "variable", "name": "_symbol", "source_mapping": { - "start": 1160, + "start": 1304, "length": 21, "filename_relative": "contracts/art-token/ArtTokenBase.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", "filename_short": "contracts/art-token/ArtTokenBase.sol", "is_dependency": false, - "lines": [27], + "lines": [25], "starting_column": 46, "ending_column": 67 }, @@ -2867,13 +2794,13 @@ "type": "function", "name": "initialize", "source_mapping": { - "start": 1119, + "start": 1263, "length": 131, "filename_relative": "contracts/art-token/ArtTokenBase.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", "filename_short": "contracts/art-token/ArtTokenBase.sol", "is_dependency": false, - "lines": [27, 28, 29], + "lines": [25, 26, 27], "starting_column": 5, "ending_column": 6 }, @@ -2882,39 +2809,39 @@ "type": "contract", "name": "ArtTokenBase", "source_mapping": { - "start": 842, - "length": 4254, + "start": 976, + "length": 4439, "filename_relative": "contracts/art-token/ArtTokenBase.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/art-token/ArtTokenBase.sol", "filename_short": "contracts/art-token/ArtTokenBase.sol", "is_dependency": false, "lines": [ - 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, - 100, 101, 102, 103, - 104, 105, 106, 107, - 108, 109, 110, 111, - 112, 113, 114, 115, - 116, 117, 118, 119, - 120, 121, 122, 123, - 124, 125, 126, 127, - 128, 129, 130, 131, - 132, 133, 134, 135, - 136 + 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, + 98, 99, 100, 101, + 102, 103, 104, 105, + 106, 107, 108, 109, + 110, 111, 112, 113, + 114, 115, 116, 117, + 118, 119, 120, 121, + 122, 123, 124, 125, + 126, 127, 128, 129, + 130, 131, 132, 133, + 134, 135 ], "starting_column": 1, "ending_column": 2 @@ -2930,9 +2857,9 @@ } } ], - "description": "Parameter ArtTokenBase.initialize(string,string)._symbol (contracts/art-token/ArtTokenBase.sol#27) is not in mixedCase\n", - "markdown": "Parameter [ArtTokenBase.initialize(string,string)._symbol](contracts/art-token/ArtTokenBase.sol#L27) is not in mixedCase\n", - "first_markdown_element": "contracts/art-token/ArtTokenBase.sol#L27", + "description": "Parameter ArtTokenBase.initialize(string,string)._symbol (contracts/art-token/ArtTokenBase.sol#25) is not in mixedCase\n", + "markdown": "Parameter [ArtTokenBase.initialize(string,string)._symbol](contracts/art-token/ArtTokenBase.sol#L25) is not in mixedCase\n", + "first_markdown_element": "contracts/art-token/ArtTokenBase.sol#L25", "id": "7bcea9354c9ddc3dbe1466bf8c094194d3838858b9a7057b8a6ff3e4d9e1c359", "check": "naming-convention", "impact": "Informational", @@ -2944,7 +2871,7 @@ "type": "variable", "name": "ART_TOKEN", "source_mapping": { - "start": 1428, + "start": 1503, "length": 36, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", @@ -2959,81 +2886,92 @@ "type": "contract", "name": "AuctionHouse", "source_mapping": { - "start": 1182, - "length": 12390, + "start": 1272, + "length": 13404, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, "lines": [ - 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, - 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, - 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, - 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, - 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, - 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, - 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, - 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, - 326, 327, 328, 329, 330, - 331, 332, 333, 334, 335, - 336, 337, 338, 339, 340, - 341, 342, 343, 344, 345, - 346, 347, 348, 349, 350, - 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, - 361, 362, 363, 364, 365, - 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, - 381, 382, 383, 384, 385 + 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, + 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, + 322, 323, 324, 325, 326, + 327, 328, 329, 330, 331, + 332, 333, 334, 335, 336, + 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, + 347, 348, 349, 350, 351, + 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, + 362, 363, 364, 365, 366, + 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, + 382, 383, 384, 385, 386, + 387, 388, 389, 390, 391, + 392, 393, 394, 395, 396, + 397, 398, 399, 400, 401, + 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, + 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, + 422, 423, 424, 425, 426, + 427, 428, 429, 430, 431, + 432, 433, 434, 435, 436, + 437, 438, 439, 440 ], "starting_column": 1, "ending_column": 2 @@ -3054,135 +2992,19 @@ "impact": "Informational", "confidence": "High" }, - { - "elements": [ - { - "type": "variable", - "name": "USDC", - "source_mapping": { - "start": 1541, - "length": 28, - "filename_relative": "contracts/auction-house/AuctionHouse.sol", - "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", - "filename_short": "contracts/auction-house/AuctionHouse.sol", - "is_dependency": false, - "lines": [33], - "starting_column": 5, - "ending_column": 33 - }, - "type_specific_fields": { - "parent": { - "type": "contract", - "name": "AuctionHouse", - "source_mapping": { - "start": 1182, - "length": 12390, - "filename_relative": "contracts/auction-house/AuctionHouse.sol", - "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", - "filename_short": "contracts/auction-house/AuctionHouse.sol", - "is_dependency": false, - "lines": [ - 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, - 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, - 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, - 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, - 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, - 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, - 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, - 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, - 326, 327, 328, 329, 330, - 331, 332, 333, 334, 335, - 336, 337, 338, 339, 340, - 341, 342, 343, 344, 345, - 346, 347, 348, 349, 350, - 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, - 361, 362, 363, 364, 365, - 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, - 381, 382, 383, 384, 385 - ], - "starting_column": 1, - "ending_column": 2 - } - } - }, - "additional_fields": { - "target": "variable", - "convention": "mixedCase" - } - } - ], - "description": "Variable AuctionHouse.USDC (contracts/auction-house/AuctionHouse.sol#33) is not in mixedCase\n", - "markdown": "Variable [AuctionHouse.USDC](contracts/auction-house/AuctionHouse.sol#L33) is not in mixedCase\n", - "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L33", - "id": "07d5bd6994cd32404289642e73b3c469146a00de74c2bd91fb3dcec2d6102074", - "check": "naming-convention", - "impact": "Informational", - "confidence": "High" - }, { "elements": [ { "type": "variable", "name": "MIN_DURATION", "source_mapping": { - "start": 1643, + "start": 1613, "length": 37, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, - "lines": [36], + "lines": [33], "starting_column": 5, "ending_column": 42 }, @@ -3191,81 +3013,92 @@ "type": "contract", "name": "AuctionHouse", "source_mapping": { - "start": 1182, - "length": 12390, + "start": 1272, + "length": 13404, "filename_relative": "contracts/auction-house/AuctionHouse.sol", "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", "filename_short": "contracts/auction-house/AuctionHouse.sol", "is_dependency": false, "lines": [ - 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, - 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, - 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, - 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, - 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, - 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, - 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, - 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, - 326, 327, 328, 329, 330, - 331, 332, 333, 334, 335, - 336, 337, 338, 339, 340, - 341, 342, 343, 344, 345, - 346, 347, 348, 349, 350, - 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, - 361, 362, 363, 364, 365, - 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, - 381, 382, 383, 384, 385 + 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, + 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, + 322, 323, 324, 325, 326, + 327, 328, 329, 330, 331, + 332, 333, 334, 335, 336, + 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, + 347, 348, 349, 350, 351, + 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, + 362, 363, 364, 365, 366, + 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, + 382, 383, 384, 385, 386, + 387, 388, 389, 390, 391, + 392, 393, 394, 395, 396, + 397, 398, 399, 400, 401, + 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, + 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, + 422, 423, 424, 425, 426, + 427, 428, 429, 430, 431, + 432, 433, 434, 435, 436, + 437, 438, 439, 440 ], "starting_column": 1, "ending_column": 2 @@ -3278,246 +3111,14 @@ } } ], - "description": "Variable AuctionHouse.MIN_DURATION (contracts/auction-house/AuctionHouse.sol#36) is not in mixedCase\n", - "markdown": "Variable [AuctionHouse.MIN_DURATION](contracts/auction-house/AuctionHouse.sol#L36) is not in mixedCase\n", - "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L36", + "description": "Variable AuctionHouse.MIN_DURATION (contracts/auction-house/AuctionHouse.sol#33) is not in mixedCase\n", + "markdown": "Variable [AuctionHouse.MIN_DURATION](contracts/auction-house/AuctionHouse.sol#L33) is not in mixedCase\n", + "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L33", "id": "98b4ffaf5185ecfde6761fb768baf7f6cc537e760d8419d5663fed6cfca136ba", "check": "naming-convention", "impact": "Informational", "confidence": "High" }, - { - "elements": [ - { - "type": "variable", - "name": "MIN_PRICE", - "source_mapping": { - "start": 1871, - "length": 34, - "filename_relative": "contracts/auction-house/AuctionHouse.sol", - "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", - "filename_short": "contracts/auction-house/AuctionHouse.sol", - "is_dependency": false, - "lines": [42], - "starting_column": 5, - "ending_column": 39 - }, - "type_specific_fields": { - "parent": { - "type": "contract", - "name": "AuctionHouse", - "source_mapping": { - "start": 1182, - "length": 12390, - "filename_relative": "contracts/auction-house/AuctionHouse.sol", - "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", - "filename_short": "contracts/auction-house/AuctionHouse.sol", - "is_dependency": false, - "lines": [ - 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, - 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, - 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, - 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, - 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, - 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, - 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, - 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, - 326, 327, 328, 329, 330, - 331, 332, 333, 334, 335, - 336, 337, 338, 339, 340, - 341, 342, 343, 344, 345, - 346, 347, 348, 349, 350, - 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, - 361, 362, 363, 364, 365, - 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, - 381, 382, 383, 384, 385 - ], - "starting_column": 1, - "ending_column": 2 - } - } - }, - "additional_fields": { - "target": "variable", - "convention": "mixedCase" - } - } - ], - "description": "Variable AuctionHouse.MIN_PRICE (contracts/auction-house/AuctionHouse.sol#42) is not in mixedCase\n", - "markdown": "Variable [AuctionHouse.MIN_PRICE](contracts/auction-house/AuctionHouse.sol#L42) is not in mixedCase\n", - "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L42", - "id": "0104d361e1ea8e3bc4ed2d89bddc062717bbd6745526d41219b06ace53334a7f", - "check": "naming-convention", - "impact": "Informational", - "confidence": "High" - }, - { - "elements": [ - { - "type": "variable", - "name": "MIN_FEE", - "source_mapping": { - "start": 1983, - "length": 32, - "filename_relative": "contracts/auction-house/AuctionHouse.sol", - "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", - "filename_short": "contracts/auction-house/AuctionHouse.sol", - "is_dependency": false, - "lines": [45], - "starting_column": 5, - "ending_column": 37 - }, - "type_specific_fields": { - "parent": { - "type": "contract", - "name": "AuctionHouse", - "source_mapping": { - "start": 1182, - "length": 12390, - "filename_relative": "contracts/auction-house/AuctionHouse.sol", - "filename_absolute": "/Users/mriynyk/Documents/work/do/contracts/contracts/auction-house/AuctionHouse.sol", - "filename_short": "contracts/auction-house/AuctionHouse.sol", - "is_dependency": false, - "lines": [ - 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, - 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, - 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, - 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, - 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, - 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, - 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, - 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, - 326, 327, 328, 329, 330, - 331, 332, 333, 334, 335, - 336, 337, 338, 339, 340, - 341, 342, 343, 344, 345, - 346, 347, 348, 349, 350, - 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, - 361, 362, 363, 364, 365, - 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, - 381, 382, 383, 384, 385 - ], - "starting_column": 1, - "ending_column": 2 - } - } - }, - "additional_fields": { - "target": "variable", - "convention": "mixedCase" - } - } - ], - "description": "Variable AuctionHouse.MIN_FEE (contracts/auction-house/AuctionHouse.sol#45) is not in mixedCase\n", - "markdown": "Variable [AuctionHouse.MIN_FEE](contracts/auction-house/AuctionHouse.sol#L45) is not in mixedCase\n", - "first_markdown_element": "contracts/auction-house/AuctionHouse.sol#L45", - "id": "b3634a21e75f1f2401b777ffb2232054c168c111d1f6db43ca86c47fef59c89e", - "check": "naming-convention", - "impact": "Informational", - "confidence": "High" - }, { "elements": [ { diff --git a/tasks/deploy-art-token-impl.ts b/tasks/deploy-art-token-impl.ts index f64f030..ce12155 100644 --- a/tasks/deploy-art-token-impl.ts +++ b/tasks/deploy-art-token-impl.ts @@ -1,7 +1,6 @@ import { task } from 'hardhat/config'; import { ProtocolConfig } from '../types/environment'; import { deploy } from '../scripts/deploy'; -import { etherToWeiForErc20 } from './utils/ether-to-wei-for-erc20'; /* npx hardhat deploy-art-token-impl --network fork @@ -22,11 +21,8 @@ task('deploy-art-token-impl').setAction(async (taskArgs: Record, console.groupEnd(); console.log('-'.repeat(process.stdout.columns)); - const { usdc, main } = config; - const { minPriceUsd, minFeeUsd, artToken, auctionHouse } = config.collection; - - const minPrice = await etherToWeiForErc20(usdc, minPriceUsd); - const minFee = await etherToWeiForErc20(usdc, minFeeUsd); + const { main } = config; + const { artToken, auctionHouse } = config.collection; console.log(`Deploying ArtToken Impl...`); console.log(`\n`); @@ -34,18 +30,13 @@ task('deploy-art-token-impl').setAction(async (taskArgs: Record, console.log(`main: ${main}`); console.log(`artToken: ${artToken.proxy}`); console.log(`auctionHouse: ${auctionHouse.proxy}`); - console.log(`usdc: ${usdc}`); - console.log(`minPriceUsd: ${minPriceUsd}`); - console.log(`minPrice: ${minPrice}`); - console.log(`minFee: ${minFeeUsd}`); - console.log(`minFee: ${minFee}`); console.groupEnd(); console.log(`\n`); console.log(`Transaction broadcasting...`); const { receipt, contractAddr: artTokenImplAddr } = await deploy({ name: 'ArtToken', - constructorArgs: [artToken.proxy, main, auctionHouse.proxy, usdc, minPrice, minFee], + constructorArgs: [artToken.proxy, main, auctionHouse.proxy], }); console.log(`Transaction broadcasted`); diff --git a/tasks/deploy-auction-house-impl.ts b/tasks/deploy-auction-house-impl.ts index 835eb78..63eea32 100644 --- a/tasks/deploy-auction-house-impl.ts +++ b/tasks/deploy-auction-house-impl.ts @@ -1,7 +1,6 @@ import { task } from 'hardhat/config'; import { ProtocolConfig } from '../types/environment'; import { deploy } from '../scripts/deploy'; -import { etherToWeiForErc20 } from './utils/ether-to-wei-for-erc20'; import { hoursToSeconds } from './utils/hours-to-seconds'; /* @@ -22,12 +21,9 @@ task('deploy-auction-house-impl').setAction(async (taskArgs: Record, har console.groupEnd(); console.log('-'.repeat(process.stdout.columns)); - const { usdc, main } = config; - const { name, symbol, minPriceUsd, minFeeUsd, minAuctionDurationHours } = config.collection; + const { main } = config; + const { name, symbol, minAuctionDurationHours } = config.collection; - const minPrice = await etherToWeiForErc20(usdc, minPriceUsd); - const minFee = await etherToWeiForErc20(usdc, minFeeUsd); const minAuctionDuration = hoursToSeconds(minAuctionDurationHours); console.log(`Deploying collection...`); @@ -35,12 +32,7 @@ task('deploy-collection').setAction(async (taskArgs: Record, har console.group('Params:'); console.log(`name: ${name}`); console.log(`symbol: ${symbol}`); - console.log(`usdc: ${usdc}`); console.log(`main: ${main}`); - console.log(`minPriceUsd: ${minPriceUsd}`); - console.log(`minPrice: ${minPrice}`); - console.log(`minFeeUsd: ${minFeeUsd}`); - console.log(`minFee: ${minFee}`); console.log(`minAuctionDurationHours: ${minAuctionDurationHours}`); console.log(`minAuctionDuration: ${minAuctionDuration}`); console.groupEnd(); @@ -60,12 +52,9 @@ task('deploy-collection').setAction(async (taskArgs: Record, har auctionHouseProxyAdminAddr, auctionHouseProxyAdminOwnerAddr, } = await deployCollection({ - usdc, main, name, symbol, - minPrice, - minFee, minAuctionDuration, }); diff --git a/tasks/deploy-market-impl.ts b/tasks/deploy-market-impl.ts index 97ab162..38dc300 100644 --- a/tasks/deploy-market-impl.ts +++ b/tasks/deploy-market-impl.ts @@ -3,7 +3,7 @@ import { ProtocolConfig } from '../types/environment'; import { deploy } from '../scripts/deploy'; /* -npx hardhat deploy-market-impl--network fork +npx hardhat deploy-market-impl --network fork */ task('deploy-market-impl').setAction(async (taskArgs: Record, hardhat) => { diff --git a/tasks/verify-art-token.ts b/tasks/verify-art-token.ts index 06dd277..9883300 100644 --- a/tasks/verify-art-token.ts +++ b/tasks/verify-art-token.ts @@ -1,6 +1,5 @@ import { task } from 'hardhat/config'; import { ProtocolConfig } from '../types/environment'; -import { etherToWeiForErc20 } from './utils/ether-to-wei-for-erc20'; /* npx hardhat verify-art-token --network fork @@ -32,9 +31,6 @@ task('verify-art-token').setAction(async (taskArgs: Record, hard // ArtToken const main = config.main; const auctionHouse = config.collection.auctionHouse.proxy; - const usdc = config.usdc; - const minPrice = await etherToWeiForErc20(usdc, config.collection.minPriceUsd); - const minFee = await etherToWeiForErc20(usdc, config.collection.minFeeUsd); console.log(`Verify ArtToken...`); console.log(`\n`); @@ -51,12 +47,9 @@ task('verify-art-token').setAction(async (taskArgs: Record, hard console.log(`proxyAdminOwner: ${proxyAdminOwner}`); console.groupEnd(); - console.group(`ArtToken:`); + console.group(`ArtToken Impl:`); console.log(`main: ${main}`); console.log(`auctionHouse: ${auctionHouse}`); - console.log(`usdc: ${usdc}`); - console.log(`minPrice: ${minPrice}`); - console.log(`minFee: ${minFee}`); console.groupEnd(); console.groupEnd(); @@ -80,7 +73,7 @@ task('verify-art-token').setAction(async (taskArgs: Record, hard await hardhat.run('verify:verify', { contract: 'contracts/art-token/ArtToken.sol:ArtToken', address: impl, - constructorArguments: [proxy, main, auctionHouse, usdc, minPrice, minFee], + constructorArguments: [proxy, main, auctionHouse], }); console.log('-'.repeat(process.stdout.columns)); }); diff --git a/tasks/verify-auction-house.ts b/tasks/verify-auction-house.ts index 1e397dc..fd7ffd9 100644 --- a/tasks/verify-auction-house.ts +++ b/tasks/verify-auction-house.ts @@ -1,6 +1,5 @@ import { task } from 'hardhat/config'; import { ProtocolConfig } from '../types/environment'; -import { etherToWeiForErc20 } from './utils/ether-to-wei-for-erc20'; import { hoursToSeconds } from './utils/hours-to-seconds'; /* @@ -33,9 +32,6 @@ task('verify-auction-house').setAction(async (taskArgs: Record, // AuctionHouse const main = config.main; const artToken = config.collection.artToken.proxy; - const usdc = config.usdc; - const minPrice = await etherToWeiForErc20(usdc, config.collection.minPriceUsd); - const minFee = await etherToWeiForErc20(usdc, config.collection.minFeeUsd); const minAuctionDuration = hoursToSeconds(config.collection.minAuctionDurationHours); console.log(`Verify AuctionHouse...`); @@ -53,13 +49,10 @@ task('verify-auction-house').setAction(async (taskArgs: Record, console.log(`proxyAdminOwner: ${proxyAdminOwner}`); console.groupEnd(); - console.group(`ArtToken:`); + console.group(`AuctionHouse Impl:`); console.log(`main: ${main}`); console.log(`artToken: ${artToken}`); - console.log(`usdc: ${usdc}`); console.log(`minAuctionDuration: ${minAuctionDuration}`); - console.log(`minPrice: ${minPrice}`); - console.log(`minFee: ${minFee}`); console.groupEnd(); console.groupEnd(); @@ -83,7 +76,7 @@ task('verify-auction-house').setAction(async (taskArgs: Record, await hardhat.run('verify:verify', { contract: 'contracts/auction-house/AuctionHouse.sol:AuctionHouse', address: impl, - constructorArguments: [proxy, main, artToken, usdc, minAuctionDuration, minPrice, minFee], + constructorArguments: [proxy, main, artToken, minAuctionDuration], }); console.log('-'.repeat(process.stdout.columns)); }); diff --git a/tests/ArtToken.ts b/tests/ArtToken.ts index 04004f6..f9c122c 100644 --- a/tests/ArtToken.ts +++ b/tests/ArtToken.ts @@ -3,24 +3,30 @@ import { Signer, MaxInt256, ZeroAddress } from 'ethers'; import { ArtToken, AuctionHouse, USDC, Market } from '../typechain-types'; import { AuctionCreationPermit } from '../typechain-types/contracts/auction-house/AuctionHouse'; import { TokenMintingPermit } from '../typechain-types/contracts/art-token/ArtToken'; -import { MIN_FEE, MIN_PRICE } from './constants/min-price-and-fee'; -import { TOKEN_CONFIG, TOKEN_ID, TOKEN_URI } from './constants/art-token'; -import { HOUR } from './constants/time'; -import { AUCTION_ID, AUCTION_STEP } from './constants/auction-house'; -import { TOTAL_SHARE } from './constants/distribution'; +import { HOUR, ONE_HUNDRED } from './constants/general'; +import { + NON_EXISTENT_TOKEN_ID, + SECOND_TOKEN_URI, + TOKEN_CONFIG, + TOKEN_CREATOR_ADDR, + TOKEN_FEE, + TOKEN_ID, + TOKEN_PRICE, + TOKEN_ROYALTY_PERCENT, + TOKEN_URI, +} from './constants/art-token'; +import { AUCTION_FEE, AUCTION_ID, AUCTION_PRICE, AUCTION_STEP } from './constants/auction-house'; +import { + REGULATION_MODE_NONE, + REGULATION_MODE_REGULATED, + REGULATION_MODE_UNREGULATED, +} from './constants/token-config'; import { getSigners } from './utils/get-signers'; import { getLatestBlockTimestamp } from './utils/get-latest-block-timestamp'; import { deployAll } from './utils/deploy-all'; import { ArtTokenUtils } from './utils/art-token-utils'; import { AuctionHouseUtils } from './utils/auction-house-utils'; -/** - * TODO: - * - cover with tests ArtTokenConfigManager - * - cover with test the logic with TokenConfig - * - tests for the `mintFromAuctionHouse` method - * - write more tests for the `mint` method - */ describe('ArtToken', function () { let artToken: ArtToken, artTokenAddr: string; let auctionHouse: AuctionHouse, auctionHouseAddr: string; @@ -29,19 +35,27 @@ describe('ArtToken', function () { let artTokenSigner: Signer, artTokenSignerAddr: string; let financier: Signer, financierAddr: string; + let admin: Signer, adminAddr: string; let institution: Signer, institutionAddr: string; let buyer: Signer, buyerAddr: string; let randomAccount: Signer, randomAccountAddr: string; before(async () => { [ - [artTokenSigner, financier, institution, buyer, randomAccount], - [artTokenSignerAddr, financierAddr, institutionAddr, buyerAddr, randomAccountAddr], + [artTokenSigner, financier, admin, institution, buyer, randomAccount], + [ + artTokenSignerAddr, + financierAddr, + adminAddr, + institutionAddr, + buyerAddr, + randomAccountAddr, + ], ] = await getSigners(); }); beforeEach(async () => { - const all = await deployAll({ signer: artTokenSigner, financier }); + const all = await deployAll({ signer: artTokenSigner, financier, admin }); artToken = all.artToken; artTokenAddr = all.artTokenAddr; @@ -61,17 +75,15 @@ describe('ArtToken', function () { it(`should mint the token, distribute price, and charge a fee`, async () => { const latestBlockTimestamp = await getLatestBlockTimestamp(); - const price = MIN_PRICE; - const fee = MIN_FEE; - - const institutionReward = (price / 5n) * 4n; // 80% - const platformReward = price / 5n; // 20% + const institutionReward = (TOKEN_PRICE / 5n) * 4n; // 80% + const platformReward = TOKEN_PRICE / 5n; // 20% const tokenMintingPermit: TokenMintingPermit.TypeStruct = { tokenId: TOKEN_ID, minter: buyerAddr, - price, - fee, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr, financierAddr], @@ -87,40 +99,125 @@ describe('ArtToken', function () { }); await expect(tx) - .to.be.emit(usdc, 'Transfer') - .withArgs(buyerAddr, artTokenAddr, price + fee); + .emit(usdc, 'Transfer') + .withArgs(buyerAddr, artTokenAddr, TOKEN_PRICE + TOKEN_FEE); await expect(tx) - .to.be.emit(usdc, 'Transfer') + .emit(usdc, 'Transfer') .withArgs(artTokenAddr, institutionAddr, institutionReward); await expect(tx) - .to.be.emit(usdc, 'Transfer') + .emit(usdc, 'Transfer') .withArgs(artTokenAddr, financierAddr, platformReward); await expect(tx) - .to.be.emit(usdc, 'Transfer') - .withArgs(artTokenAddr, financierAddr, fee); + .emit(usdc, 'Transfer') + .withArgs(artTokenAddr, financierAddr, TOKEN_FEE); - await expect(tx) - .to.be.emit(artToken, 'Transfer') + await expect(tx) // + .emit(artToken, 'Transfer') .withArgs(ZeroAddress, buyerAddr, TOKEN_ID); }); + it(`should set correct token config`, async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + + const tokenMintingPermit: TokenMintingPermit.TypeStruct = { + tokenId: TOKEN_ID, + minter: buyerAddr, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, + tokenURI: TOKEN_URI, + tokenConfig: TOKEN_CONFIG, + participants: [institutionAddr], + rewards: [TOKEN_PRICE], + deadline: latestBlockTimestamp + HOUR, + }; + + const tx = await ArtTokenUtils.mint({ + artToken, + permit: tokenMintingPermit, + permitSigner: artTokenSigner, + sender: buyer, + }); + + const tokenCreator = await artToken.tokenCreator(TOKEN_ID); + const tokenRegulationMode = await artToken.tokenRegulationMode(TOKEN_ID); + + expect(tokenCreator).equal(TOKEN_CONFIG.creator); + expect(tokenRegulationMode).equal(TOKEN_CONFIG.regulationMode); + + await expect(tx).emit(artToken, 'TokenConfigUpdated').withArgs(TOKEN_ID); + }); + + it(`should fail if the caller is not the allowed minter`, async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + + const tokenMintingPermit: TokenMintingPermit.TypeStruct = { + tokenId: TOKEN_ID, + minter: buyerAddr, // Not allowed minter + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, + tokenURI: TOKEN_URI, + tokenConfig: TOKEN_CONFIG, + participants: [institutionAddr], + rewards: [TOKEN_PRICE], + deadline: latestBlockTimestamp + HOUR, + }; + + const tx = ArtTokenUtils.mint({ + artToken, + permit: tokenMintingPermit, + permitSigner: artTokenSigner, + sender: randomAccount, + }); + + await expect(tx).rejectedWith('ArtTokenUnauthorizedAccount'); + }); + + it(`should fail if the currency is not allowed`, async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + + const tokenMintingPermit: TokenMintingPermit.TypeStruct = { + tokenId: TOKEN_ID, + minter: buyerAddr, + currency: randomAccountAddr, // Not allowed currency + price: TOKEN_PRICE, + fee: TOKEN_FEE, + tokenURI: TOKEN_URI, + tokenConfig: TOKEN_CONFIG, + participants: [institutionAddr], + rewards: [TOKEN_PRICE], + deadline: latestBlockTimestamp + HOUR, + }; + + const tx = ArtTokenUtils.mint({ + artToken, + permit: tokenMintingPermit, + permitSigner: artTokenSigner, + sender: buyer, + }); + + await expect(tx).rejectedWith('ArtTokenCurrencyInvalid'); + }); + it(`should fail if the token is reserved by an auction`, async () => { const latestBlockTimestamp = await getLatestBlockTimestamp(); const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { auctionId: AUCTION_ID, tokenId: TOKEN_ID, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, step: AUCTION_STEP, endTime: latestBlockTimestamp + HOUR, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - shares: [TOTAL_SHARE], + shares: [ONE_HUNDRED], deadline: latestBlockTimestamp + HOUR, }; @@ -134,12 +231,13 @@ describe('ArtToken', function () { const tokenMintingPermit: TokenMintingPermit.TypeStruct = { tokenId: TOKEN_ID, minter: buyerAddr, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - rewards: [MIN_PRICE], + rewards: [TOKEN_PRICE], deadline: latestBlockTimestamp + HOUR, }; @@ -150,7 +248,7 @@ describe('ArtToken', function () { sender: buyer, }); - await expect(tx).to.be.rejectedWith('ArtTokenTokenReserved'); + await expect(tx).rejectedWith('ArtTokenTokenReserved'); }); it(`should fail if the permit signer is not the art token signer`, async () => { @@ -159,12 +257,13 @@ describe('ArtToken', function () { const tokenMintingPermit: TokenMintingPermit.TypeStruct = { tokenId: TOKEN_ID, minter: buyerAddr, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - rewards: [MIN_PRICE], + rewards: [TOKEN_PRICE], deadline: latestBlockTimestamp + HOUR, }; @@ -175,7 +274,17 @@ describe('ArtToken', function () { sender: buyer, }); - await expect(tx).to.be.rejectedWith('AuthorizationUnauthorizedAction'); + await expect(tx).rejectedWith('AuthorizationUnauthorizedAction'); + }); + }); + + describe(`method 'mintFromAuctionHouse'`, () => { + it(`should fail if the caller is not the auction house`, async () => { + const tx = artToken + .connect(randomAccount) + .mintFromAuctionHouse(randomAccountAddr, TOKEN_ID, TOKEN_URI, TOKEN_CONFIG); + + await expect(tx).rejectedWith('ArtTokenUnauthorizedAccount'); }); }); @@ -186,12 +295,13 @@ describe('ArtToken', function () { const tokenMintingPermit: TokenMintingPermit.TypeStruct = { tokenId: TOKEN_ID, minter: buyerAddr, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - rewards: [MIN_PRICE], + rewards: [TOKEN_PRICE], deadline: latestBlockTimestamp + HOUR, }; @@ -205,42 +315,225 @@ describe('ArtToken', function () { }); }); - it(`should transfer to a non-contract account`, async () => { - const tx = await artToken.connect(buyer).transferFrom(buyer, randomAccount, TOKEN_ID); + for (const regulationMode of [ + REGULATION_MODE_NONE, + REGULATION_MODE_UNREGULATED, + REGULATION_MODE_REGULATED, + ]) { + describe(`Regulation mode is '${regulationMode}'`, () => { + beforeEach(async () => { + await artToken + .connect(admin) + .updateTokenRegulationMode(TOKEN_ID, regulationMode); + }); + + it(`should transfer to a non-contract account`, async () => { + const tx = await artToken + .connect(buyer) + .transferFrom(buyer, randomAccount, TOKEN_ID); + + await expect(tx) + .emit(artToken, 'Transfer') + .withArgs(buyerAddr, randomAccountAddr, TOKEN_ID); + }); + + it(`should transfer to a partner contract`, async () => { + const tx = await artToken.connect(buyer).transferFrom(buyer, market, TOKEN_ID); + + await expect(tx) + .emit(artToken, 'Transfer') + .withArgs(buyerAddr, marketAddr, TOKEN_ID); + }); + + if ([REGULATION_MODE_NONE, REGULATION_MODE_REGULATED].includes(regulationMode)) { + it(`should fail if a token is transferred to a non-partner contract`, async () => { + const tx = artToken.connect(buyer).transferFrom(buyer, usdc, TOKEN_ID); + + await expect(tx).rejectedWith('ArtTokenUnauthorizedAccount'); + }); + } + + if ([REGULATION_MODE_UNREGULATED].includes(regulationMode)) { + it(`should transfer to a non-partner contract`, async () => { + const tx = await artToken + .connect(buyer) + .transferFrom(buyer, usdc, TOKEN_ID); + + await expect(tx) + .emit(artToken, 'Transfer') + .withArgs(buyerAddr, usdcAddr, TOKEN_ID); + }); + } + }); + } + }); - await expect(tx) - .to.be.emit(artToken, 'Transfer') - .withArgs(buyerAddr, randomAccountAddr, TOKEN_ID); - }); + describe(`method 'approve'`, () => { + beforeEach(async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); - it(`should transfer to a partner contract`, async () => { - const tx = await artToken.connect(buyer).transferFrom(buyer, market, TOKEN_ID); + const tokenMintingPermit: TokenMintingPermit.TypeStruct = { + tokenId: TOKEN_ID, + minter: buyerAddr, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, + tokenURI: TOKEN_URI, + tokenConfig: TOKEN_CONFIG, + participants: [institutionAddr], + rewards: [TOKEN_PRICE], + deadline: latestBlockTimestamp + HOUR, + }; - await expect(tx) - .to.be.emit(artToken, 'Transfer') - .withArgs(buyerAddr, marketAddr, TOKEN_ID); + await usdc.connect(buyer).mintAndApprove(artToken, MaxInt256); + + await ArtTokenUtils.mint({ + artToken, + permit: tokenMintingPermit, + permitSigner: artTokenSigner, + sender: buyer, + }); }); - it(`should fail if a token is transferred to a non-partner contract`, async () => { - const tx = artToken.connect(buyer).transferFrom(buyer, usdc, TOKEN_ID); + for (const regulationMode of [ + REGULATION_MODE_NONE, + REGULATION_MODE_UNREGULATED, + REGULATION_MODE_REGULATED, + ]) { + describe(`Regulation mode is '${regulationMode}'`, () => { + beforeEach(async () => { + await artToken + .connect(admin) + .updateTokenRegulationMode(TOKEN_ID, regulationMode); + }); + + it(`should provide the approval to a non-contract account`, async () => { + const tx = await artToken.connect(buyer).approve(randomAccountAddr, TOKEN_ID); + + await expect(tx) + .emit(artToken, 'Approval') + .withArgs(buyerAddr, randomAccountAddr, TOKEN_ID); + }); + + it(`should provide the approval to a partner contract`, async () => { + const tx = await artToken.connect(buyer).approve(market, TOKEN_ID); + + await expect(tx) + .emit(artToken, 'Approval') + .withArgs(buyerAddr, marketAddr, TOKEN_ID); + }); + + if ([REGULATION_MODE_NONE, REGULATION_MODE_REGULATED].includes(regulationMode)) { + it(`should fail if approval is provided to a non-partner contract`, async () => { + const tx = artToken.connect(buyer).approve(usdc, TOKEN_ID); + + await expect(tx).rejectedWith('ArtTokenUnauthorizedAccount'); + }); + + it( + `should fail if a token is transferred by a non-partner contract with approval`, + ); + } + + if ([REGULATION_MODE_UNREGULATED].includes(regulationMode)) { + it(`should provide the approval to a non-partner contract`, async () => { + const tx = await artToken.connect(buyer).approve(usdc, TOKEN_ID); + + await expect(tx) + .emit(artToken, 'Approval') + .withArgs(buyerAddr, usdc, TOKEN_ID); + }); + } + }); + } + }); + + describe(`method 'setApprovalForAll'`, () => { + beforeEach(async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + + const tokenMintingPermit: TokenMintingPermit.TypeStruct = { + tokenId: TOKEN_ID, + minter: buyerAddr, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, + tokenURI: TOKEN_URI, + tokenConfig: TOKEN_CONFIG, + participants: [institutionAddr], + rewards: [TOKEN_PRICE], + deadline: latestBlockTimestamp + HOUR, + }; + + await usdc.connect(buyer).mintAndApprove(artToken, MaxInt256); - await expect(tx).to.eventually.rejectedWith('ArtTokenUnauthorizedAccount'); + await ArtTokenUtils.mint({ + artToken, + permit: tokenMintingPermit, + permitSigner: artTokenSigner, + sender: buyer, + }); }); + + for (const regulationMode of [ + REGULATION_MODE_NONE, + REGULATION_MODE_UNREGULATED, + REGULATION_MODE_REGULATED, + ]) { + describe(`Regulation mode is '${regulationMode}'`, () => { + beforeEach(async () => { + await artToken + .connect(admin) + .updateTokenRegulationMode(TOKEN_ID, regulationMode); + }); + + it(`should provide the approval to a non-contract account`, async () => { + const tx = await artToken + .connect(buyer) + .setApprovalForAll(randomAccountAddr, true); + + await expect(tx) + .emit(artToken, 'ApprovalForAll') + .withArgs(buyerAddr, randomAccountAddr, true); + }); + + it(`should provide the approval to a partner contract`, async () => { + const tx = await artToken.connect(buyer).setApprovalForAll(market, true); + + await expect(tx) + .emit(artToken, 'ApprovalForAll') + .withArgs(buyerAddr, marketAddr, true); + }); + + it(`should fail if approval is provided to a non-partner contract`, async () => { + const tx = artToken.connect(buyer).setApprovalForAll(usdc, true); + + await expect(tx).rejectedWith('ArtTokenUnauthorizedAccount'); + }); + + if ([REGULATION_MODE_NONE, REGULATION_MODE_REGULATED].includes(regulationMode)) { + it( + `should fail if a token is transferred by a non-partner contract with approval`, + ); + } + }); + } }); - describe(`method 'approve'`, () => { + describe(`method 'royaltyInfo'`, () => { beforeEach(async () => { const latestBlockTimestamp = await getLatestBlockTimestamp(); const tokenMintingPermit: TokenMintingPermit.TypeStruct = { tokenId: TOKEN_ID, minter: buyerAddr, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - rewards: [MIN_PRICE], + rewards: [TOKEN_PRICE], deadline: latestBlockTimestamp + HOUR, }; @@ -254,42 +547,41 @@ describe('ArtToken', function () { }); }); - it(`should provide the approval to a non-contract account`, async () => { - const tx = await artToken.connect(buyer).approve(randomAccountAddr, TOKEN_ID); + it(`should return correct receiver address`, async () => { + const [receiver] = await artToken.royaltyInfo(TOKEN_ID, TOKEN_PRICE); - await expect(tx) - .to.be.emit(artToken, 'Approval') - .withArgs(buyerAddr, randomAccountAddr, TOKEN_ID); + expect(receiver).equal(TOKEN_CREATOR_ADDR); }); - it(`should provide the approval to a partner contract`, async () => { - const tx = await artToken.connect(buyer).approve(market, TOKEN_ID); + it(`should return correct default receiver address`, async () => { + await artToken.connect(admin).updateTokenCreator(TOKEN_ID, ZeroAddress); - await expect(tx) - .to.be.emit(artToken, 'Approval') - .withArgs(buyerAddr, marketAddr, TOKEN_ID); + const [receiver] = await artToken.royaltyInfo(TOKEN_ID, TOKEN_PRICE); + + expect(receiver).equal(financierAddr); }); - it(`should fail if approval is provided to a non-partner contract`, async () => { - const tx = artToken.connect(buyer).approve(usdc, TOKEN_ID); + it(`should return correct royalty amount`, async () => { + const [_, royaltyAmount] = await artToken.royaltyInfo(TOKEN_ID, TOKEN_PRICE); - await expect(tx).to.eventually.rejectedWith('ArtTokenUnauthorizedAccount'); + expect(royaltyAmount).equal((TOKEN_PRICE * TOKEN_ROYALTY_PERCENT) / ONE_HUNDRED); }); }); - describe(`method 'setApprovalForAll'`, () => { + describe(`method 'setTokenURI'`, () => { beforeEach(async () => { const latestBlockTimestamp = await getLatestBlockTimestamp(); const tokenMintingPermit: TokenMintingPermit.TypeStruct = { tokenId: TOKEN_ID, minter: buyerAddr, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - rewards: [MIN_PRICE], + rewards: [TOKEN_PRICE], deadline: latestBlockTimestamp + HOUR, }; @@ -303,26 +595,26 @@ describe('ArtToken', function () { }); }); - it(`should provide the approval to a non-contract account`, async () => { - const tx = await artToken.connect(buyer).setApprovalForAll(randomAccountAddr, true); + it(`should set the new token URI`, async () => { + const tx = await artToken.connect(admin).setTokenURI(TOKEN_ID, SECOND_TOKEN_URI); - await expect(tx) - .to.be.emit(artToken, 'ApprovalForAll') - .withArgs(buyerAddr, randomAccountAddr, true); + await expect(tx).emit(artToken, 'MetadataUpdate').withArgs(TOKEN_ID); + + const tokenURI = await artToken.tokenURI(TOKEN_ID); + + expect(tokenURI).equal(SECOND_TOKEN_URI); }); - it(`should provide the approval to a partner contract`, async () => { - const tx = await artToken.connect(buyer).setApprovalForAll(market, true); + it(`should fail if the caller is not the art token admin`, async () => { + const tx = artToken.connect(randomAccount).setTokenURI(TOKEN_ID, SECOND_TOKEN_URI); - await expect(tx) - .to.be.emit(artToken, 'ApprovalForAll') - .withArgs(buyerAddr, marketAddr, true); + await expect(tx).rejectedWith('RoleSystemUnauthorizedAccount'); }); - it(`should fail if approval is provided to a non-partner contract`, async () => { - const tx = artToken.connect(buyer).setApprovalForAll(usdc, true); + it(`should fail if the token does not exist`, async () => { + const tx = artToken.connect(admin).setTokenURI(NON_EXISTENT_TOKEN_ID, SECOND_TOKEN_URI); - await expect(tx).to.eventually.rejectedWith('ArtTokenUnauthorizedAccount'); + await expect(tx).rejectedWith('ArtTokenNonexistentToken'); }); }); @@ -345,4 +637,84 @@ describe('ArtToken', function () { expect(authorized).equal(false); }); }); + + describe(`ArtTokenConfigManager`, () => { + beforeEach(async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + + const tokenMintingPermit: TokenMintingPermit.TypeStruct = { + tokenId: TOKEN_ID, + minter: buyerAddr, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, + tokenURI: TOKEN_URI, + tokenConfig: TOKEN_CONFIG, + participants: [institutionAddr], + rewards: [TOKEN_PRICE], + deadline: latestBlockTimestamp + HOUR, + }; + + await usdc.connect(buyer).mintAndApprove(artToken, MaxInt256); + + await ArtTokenUtils.mint({ + artToken, + permit: tokenMintingPermit, + permitSigner: artTokenSigner, + sender: buyer, + }); + }); + + describe(`method 'updateTokenCreator'`, () => { + it(`should update the token creator`, async () => { + const tokenCreatorBefore = await artToken.tokenCreator(TOKEN_ID); + + expect(tokenCreatorBefore).not.equal(institutionAddr); + + const tx = await artToken + .connect(admin) + .updateTokenCreator(TOKEN_ID, institutionAddr); + + const tokenCreatorAfter = await artToken.tokenCreator(TOKEN_ID); + + expect(tokenCreatorAfter).equal(institutionAddr); + + await expect(tx).emit(artToken, 'TokenConfigUpdated').withArgs(TOKEN_ID); + }); + + it(`should fail if the caller is not the art token admin`, async () => { + const tx = artToken + .connect(randomAccount) + .updateTokenCreator(TOKEN_ID, randomAccountAddr); + + await expect(tx).rejectedWith('RoleSystemUnauthorizedAccount'); + }); + }); + + describe(`method 'updateTokenRegulationMode'`, () => { + it(`should update the token regulation mode`, async () => { + const tokenRegulationModeBefore = await artToken.tokenRegulationMode(TOKEN_ID); + + expect(tokenRegulationModeBefore).not.equal(REGULATION_MODE_UNREGULATED); + + const tx = await artToken + .connect(admin) + .updateTokenRegulationMode(TOKEN_ID, REGULATION_MODE_UNREGULATED); + + const tokenRegulationModeAfter = await artToken.tokenRegulationMode(TOKEN_ID); + + expect(tokenRegulationModeAfter).equal(REGULATION_MODE_UNREGULATED); + + await expect(tx).emit(artToken, 'TokenConfigUpdated').withArgs(TOKEN_ID); + }); + + it(`should fail if the caller is not the art token admin`, async () => { + const tx = artToken + .connect(randomAccount) + .updateTokenRegulationMode(TOKEN_ID, REGULATION_MODE_UNREGULATED); + + await expect(tx).rejectedWith('RoleSystemUnauthorizedAccount'); + }); + }); + }); }); diff --git a/tests/AuctionHouse.ts b/tests/AuctionHouse.ts index 10270a9..697dfe7 100644 --- a/tests/AuctionHouse.ts +++ b/tests/AuctionHouse.ts @@ -5,23 +5,38 @@ import { setNextBlockTimestamp } from '@nomicfoundation/hardhat-network-helpers/ import { ArtToken, AuctionHouse, USDC } from '../typechain-types'; import { TokenMintingPermit } from '../typechain-types/contracts/art-token/ArtToken'; import { AuctionCreationPermit } from '../typechain-types/contracts/auction-house/AuctionHouse'; -import { MIN_FEE, MIN_PRICE } from './constants/min-price-and-fee'; -import { TOTAL_SHARE } from './constants/distribution'; -import { AUCTION_ID, AUCTION_STEP, SECOND_AUCTION_ID } from './constants/auction-house'; -import { TOKEN_CONFIG, TOKEN_ID, TOKEN_URI } from './constants/art-token'; -import { HOUR } from './constants/time'; +import { ONE_HUNDRED, HOUR } from './constants/general'; +import { + AUCTION_FEE, + AUCTION_ID, + AUCTION_PRICE, + AUCTION_STEP, + NON_EXISTENT_AUCTION_ID, + SECOND_AUCTION_ID, +} from './constants/auction-house'; +import { + NON_EXISTENT_TOKEN_ID, + TOKEN_CONFIG, + TOKEN_CREATOR_ADDR, + TOKEN_FEE, + TOKEN_ID, + TOKEN_PRICE, + TOKEN_REGULATION_MODE, + TOKEN_URI, +} from './constants/art-token'; import { getSigners } from './utils/get-signers'; import { getLatestBlockTimestamp } from './utils/get-latest-block-timestamp'; import { deployAll } from './utils/deploy-all'; import { ArtTokenUtils } from './utils/art-token-utils'; import { AuctionHouseUtils } from './utils/auction-house-utils'; -describe('AuctionHouse', function () { +describe(`AuctionHouse`, () => { let auctionHouse: AuctionHouse, auctionHouseAddr: string; let artToken: ArtToken, artTokenAddr: string; let usdc: USDC, usdcAddr: string; let auctionHouseSigner: Signer, auctionHouseSignerAddr: string; + let admin: Signer, adminAddr: string; let financier: Signer, financierAddr: string; let institution: Signer, institutionAddr: string; let buyer: Signer, buyerAddr: string; @@ -29,8 +44,22 @@ describe('AuctionHouse', function () { before(async () => { [ - [auctionHouseSigner, financier, institution, buyer, randomAccount], - [auctionHouseSignerAddr, financierAddr, institutionAddr, buyerAddr, randomAccountAddr], + [ + auctionHouseSigner, + admin, + financier, + institution, + buyer, + randomAccount, // + ], + [ + auctionHouseSignerAddr, + adminAddr, + financierAddr, + institutionAddr, + buyerAddr, + randomAccountAddr, + ], ] = await getSigners(); }); @@ -38,6 +67,7 @@ describe('AuctionHouse', function () { const all = await deployAll({ signer: auctionHouseSigner, financier, + admin, }); auctionHouse = all.auctionHouse; @@ -52,19 +82,17 @@ describe('AuctionHouse', function () { it(`should create the auction`, async () => { const latestBlockTimestamp = await getLatestBlockTimestamp(); - const price = MIN_PRICE; - const fee = MIN_FEE; - const step = AUCTION_STEP; const endTime = latestBlockTimestamp + HOUR; const participants = [institutionAddr, financierAddr]; - const shares = [(TOTAL_SHARE / 5n) * 4n, TOTAL_SHARE / 5n]; + const shares = [(ONE_HUNDRED / 5n) * 4n, ONE_HUNDRED / 5n]; const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { auctionId: AUCTION_ID, tokenId: TOKEN_ID, - price, - fee, - step, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, + step: AUCTION_STEP, endTime, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, @@ -83,19 +111,20 @@ describe('AuctionHouse', function () { const auction = await auctionHouse.auction(AUCTION_ID); await expect(tx) - .to.be.emit(auctionHouse, 'Created') - .withArgs(AUCTION_ID, TOKEN_ID, price, endTime); + .emit(auctionHouse, 'Created') + .withArgs(AUCTION_ID, TOKEN_ID, AUCTION_PRICE, endTime); expect(auction.tokenId).equal(TOKEN_ID); expect(auction.tokenURI).equal(TOKEN_URI); expect(auction.buyer).equal(ZeroAddress); - expect(auction.price).equal(price); - expect(auction.fee).equal(fee); - expect(auction.step).equal(step); + expect(auction.price).equal(AUCTION_PRICE); + expect(auction.fee).equal(AUCTION_FEE); + expect(auction.step).equal(AUCTION_STEP); expect(auction.endTime).equal(endTime); expect(auction.sold).equal(false); expect(auction.participants).to.deep.equal(participants); expect(auction.shares).to.deep.equal(shares); + expect(auction.currency).to.deep.equal(usdcAddr); }); it(`should create a new auction for a token that was not sold in the previous auction`, async () => { @@ -104,14 +133,15 @@ describe('AuctionHouse', function () { const firstAuctionCreationPermit: AuctionCreationPermit.TypeStruct = { auctionId: AUCTION_ID, tokenId: TOKEN_ID, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, step: AUCTION_STEP, endTime: latestBlockTimestamp + HOUR, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - shares: [TOTAL_SHARE], + shares: [ONE_HUNDRED], deadline: latestBlockTimestamp + HOUR, }; @@ -143,6 +173,34 @@ describe('AuctionHouse', function () { expect(auction.tokenId).equal(TOKEN_ID); }); + it(`should fail if the currency is not allowed`, async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + + const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { + auctionId: AUCTION_ID, + tokenId: TOKEN_ID, + currency: randomAccountAddr, // Not allowed currency + price: AUCTION_PRICE, + fee: AUCTION_FEE, + step: AUCTION_STEP, + endTime: latestBlockTimestamp + HOUR, + tokenURI: TOKEN_URI, + tokenConfig: TOKEN_CONFIG, + participants: [institutionAddr], + shares: [ONE_HUNDRED], + deadline: latestBlockTimestamp + HOUR, + }; + + const tx = AuctionHouseUtils.create({ + auctionHouse, + permit: auctionCreationPermit, + permitSigner: auctionHouseSigner, + sender: institution, + }); + + await expect(tx).rejectedWith('AuctionHouseInvalidCurrency'); + }); + it(`should fail if the auction duration is less than the minimum duration`, async () => { const latestBlockTimestamp = await getLatestBlockTimestamp(); @@ -155,14 +213,15 @@ describe('AuctionHouse', function () { const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { auctionId: AUCTION_ID, tokenId: TOKEN_ID, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, step: AUCTION_STEP, endTime: nextBlockTimestamp + minDuration - 1, // Wrong end time tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - shares: [TOTAL_SHARE], + shares: [ONE_HUNDRED], deadline: latestBlockTimestamp + HOUR, }; @@ -173,7 +232,7 @@ describe('AuctionHouse', function () { sender: institution, }); - await expect(tx).to.eventually.rejectedWith('AuctionHouseInvalidEndTime'); + await expect(tx).rejectedWith('AuctionHouseInvalidEndTime'); }); it(`should fail if the auction duration is greater than the maximum duration`, async () => { @@ -188,14 +247,15 @@ describe('AuctionHouse', function () { const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { auctionId: AUCTION_ID, tokenId: TOKEN_ID, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, step: AUCTION_STEP, endTime: nextBlockTimestamp + maxDuration + 1, // Wrong end time tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - shares: [TOTAL_SHARE], + shares: [ONE_HUNDRED], deadline: latestBlockTimestamp + HOUR, }; @@ -206,7 +266,7 @@ describe('AuctionHouse', function () { sender: institution, }); - await expect(tx).to.eventually.rejectedWith('AuctionHouseInvalidEndTime'); + await expect(tx).rejectedWith('AuctionHouseInvalidEndTime'); }); it(`should fail if the auction already exists`, async () => { @@ -215,14 +275,15 @@ describe('AuctionHouse', function () { const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { auctionId: AUCTION_ID, tokenId: TOKEN_ID, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, step: AUCTION_STEP, endTime: latestBlockTimestamp + HOUR, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - shares: [TOTAL_SHARE], + shares: [ONE_HUNDRED], deadline: latestBlockTimestamp + HOUR, }; @@ -240,7 +301,7 @@ describe('AuctionHouse', function () { sender: institution, }); - await expect(tx).to.eventually.rejectedWith('AuctionHouseAuctionExists'); + await expect(tx).rejectedWith('AuctionHouseAuctionExists'); }); it(`should fail if the token is already in an active auction`, async () => { @@ -249,14 +310,15 @@ describe('AuctionHouse', function () { const firstAuctionCreationPermit: AuctionCreationPermit.TypeStruct = { auctionId: AUCTION_ID, tokenId: TOKEN_ID, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, step: AUCTION_STEP, endTime: latestBlockTimestamp + HOUR, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - shares: [TOTAL_SHARE], + shares: [ONE_HUNDRED], deadline: latestBlockTimestamp + HOUR, }; @@ -279,7 +341,7 @@ describe('AuctionHouse', function () { sender: institution, }); - await expect(tx).to.eventually.rejectedWith('AuctionHouseTokenReserved'); + await expect(tx).rejectedWith('AuctionHouseTokenReserved'); }); it(`should fail if the token is in an inactive auction with a buyer`, async () => { @@ -288,14 +350,15 @@ describe('AuctionHouse', function () { const firstAuctionCreationPermit: AuctionCreationPermit.TypeStruct = { auctionId: AUCTION_ID, tokenId: TOKEN_ID, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, step: AUCTION_STEP, endTime: latestBlockTimestamp + HOUR, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - shares: [TOTAL_SHARE], + shares: [ONE_HUNDRED], deadline: latestBlockTimestamp + HOUR, }; @@ -315,7 +378,7 @@ describe('AuctionHouse', function () { await usdc.connect(buyer).mintAndApprove(auctionHouse, MaxInt256); - await auctionHouse.connect(buyer).raiseInitial(AUCTION_ID, 100_000_000n); + await auctionHouse.connect(buyer).raiseInitial(AUCTION_ID, AUCTION_PRICE); await setNextBlockTimestamp(firstAuctionCreationPermit.endTime); @@ -326,7 +389,7 @@ describe('AuctionHouse', function () { sender: institution, }); - await expect(tx).to.eventually.rejectedWith('AuctionHouseTokenReserved'); + await expect(tx).rejectedWith('AuctionHouseTokenReserved'); }); it(`should fail if the token is already minted`, async () => { @@ -335,26 +398,28 @@ describe('AuctionHouse', function () { const tokenMintingPermit: TokenMintingPermit.TypeStruct = { tokenId: TOKEN_ID, minter: buyerAddr, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - rewards: [MIN_PRICE], + rewards: [TOKEN_PRICE], deadline: latestBlockTimestamp + HOUR, }; const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { auctionId: AUCTION_ID, tokenId: TOKEN_ID, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, step: AUCTION_STEP, endTime: latestBlockTimestamp + HOUR, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - shares: [TOTAL_SHARE], + shares: [ONE_HUNDRED], deadline: latestBlockTimestamp + HOUR, }; @@ -374,7 +439,7 @@ describe('AuctionHouse', function () { sender: institution, }); - await expect(tx).to.eventually.rejectedWith('AuctionHouseTokenReserved'); + await expect(tx).rejectedWith('AuctionHouseTokenReserved'); }); it(`should fail if the permit signer is not the auction house signer`, async () => { @@ -383,14 +448,15 @@ describe('AuctionHouse', function () { const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { auctionId: AUCTION_ID, tokenId: TOKEN_ID, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, step: AUCTION_STEP, endTime: latestBlockTimestamp + HOUR, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - shares: [TOTAL_SHARE], + shares: [ONE_HUNDRED], deadline: latestBlockTimestamp + HOUR, }; @@ -401,7 +467,7 @@ describe('AuctionHouse', function () { sender: institution, }); - await expect(tx).to.eventually.rejectedWith('AuthorizationUnauthorizedAction'); + await expect(tx).rejectedWith('AuthorizationUnauthorizedAction'); }); }); @@ -412,14 +478,15 @@ describe('AuctionHouse', function () { const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { auctionId: AUCTION_ID, tokenId: TOKEN_ID, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, step: AUCTION_STEP, endTime: latestBlockTimestamp + HOUR, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - shares: [TOTAL_SHARE], + shares: [ONE_HUNDRED], deadline: latestBlockTimestamp + HOUR, }; @@ -446,11 +513,11 @@ describe('AuctionHouse', function () { expect(auction.price).equal(newPrice); await expect(tx) - .to.be.emit(auctionHouse, 'Raised') + .emit(auctionHouse, 'Raised') .withArgs(AUCTION_ID, auction.buyer, auction.price); await expect(tx) - .to.be.emit(usdc, 'Transfer') + .emit(usdc, 'Transfer') .withArgs(buyerAddr, auctionHouseAddr, auction.price + auction.fee); }); @@ -474,13 +541,15 @@ describe('AuctionHouse', function () { const tx = auctionHouse.connect(buyer).raiseInitial(AUCTION_ID, newPrice); - await expect(tx).to.eventually.rejectedWith('AuctionHouseRaiseTooLow'); + await expect(tx).rejectedWith('AuctionHouseRaiseTooLow'); }); it(`should fail if the auction does not exist`, async () => { - const tx = auctionHouse.connect(buyer).raiseInitial(0, 1n); + const tx = auctionHouse + .connect(buyer) + .raiseInitial(NON_EXISTENT_AUCTION_ID, AUCTION_PRICE); - await expect(tx).to.eventually.rejectedWith('AuctionHouseAuctionNotExist'); + await expect(tx).rejectedWith('AuctionHouseAuctionNotExist'); }); it(`should fail if the auction has a buyer`, async () => { @@ -492,7 +561,7 @@ describe('AuctionHouse', function () { const tx = auctionHouse.connect(randomAccount).raiseInitial(AUCTION_ID, auction.price); - await expect(tx).to.eventually.rejectedWith('AuctionHouseBuyerExists'); + await expect(tx).rejectedWith('AuctionHouseBuyerExists'); }); it(`should fail if the auction has ended`, async () => { @@ -502,8 +571,10 @@ describe('AuctionHouse', function () { const tx = auctionHouse.connect(buyer).raiseInitial(AUCTION_ID, auction.price); - await expect(tx).to.eventually.rejectedWith('AuctionHouseAuctionEnded'); + await expect(tx).rejectedWith('AuctionHouseAuctionEnded'); }); + + it(`should fail if the buyer is unauthorized`); }); describe(`method 'raise'`, () => { @@ -513,14 +584,15 @@ describe('AuctionHouse', function () { const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { auctionId: AUCTION_ID, tokenId: TOKEN_ID, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, step: AUCTION_STEP, endTime: latestBlockTimestamp + HOUR, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - shares: [TOTAL_SHARE], + shares: [ONE_HUNDRED], deadline: latestBlockTimestamp + HOUR, }; @@ -550,15 +622,15 @@ describe('AuctionHouse', function () { expect(auction.price).equal(newPrice); await expect(tx) - .to.be.emit(auctionHouse, 'Raised') + .emit(auctionHouse, 'Raised') .withArgs(AUCTION_ID, auction.buyer, auction.price); await expect(tx) - .to.be.emit(usdc, 'Transfer') + .emit(usdc, 'Transfer') .withArgs(buyerAddr, auctionHouseAddr, auction.price + auction.fee); await expect(tx) - .to.be.emit(usdc, 'Transfer') + .emit(usdc, 'Transfer') .withArgs(auctionHouseAddr, randomAccountAddr, initialPrice + fee); }); @@ -586,13 +658,13 @@ describe('AuctionHouse', function () { const tx = auctionHouse.connect(buyer).raise(AUCTION_ID, newPrice); - await expect(tx).to.eventually.rejectedWith('AuctionHouseRaiseTooLow'); + await expect(tx).rejectedWith('AuctionHouseRaiseTooLow'); }); it(`should fail if the auction does not exist`, async () => { - const tx = auctionHouse.connect(buyer).raise(0, 2n); + const tx = auctionHouse.connect(buyer).raise(NON_EXISTENT_AUCTION_ID, AUCTION_PRICE); - await expect(tx).to.eventually.rejectedWith('AuctionHouseAuctionNotExist'); + await expect(tx).rejectedWith('AuctionHouseAuctionNotExist'); }); it(`should fail if the auction has ended`, async () => { @@ -604,7 +676,7 @@ describe('AuctionHouse', function () { const tx = auctionHouse.connect(buyer).raise(AUCTION_ID, initialPrice + step); - await expect(tx).to.eventually.rejectedWith('AuctionHouseAuctionEnded'); + await expect(tx).rejectedWith('AuctionHouseAuctionEnded'); }); it(`should fail if the auction does not have a buyer`, async () => { @@ -612,8 +684,10 @@ describe('AuctionHouse', function () { const tx = auctionHouse.connect(buyer).raise(AUCTION_ID, initialPrice + step); - await expect(tx).to.eventually.rejectedWith('AuctionHouseBuyerNotExists'); + await expect(tx).rejectedWith('AuctionHouseBuyerNotExists'); }); + + it(`should fail if the buyer is unauthorized`); }); describe(`method 'finish'`, async () => { @@ -623,14 +697,15 @@ describe('AuctionHouse', function () { const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { auctionId: AUCTION_ID, tokenId: TOKEN_ID, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, step: AUCTION_STEP, endTime: latestBlockTimestamp + HOUR, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - shares: [TOTAL_SHARE], + shares: [ONE_HUNDRED], deadline: latestBlockTimestamp + HOUR, }; @@ -645,8 +720,7 @@ describe('AuctionHouse', function () { }); it(`should finish the auction`, async () => { - const { price, endTime, fee, participants, shares } = - await auctionHouse.auction(AUCTION_ID); + const { price, endTime, fee } = await auctionHouse.auction(AUCTION_ID); await auctionHouse.connect(buyer).raiseInitial(AUCTION_ID, price); @@ -659,26 +733,38 @@ describe('AuctionHouse', function () { expect(auction.sold).equal(true); await expect(tx) // - .to.be.emit(auctionHouse, 'Sold') + .emit(auctionHouse, 'Sold') .withArgs(AUCTION_ID); - await expect(tx) - .to.be.emit(usdc, 'Transfer') + await expect(tx) // + .emit(artToken, 'Transfer') + .withArgs(ZeroAddress, buyerAddr, TOKEN_ID); + + await expect(tx) // + .emit(usdc, 'Transfer') .withArgs(auctionHouseAddr, financierAddr, fee); + }); - await expect(tx) - .to.be.emit(artToken, 'Transfer') - .withArgs(ZeroAddress, buyerAddr, TOKEN_ID); + it(`should mint the token with correct token config`, async () => { + const { price, endTime } = await auctionHouse.auction(AUCTION_ID); - await expect(tx) - .to.be.emit(usdc, 'Transfer') - .withArgs(auctionHouseAddr, participants[0], (price * shares[0]) / TOTAL_SHARE); + await auctionHouse.connect(buyer).raiseInitial(AUCTION_ID, price); + + await setNextBlockTimestamp(endTime); + + await auctionHouse.connect(buyer).finish(AUCTION_ID); + + const tokenCreator = await artToken.tokenCreator(TOKEN_ID); + const tokenRegulationMode = await artToken.tokenRegulationMode(TOKEN_ID); + + expect(tokenCreator).equal(TOKEN_CREATOR_ADDR); + expect(tokenRegulationMode).equal(TOKEN_REGULATION_MODE); }); it(`should fail if the auction does not exist`, async () => { - const tx = auctionHouse.connect(buyer).finish(0); + const tx = auctionHouse.connect(buyer).finish(NON_EXISTENT_AUCTION_ID); - await expect(tx).to.eventually.rejectedWith('AuctionHouseAuctionNotExist'); + await expect(tx).rejectedWith('AuctionHouseAuctionNotExist'); }); it(`should fail if the token has been sold`, async () => { @@ -692,7 +778,7 @@ describe('AuctionHouse', function () { const tx = auctionHouse.connect(buyer).finish(AUCTION_ID); - await expect(tx).to.eventually.rejectedWith('AuctionHouseTokenSold'); + await expect(tx).rejectedWith('AuctionHouseTokenSold'); }); it(`should fail if the auction has not ended`, async () => { @@ -702,7 +788,7 @@ describe('AuctionHouse', function () { const tx = auctionHouse.connect(buyer).finish(AUCTION_ID); - await expect(tx).to.eventually.rejectedWith('AuctionHouseAuctionNotEnded'); + await expect(tx).rejectedWith('AuctionHouseAuctionNotEnded'); }); it(`should fail if the auction does not have a buyer`, async () => { @@ -712,7 +798,85 @@ describe('AuctionHouse', function () { const tx = auctionHouse.connect(buyer).finish(AUCTION_ID); - await expect(tx).to.eventually.rejectedWith('AuctionHouseBuyerNotExists'); + await expect(tx).rejectedWith('AuctionHouseBuyerNotExists'); + }); + }); + + describe(`method 'cancel'`, () => { + beforeEach(async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + + const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { + auctionId: AUCTION_ID, + tokenId: TOKEN_ID, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, + step: AUCTION_STEP, + endTime: latestBlockTimestamp + HOUR, + tokenURI: TOKEN_URI, + tokenConfig: TOKEN_CONFIG, + participants: [institutionAddr], + shares: [ONE_HUNDRED], + deadline: latestBlockTimestamp + HOUR, + }; + + await AuctionHouseUtils.create({ + auctionHouse, + permit: auctionCreationPermit, + permitSigner: auctionHouseSigner, + sender: institution, + }); + + await usdc.connect(buyer).mintAndApprove(auctionHouse, MaxInt256); + }); + + it(`should cancel the auction by setting block timestamp as the end time`, async () => { + const { endTime: originalEndTime } = await auctionHouse.auction(AUCTION_ID); + + const tx = await auctionHouse.connect(admin).cancel(AUCTION_ID); + + const blockTimestamp = await getLatestBlockTimestamp(); + const { endTime } = await auctionHouse.auction(AUCTION_ID); + const tokenReserved = await auctionHouse.tokenReserved(TOKEN_ID); + + expect(endTime).lessThan(originalEndTime); + expect(endTime).equal(blockTimestamp); + expect(tokenReserved).equal(false); + + await expect(tx) // + .emit(auctionHouse, 'Cancelled') + .withArgs(AUCTION_ID); + }); + + it(`should fail if the auction does not exist`, async () => { + const tx = auctionHouse.connect(admin).cancel(SECOND_AUCTION_ID); + + await expect(tx).rejectedWith('AuctionHouseAuctionNotExist'); + }); + + it(`should fail if the auction has a buyer`, async () => { + await auctionHouse.connect(buyer).raiseInitial(AUCTION_ID, AUCTION_PRICE); + + const tx = auctionHouse.connect(admin).cancel(AUCTION_ID); + + await expect(tx).rejectedWith('AuctionHouseBuyerExists'); + }); + + it(`should fail if the auction has already ended`, async () => { + const { endTime } = await auctionHouse.auction(AUCTION_ID); + + await setNextBlockTimestamp(endTime); + + const tx = auctionHouse.connect(admin).cancel(AUCTION_ID); + + await expect(tx).rejectedWith('AuctionHouseAuctionEnded'); + }); + + it(`should fail if the sender is not the auction house admin`, async () => { + const tx = auctionHouse.connect(randomAccount).cancel(AUCTION_ID); + + await expect(tx).rejectedWith('RoleSystemUnauthorizedAccount'); }); }); @@ -723,14 +887,15 @@ describe('AuctionHouse', function () { const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { auctionId: AUCTION_ID, tokenId: TOKEN_ID, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, step: AUCTION_STEP, endTime: latestBlockTimestamp + HOUR, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - shares: [TOTAL_SHARE], + shares: [ONE_HUNDRED], deadline: latestBlockTimestamp + HOUR, }; @@ -774,9 +939,286 @@ describe('AuctionHouse', function () { }); it(`should return 'false' for a token that has never been put up for auction`, async () => { - const tokenReserved = await auctionHouse.tokenReserved(0); + const tokenReserved = await auctionHouse.tokenReserved(NON_EXISTENT_TOKEN_ID); expect(tokenReserved).equal(false); }); }); + + describe(`ShareDistributor`, () => { + beforeEach(async () => { + await usdc.connect(buyer).mintAndApprove(auctionHouse, MaxInt256); + }); + + it(`should distribute the price among participants according to shares`, async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + const endTime = latestBlockTimestamp + HOUR; + + const institutionShare = (ONE_HUNDRED / 5n) * 4n; // 80% + const platformShare = ONE_HUNDRED / 5n; // 20% + + const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { + auctionId: AUCTION_ID, + tokenId: TOKEN_ID, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, + step: AUCTION_STEP, + endTime: endTime, + tokenURI: TOKEN_URI, + tokenConfig: TOKEN_CONFIG, + participants: [institutionAddr, financierAddr], + shares: [institutionShare, platformShare], + deadline: latestBlockTimestamp + HOUR, + }; + + await AuctionHouseUtils.create({ + auctionHouse, + permit: auctionCreationPermit, + permitSigner: auctionHouseSigner, + sender: institution, + }); + + await auctionHouse.connect(buyer).raiseInitial(AUCTION_ID, AUCTION_PRICE); + + await setNextBlockTimestamp(endTime); + + const tx = await auctionHouse.connect(buyer).finish(AUCTION_ID); + + const institutionReward = (AUCTION_PRICE * institutionShare) / ONE_HUNDRED; + const platformReward = (AUCTION_PRICE * platformShare) / ONE_HUNDRED; + + await expect(tx) + .emit(usdc, 'Transfer') + .withArgs(auctionHouseAddr, institutionAddr, institutionReward); + + await expect(tx) + .emit(usdc, 'Transfer') + .withArgs(auctionHouseAddr, financierAddr, platformReward); + }); + + it(`should send the remainder of the division to the last participant`, async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + const endTime = latestBlockTimestamp + HOUR; + + const institutionShare = (ONE_HUNDRED / 5n) * 4n; // 80% + const platformShare = ONE_HUNDRED / 5n; // 20% + + const remainder = 1n; + const priceWithRemainder = 100_000_000n + remainder; + + const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { + auctionId: AUCTION_ID, + tokenId: TOKEN_ID, + currency: usdcAddr, + price: priceWithRemainder, + fee: AUCTION_FEE, + step: AUCTION_STEP, + endTime: endTime, + tokenURI: TOKEN_URI, + tokenConfig: TOKEN_CONFIG, + participants: [institutionAddr, financierAddr], + shares: [institutionShare, platformShare], + deadline: latestBlockTimestamp + HOUR, + }; + + await AuctionHouseUtils.create({ + auctionHouse, + permit: auctionCreationPermit, + permitSigner: auctionHouseSigner, + sender: institution, + }); + + await auctionHouse.connect(buyer).raiseInitial(AUCTION_ID, priceWithRemainder); + + await setNextBlockTimestamp(endTime); + + const tx = await auctionHouse.connect(buyer).finish(AUCTION_ID); + + const institutionReward = (priceWithRemainder * institutionShare) / ONE_HUNDRED; + const platformReward = (priceWithRemainder * platformShare) / ONE_HUNDRED + remainder; + + await expect(tx) + .emit(usdc, 'Transfer') + .withArgs(auctionHouseAddr, institutionAddr, institutionReward); + + await expect(tx) + .emit(usdc, 'Transfer') + .withArgs(auctionHouseAddr, financierAddr, platformReward); + }); + + it(`should fail if the number of participants and the number of shares do not match`, async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + + const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { + auctionId: AUCTION_ID, + tokenId: TOKEN_ID, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, + step: AUCTION_STEP, + endTime: latestBlockTimestamp + HOUR, + tokenURI: TOKEN_URI, + tokenConfig: TOKEN_CONFIG, + participants: [institutionAddr, financierAddr], + shares: [ONE_HUNDRED], + deadline: latestBlockTimestamp + HOUR, + }; + + const tx = AuctionHouseUtils.create({ + auctionHouse, + permit: auctionCreationPermit, + permitSigner: auctionHouseSigner, + sender: institution, + }); + + await expect(tx).rejectedWith('ShareDistributorParticipantsSharesMismatch'); + }); + + it(`should fail if the total share is greater than 100%`, async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + + const institutionShare = (ONE_HUNDRED / 5n) * 4n; // 80% + const platformShare = ONE_HUNDRED / 4n; // 25% + + const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { + auctionId: AUCTION_ID, + tokenId: TOKEN_ID, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, + step: AUCTION_STEP, + endTime: latestBlockTimestamp + HOUR, + tokenURI: TOKEN_URI, + tokenConfig: TOKEN_CONFIG, + participants: [institutionAddr, financierAddr], + shares: [institutionShare, platformShare], + deadline: latestBlockTimestamp + HOUR, + }; + + const tx = AuctionHouseUtils.create({ + auctionHouse, + permit: auctionCreationPermit, + permitSigner: auctionHouseSigner, + sender: institution, + }); + + await expect(tx).rejectedWith('ShareDistributorSharesSumInvalid(10500)'); + }); + + it(`should fail if the total share is less than 100%`, async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + + const institutionShare = (ONE_HUNDRED / 5n) * 3n; // 60% + const platformShare = ONE_HUNDRED / 5n; // 20% + + const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { + auctionId: AUCTION_ID, + tokenId: TOKEN_ID, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, + step: AUCTION_STEP, + endTime: latestBlockTimestamp + HOUR, + tokenURI: TOKEN_URI, + tokenConfig: TOKEN_CONFIG, + participants: [institutionAddr, financierAddr], + shares: [institutionShare, platformShare], + deadline: latestBlockTimestamp + HOUR, + }; + + const tx = AuctionHouseUtils.create({ + auctionHouse, + permit: auctionCreationPermit, + permitSigner: auctionHouseSigner, + sender: institution, + }); + + await expect(tx).rejectedWith('ShareDistributorSharesSumInvalid(8000)'); + }); + + it(`should fail if shares and participants are missing`, async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + + const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { + auctionId: AUCTION_ID, + tokenId: TOKEN_ID, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, + step: AUCTION_STEP, + endTime: latestBlockTimestamp + HOUR, + tokenURI: TOKEN_URI, + tokenConfig: TOKEN_CONFIG, + participants: [], + shares: [], + deadline: latestBlockTimestamp + HOUR, + }; + + const tx = AuctionHouseUtils.create({ + auctionHouse, + permit: auctionCreationPermit, + permitSigner: auctionHouseSigner, + sender: institution, + }); + + await expect(tx).rejectedWith('ShareDistributorSharesSumInvalid(0)'); + }); + + it(`should fail if a participant address is zero`, async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + + const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { + auctionId: AUCTION_ID, + tokenId: TOKEN_ID, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, + step: AUCTION_STEP, + endTime: latestBlockTimestamp + HOUR, + tokenURI: TOKEN_URI, + tokenConfig: TOKEN_CONFIG, + participants: [institutionAddr, ZeroAddress], + shares: [ONE_HUNDRED / 2n, ONE_HUNDRED / 2n], + deadline: latestBlockTimestamp + HOUR, + }; + + const tx = AuctionHouseUtils.create({ + auctionHouse, + permit: auctionCreationPermit, + permitSigner: auctionHouseSigner, + sender: institution, + }); + + await expect(tx).rejectedWith('ShareDistributorZeroAddress'); + }); + + it(`should fail if a participant has a zero share`, async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + + const auctionCreationPermit: AuctionCreationPermit.TypeStruct = { + auctionId: AUCTION_ID, + tokenId: TOKEN_ID, + currency: usdcAddr, + price: AUCTION_PRICE, + fee: AUCTION_FEE, + step: AUCTION_STEP, + endTime: latestBlockTimestamp + HOUR, + tokenURI: TOKEN_URI, + tokenConfig: TOKEN_CONFIG, + participants: [institutionAddr, financierAddr], + shares: [ONE_HUNDRED, 0n], + deadline: latestBlockTimestamp + HOUR, + }; + + const tx = AuctionHouseUtils.create({ + auctionHouse, + permit: auctionCreationPermit, + permitSigner: auctionHouseSigner, + sender: institution, + }); + + await expect(tx).rejectedWith('ShareDistributorZeroShare'); + }); + }); }); diff --git a/tests/Authorization.ts b/tests/Authorization.ts index d1681b7..98bdb19 100644 --- a/tests/Authorization.ts +++ b/tests/Authorization.ts @@ -1,9 +1,8 @@ import { expect } from 'chai'; import { Signer, MaxInt256 } from 'ethers'; import { ArtToken, USDC } from '../typechain-types'; -import { MIN_FEE, MIN_PRICE } from './constants/min-price-and-fee'; -import { TOKEN_CONFIG, TOKEN_ID, TOKEN_URI } from './constants/art-token'; -import { HOUR } from './constants/time'; +import { HOUR } from './constants/general'; +import { TOKEN_CONFIG, TOKEN_FEE, TOKEN_ID, TOKEN_PRICE, TOKEN_URI } from './constants/art-token'; import { getSigners } from './utils/get-signers'; import { getLatestBlockTimestamp } from './utils/get-latest-block-timestamp'; import { deployAll } from './utils/deploy-all'; @@ -50,12 +49,13 @@ describe('Authorization', function () { const tokenMintingPermit: TokenMintingPermit.TypeStruct = { tokenId: TOKEN_ID, minter: buyerAddr, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - rewards: [MIN_PRICE], + rewards: [TOKEN_PRICE], deadline: latestBlockTimestamp + HOUR, }; @@ -73,12 +73,13 @@ describe('Authorization', function () { const tokenMintingPermit: TokenMintingPermit.TypeStruct = { tokenId: TOKEN_ID, minter: buyerAddr, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - rewards: [MIN_PRICE], + rewards: [TOKEN_PRICE], deadline: latestBlockTimestamp - HOUR, // Wrong deadline }; @@ -89,7 +90,7 @@ describe('Authorization', function () { sender: buyer, }); - await expect(tx).to.be.rejectedWith('AuthorizationDeadlineExpired'); + await expect(tx).rejectedWith('AuthorizationDeadlineExpired'); }); it(`should fail if the signer is invalid`, async () => { @@ -98,12 +99,13 @@ describe('Authorization', function () { const tokenMintingPermit: TokenMintingPermit.TypeStruct = { tokenId: TOKEN_ID, minter: buyerAddr, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - rewards: [MIN_PRICE], + rewards: [TOKEN_PRICE], deadline: latestBlockTimestamp + HOUR, }; @@ -114,7 +116,7 @@ describe('Authorization', function () { sender: buyer, }); - await expect(tx).to.be.rejectedWith('AuthorizationUnauthorizedAction'); + await expect(tx).rejectedWith('AuthorizationUnauthorizedAction'); }); }); }); diff --git a/tests/CurrencyManager.ts b/tests/CurrencyManager.ts index 12764e7..2aa6cff 100644 --- a/tests/CurrencyManager.ts +++ b/tests/CurrencyManager.ts @@ -35,35 +35,39 @@ describe('CurrencyManager', function () { describe(`method 'currencyAllowed'`, () => { it(`should return true if the currency is allowed`, async () => { - expect(await currencyManager.currencyAllowed(usdcAddr)).to.be.true; + const currencyAllowed = await currencyManager.currencyAllowed(usdcAddr); + + expect(currencyAllowed).equal(true); }); it(`should return false if the currency is not allowed`, async () => { - expect(await currencyManager.currencyAllowed(ZeroAddress)).to.be.false; + const currencyAllowed = await currencyManager.currencyAllowed(ZeroAddress); + + expect(currencyAllowed).equal(false); }); }); describe(`method 'updateCurrencyStatus'`, () => { it(`should update the currency status if the caller is an admin`, async () => { - expect(await currencyManager.currencyAllowed(usdcAddr)).to.be.true; + const currencyAllowedBefore = await currencyManager.currencyAllowed(usdcAddr); - await expect(currencyManager.connect(admin).updateCurrencyStatus(usdcAddr, false)) - .to.emit(currencyManager, 'CurrencyStatusUpdated') - .withArgs(usdcAddr, false); + expect(currencyAllowedBefore).equal(true); - expect(await currencyManager.currencyAllowed(usdcAddr)).to.be.false; + const tx = await currencyManager.connect(admin).updateCurrencyStatus(usdcAddr, false); - await expect(currencyManager.connect(admin).updateCurrencyStatus(usdcAddr, true)) - .to.emit(currencyManager, 'CurrencyStatusUpdated') - .withArgs(usdcAddr, true); + const currencyAllowedAfter = await currencyManager.currencyAllowed(usdcAddr); - expect(await currencyManager.currencyAllowed(usdcAddr)).to.be.true; + expect(currencyAllowedAfter).equal(false); + + await expect(tx) + .emit(currencyManager, 'CurrencyStatusUpdated') + .withArgs(usdcAddr, false); }); it(`should fail if the caller is not an admin`, async () => { - await expect( - currencyManager.connect(randomAccount).updateCurrencyStatus(usdcAddr, false), - ).to.be.revertedWithCustomError(currencyManager, 'RoleSystemUnauthorizedAccount'); + const tx = currencyManager.connect(randomAccount).updateCurrencyStatus(usdcAddr, false); + + await expect(tx).rejectedWith('RoleSystemUnauthorizedAccount'); }); }); }); diff --git a/tests/Distribution.ts b/tests/Distribution.ts deleted file mode 100644 index b84c20a..0000000 --- a/tests/Distribution.ts +++ /dev/null @@ -1,238 +0,0 @@ -import { expect } from 'chai'; -import { Signer, MaxInt256 } from 'ethers'; -import { ArtToken, USDC } from '../typechain-types'; -import { BuyPermitStruct } from '../types/art-token'; -import { MIN_FEE, MIN_PRICE } from './constants/min-price-and-fee'; -import { TOTAL_SHARE } from './constants/distribution'; -import { TOKEN_ID, TOKEN_URI } from './constants/art-token'; -import { HOUR } from './constants/time'; -import { getSigners } from './utils/get-signers'; -import { getLatestBlockTimestamp } from './utils/get-latest-block-timestamp'; -import { deployAll } from './utils/deploy-all'; -import { ArtTokenUtils } from './utils/art-token-utils'; - -/** - * TODO: - * - test this module with AuctionHouse - */ -describe.skip('Distribution', function () { - let artToken: ArtToken, artTokenAddr: string; - let usdc: USDC, usdcAddr: string; - - let artTokenSigner: Signer, artTokenSignerAddr: string; - let financier: Signer, financierAddr: string; - let institution: Signer, institutionAddr: string; - let buyer: Signer, buyerAddr: string; - - before(async () => { - [ - [artTokenSigner, financier, institution, buyer], - [artTokenSignerAddr, financierAddr, institutionAddr, buyerAddr], - ] = await getSigners(); - }); - - beforeEach(async () => { - const all = await deployAll({ - signer: artTokenSigner, - financier, - }); - - artToken = all.artToken; - artTokenAddr = all.artTokenAddr; - usdc = all.usdc; - usdcAddr = all.usdcAddr; - }); - - describe(`method 'safeDistribute'`, () => { - beforeEach(async () => { - await usdc.connect(buyer).mintAndApprove(artToken, MaxInt256); - }); - - it(`should distribute the price among participants according to shares`, async () => { - const latestBlockTimestamp = await getLatestBlockTimestamp(); - - const institutionShare = (TOTAL_SHARE / 5n) * 4n; // 80% - const platformShare = TOTAL_SHARE / 5n; // 20% - - const price = MIN_PRICE; - - const buyPermit: BuyPermitStruct = { - tokenId: TOKEN_ID, - tokenURI: TOKEN_URI, - sender: buyerAddr, - price, - fee: MIN_FEE, - participants: [institutionAddr, financierAddr], - shares: [institutionShare, platformShare], - deadline: latestBlockTimestamp + HOUR, - }; - - const tx = await ArtTokenUtils.buy({ - artToken, - permit: buyPermit, - permitSigner: artTokenSigner, - sender: buyer, - }); - - await expect(tx) - .to.be.emit(usdc, 'Transfer') - .withArgs(artTokenAddr, institutionAddr, (price * institutionShare) / TOTAL_SHARE); - - await expect(tx) - .to.be.emit(usdc, 'Transfer') - .withArgs(artTokenAddr, financierAddr, (price * platformShare) / TOTAL_SHARE); - }); - - it(`should send the remainder of the division to the last participant`, async () => { - const latestBlockTimestamp = await getLatestBlockTimestamp(); - - const institutionShare = (TOTAL_SHARE / 5n) * 4n; // 80% - const platformShare = TOTAL_SHARE / 5n; // 20% - - const remainder = 1n; - const price = 100_000_000n + remainder; - - const buyPermit: BuyPermitStruct = { - tokenId: TOKEN_ID, - tokenURI: TOKEN_URI, - sender: buyerAddr, - price, - fee: MIN_FEE, - participants: [institutionAddr, financierAddr], - shares: [institutionShare, platformShare], - deadline: latestBlockTimestamp + HOUR, - }; - - const tx = await ArtTokenUtils.buy({ - artToken, - permit: buyPermit, - permitSigner: artTokenSigner, - sender: buyer, - }); - - await expect(tx) - .to.be.emit(usdc, 'Transfer') - .withArgs(artTokenAddr, institutionAddr, (price * institutionShare) / TOTAL_SHARE); - - await expect(tx) - .to.be.emit(usdc, 'Transfer') - .withArgs( - artTokenAddr, - financierAddr, - (price * platformShare) / TOTAL_SHARE + remainder, - ); - }); - - it(`should fail if the number of participants and the number of shares do not match`, async () => { - const latestBlockTimestamp = await getLatestBlockTimestamp(); - - const institutionShare = TOTAL_SHARE; - - const price = MIN_PRICE; - - const buyPermit: BuyPermitStruct = { - tokenId: TOKEN_ID, - tokenURI: TOKEN_URI, - sender: buyerAddr, - price, - fee: MIN_FEE, - participants: [institutionAddr, financierAddr], - shares: [institutionShare], - deadline: latestBlockTimestamp + HOUR, - }; - - const tx = ArtTokenUtils.buy({ - artToken, - permit: buyPermit, - permitSigner: artTokenSigner, - sender: buyer, - }); - - await expect(tx).to.be.rejectedWith('DistributionParticipantsSharesMismatch'); - }); - - it(`should fail if the total share is greater than 100%`, async () => { - const latestBlockTimestamp = await getLatestBlockTimestamp(); - - const institutionShare = (TOTAL_SHARE / 5n) * 4n; // 80% - const platformShare = TOTAL_SHARE / 4n; // 25% - - const price = MIN_PRICE; - - const buyPermit: BuyPermitStruct = { - tokenId: TOKEN_ID, - tokenURI: TOKEN_URI, - sender: buyerAddr, - price, - fee: MIN_FEE, - participants: [institutionAddr, financierAddr], - shares: [institutionShare, platformShare], - deadline: latestBlockTimestamp + HOUR, - }; - - const tx = ArtTokenUtils.buy({ - artToken, - permit: buyPermit, - permitSigner: artTokenSigner, - sender: buyer, - }); - - await expect(tx).to.be.rejectedWith('DistributionSharesSumInvalid(10500)'); - }); - - it(`should fail if the total share is less than 100%`, async () => { - const latestBlockTimestamp = await getLatestBlockTimestamp(); - - const institutionShare = (TOTAL_SHARE / 5n) * 3n; // 60% - const platformShare = TOTAL_SHARE / 5n; // 20% - - const price = MIN_PRICE; - - const buyPermit: BuyPermitStruct = { - tokenId: TOKEN_ID, - tokenURI: TOKEN_URI, - sender: buyerAddr, - price, - fee: MIN_FEE, - participants: [institutionAddr, financierAddr], - shares: [institutionShare, platformShare], - deadline: latestBlockTimestamp + HOUR, - }; - - const tx = ArtTokenUtils.buy({ - artToken, - permit: buyPermit, - permitSigner: artTokenSigner, - sender: buyer, - }); - - await expect(tx).to.be.rejectedWith('DistributionSharesSumInvalid(8000)'); - }); - - it(`should fail if shares and participants are missing`, async () => { - const latestBlockTimestamp = await getLatestBlockTimestamp(); - - const price = MIN_PRICE; - - const buyPermit: BuyPermitStruct = { - tokenId: TOKEN_ID, - tokenURI: TOKEN_URI, - sender: buyerAddr, - price, - fee: MIN_FEE, - participants: [], - shares: [], - deadline: latestBlockTimestamp + HOUR, - }; - - const tx = ArtTokenUtils.buy({ - artToken, - permit: buyPermit, - permitSigner: artTokenSigner, - sender: buyer, - }); - - await expect(tx).to.be.rejectedWith('DistributionSharesSumInvalid(0)'); - }); - }); -}); diff --git a/tests/Market.ts b/tests/Market.ts index 32a783a..53d741e 100644 --- a/tests/Market.ts +++ b/tests/Market.ts @@ -3,10 +3,9 @@ import { Signer, MaxInt256, randomBytes } from 'ethers'; import { ArtToken, Market, USDC } from '../typechain-types'; import { TokenMintingPermit } from '../typechain-types/contracts/art-token/ArtToken'; import { Order, OrderExecutionPermit } from '../typechain-types/contracts/market/Market'; -import { TOKEN_CONFIG, TOKEN_ID, TOKEN_URI } from './constants/art-token'; -import { MIN_FEE, MIN_PRICE } from './constants/min-price-and-fee'; -import { PRICE, ASK_SIDE_FEE, BID_SIDE_FEE, ASK_SIDE, BID_SIDE } from './constants/market'; -import { HOUR } from './constants/time'; +import { TOKEN_CONFIG, TOKEN_FEE, TOKEN_ID, TOKEN_PRICE, TOKEN_URI } from './constants/art-token'; +import { HOUR } from './constants/general'; +import { ORDER_PRICE, ASK_SIDE_FEE, BID_SIDE_FEE, ASK_SIDE, BID_SIDE } from './constants/market'; import { getSigners } from './utils/get-signers'; import { getLatestBlockTimestamp } from './utils/get-latest-block-timestamp'; import { deployAll } from './utils/deploy-all'; @@ -67,12 +66,13 @@ describe('Market', function () { const tokenMintingPermit: TokenMintingPermit.TypeStruct = { tokenId: TOKEN_ID, minter: makerAddr, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - rewards: [MIN_PRICE], + rewards: [TOKEN_PRICE], deadline: latestBlockTimestamp + HOUR, }; @@ -93,9 +93,9 @@ describe('Market', function () { it(`should execute the order`, async () => { const latestBlockTimestamp = await getLatestBlockTimestamp(); - const askSideReward = PRICE - ASK_SIDE_FEE; - const institutionReward = PRICE - askSideReward - 100n; - const platformReward = PRICE - askSideReward - institutionReward; + const askSideReward = ORDER_PRICE - ASK_SIDE_FEE; + const platformReward = 100n; + const institutionReward = ASK_SIDE_FEE - platformReward; const order: Order.TypeStruct = { side: ASK_SIDE, @@ -103,7 +103,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: ASK_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -129,35 +129,45 @@ describe('Market', function () { sender: taker, }); + const orderInvalidated = await market.orderInvalidated(maker, orderHash); + + expect(orderInvalidated).equal(true); + await expect(tx) - .to.be.emit(usdc, 'Transfer') - .withArgs(takerAddr, marketAddr, PRICE + BID_SIDE_FEE); + .emit(usdc, 'Transfer') + .withArgs(takerAddr, marketAddr, ORDER_PRICE + BID_SIDE_FEE); await expect(tx) - .to.be.emit(usdc, 'Transfer') // + .emit(usdc, 'Transfer') .withArgs(marketAddr, financierAddr, BID_SIDE_FEE); - await expect(tx) - .to.be.emit(usdc, 'Transfer') + await expect(tx) // + .emit(usdc, 'Transfer') .withArgs(marketAddr, makerAddr, askSideReward); await expect(tx) - .to.be.emit(usdc, 'Transfer') + .emit(usdc, 'Transfer') .withArgs(marketAddr, institutionAddr, institutionReward); await expect(tx) - .to.be.emit(usdc, 'Transfer') + .emit(usdc, 'Transfer') .withArgs(marketAddr, financierAddr, platformReward); - await expect(tx) - .to.be.emit(artToken, 'Transfer') // + await expect(tx) // + .emit(artToken, 'Transfer') .withArgs(makerAddr, takerAddr, TOKEN_ID); await expect(tx) - .to.be.emit(market, 'AskOrderExecuted') - .withArgs(orderHash, artTokenAddr, usdcAddr, makerAddr, takerAddr, TOKEN_ID, PRICE); - - await expect(market.orderInvalidated(maker, orderHash)).to.eventually.equal(true); + .emit(market, 'AskOrderExecuted') + .withArgs( + orderHash, + artTokenAddr, + usdcAddr, + makerAddr, + takerAddr, + TOKEN_ID, + ORDER_PRICE, + ); }); it(`should execute the order with zero maker fee`, async () => { @@ -169,7 +179,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: 0n, // Zero fee startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -195,7 +205,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.be.emit(usdc, 'Transfer').withArgs(marketAddr, makerAddr, PRICE); // Full price to maker + await expect(tx).emit(usdc, 'Transfer').withArgs(marketAddr, makerAddr, ORDER_PRICE); // Full price to maker }); it(`should execute the order with zero taker fee`, async () => { @@ -207,7 +217,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: ASK_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -233,7 +243,9 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.be.emit(usdc, 'Transfer').withArgs(takerAddr, marketAddr, PRICE); // Only price, no fee + await expect(tx) // + .emit(usdc, 'Transfer') + .withArgs(takerAddr, marketAddr, ORDER_PRICE); // Only price, no fee }); it(`should fail if the order start time is greater than the current time`, async () => { @@ -248,7 +260,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: ASK_SIDE_FEE, startTime, endTime, @@ -272,7 +284,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketOrderOutsideOfTimeRange'); + await expect(tx).rejectedWith('MarketOrderOutsideOfTimeRange'); }); it(`should fail if the order end time is less than the current time`, async () => { @@ -287,7 +299,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: ASK_SIDE_FEE, startTime, endTime, @@ -311,7 +323,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketOrderOutsideOfTimeRange'); + await expect(tx).rejectedWith('MarketOrderOutsideOfTimeRange'); }); it(`should fail if the order signer is not the maker`, async () => { @@ -323,7 +335,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: ASK_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -347,7 +359,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketUnauthorizedOrder'); + await expect(tx).rejectedWith('MarketUnauthorizedOrder'); }); it(`should fail if the permit order hash and the order hash do not match`, async () => { @@ -359,7 +371,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: ASK_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -383,7 +395,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketInvalidOrderHash'); + await expect(tx).rejectedWith('MarketInvalidOrderHash'); }); it(`should fail if the permit signer is not the market signer`, async () => { @@ -395,7 +407,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: ASK_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -419,7 +431,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('AuthorizationUnauthorizedAction'); + await expect(tx).rejectedWith('AuthorizationUnauthorizedAction'); }); it(`should fail if the order is invalidated`, async () => { @@ -431,7 +443,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: ASK_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -459,7 +471,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketOrderInvalidated'); + await expect(tx).rejectedWith('MarketOrderInvalidated'); }); it(`should fail if the order side is not Ask`, async () => { @@ -471,7 +483,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: ASK_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -495,7 +507,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketInvalidOrderSide'); + await expect(tx).rejectedWith('MarketInvalidOrderSide'); }); it(`should fail if the ask side fee is greater than or equal to the price`, async () => { @@ -507,8 +519,8 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, - makerFee: PRICE, // Fee equals price + price: ORDER_PRICE, + makerFee: ORDER_PRICE, // Fee equals price startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, }; @@ -531,7 +543,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketInvalidAskSideFee'); + await expect(tx).rejectedWith('MarketInvalidAskSideFee'); }); it(`should fail if the currency is not allowed`, async () => { @@ -543,7 +555,7 @@ describe('Market', function () { currency: randomAccountAddr, // Invalid currency maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: ASK_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -567,10 +579,10 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketCurrencyInvalid'); + await expect(tx).rejectedWith('MarketCurrencyInvalid'); }); - it(`should fail if the permit taker is not the sender`, async () => { + it(`should fail if the sender is not the permitted taker`, async () => { const latestBlockTimestamp = await getLatestBlockTimestamp(); const order: Order.TypeStruct = { @@ -579,7 +591,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: ASK_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -603,7 +615,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketUnauthorizedAccount'); + await expect(tx).rejectedWith('MarketUnauthorizedAccount'); }); it(`should fail if the permit deadline has expired`, async () => { @@ -615,7 +627,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: ASK_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -639,7 +651,81 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('AuthorizationDeadlineExpired'); + await expect(tx).rejectedWith('AuthorizationDeadlineExpired'); + }); + + it(`should fail if the sum of rewards is greater than the ask side fee`, async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + + const order: Order.TypeStruct = { + side: ASK_SIDE, + collection: artTokenAddr, + currency: usdcAddr, + maker: makerAddr, + tokenId: TOKEN_ID, + price: ORDER_PRICE, + makerFee: ASK_SIDE_FEE, + startTime: latestBlockTimestamp, + endTime: latestBlockTimestamp + HOUR, + }; + + const orderExecutionPermit: OrderExecutionPermit.TypeStruct = { + orderHash: MarketUtils.hashOrder(order), + taker: takerAddr, + takerFee: BID_SIDE_FEE, + participants: [institutionAddr], + rewards: [ASK_SIDE_FEE + 1n], // Incorrect rewards sum + deadline: latestBlockTimestamp + HOUR, + }; + + await usdc.connect(taker).transfer(marketAddr, 1n); + + const tx = MarketUtils.executeAsk({ + market, + order, + permit: orderExecutionPermit, + orderSigner: maker, + permitSigner: marketSigner, + sender: taker, + }); + + await expect(tx).rejectedWith('SafeERC20BulkTransferIncorrectTotalAmount'); + }); + + it(`should fail if the sum of rewards is less than the ask side fee`, async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + + const order: Order.TypeStruct = { + side: ASK_SIDE, + collection: artTokenAddr, + currency: usdcAddr, + maker: makerAddr, + tokenId: TOKEN_ID, + price: ORDER_PRICE, + makerFee: ASK_SIDE_FEE, + startTime: latestBlockTimestamp, + endTime: latestBlockTimestamp + HOUR, + }; + + const orderExecutionPermit: OrderExecutionPermit.TypeStruct = { + orderHash: MarketUtils.hashOrder(order), + taker: takerAddr, + takerFee: BID_SIDE_FEE, + participants: [institutionAddr], + rewards: [ASK_SIDE_FEE - 1n], // Incorrect rewards sum + deadline: latestBlockTimestamp + HOUR, + }; + + const tx = MarketUtils.executeAsk({ + market, + order, + permit: orderExecutionPermit, + orderSigner: maker, + permitSigner: marketSigner, + sender: taker, + }); + + await expect(tx).rejectedWith('SafeERC20BulkTransferIncorrectTotalAmount'); }); }); @@ -648,18 +734,20 @@ describe('Market', function () { * MAKER is BID_SIDE * TAKER is ASK_SIDE */ + beforeEach(async () => { const latestBlockTimestamp = await getLatestBlockTimestamp(); const tokenMintingPermit: TokenMintingPermit.TypeStruct = { tokenId: TOKEN_ID, minter: takerAddr, - price: MIN_PRICE, - fee: MIN_FEE, + currency: usdcAddr, + price: TOKEN_PRICE, + fee: TOKEN_FEE, tokenURI: TOKEN_URI, tokenConfig: TOKEN_CONFIG, participants: [institutionAddr], - rewards: [MIN_PRICE], + rewards: [TOKEN_PRICE], deadline: latestBlockTimestamp + HOUR, }; @@ -680,9 +768,9 @@ describe('Market', function () { it(`should execute the order`, async () => { const latestBlockTimestamp = await getLatestBlockTimestamp(); - const askSideReward = PRICE - ASK_SIDE_FEE; - const institutionReward = PRICE - askSideReward - 100n; - const platformReward = PRICE - askSideReward - institutionReward; + const askSideReward = ORDER_PRICE - ASK_SIDE_FEE; + const platformReward = 100n; + const institutionReward = ASK_SIDE_FEE - platformReward; const order: Order.TypeStruct = { side: BID_SIDE, @@ -690,7 +778,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: BID_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -716,35 +804,45 @@ describe('Market', function () { sender: taker, }); + const orderInvalidated = await market.orderInvalidated(maker, orderHash); + + expect(orderInvalidated).equal(true); + await expect(tx) - .to.be.emit(usdc, 'Transfer') - .withArgs(makerAddr, marketAddr, PRICE + BID_SIDE_FEE); + .emit(usdc, 'Transfer') + .withArgs(makerAddr, marketAddr, ORDER_PRICE + BID_SIDE_FEE); await expect(tx) - .to.be.emit(usdc, 'Transfer') // + .emit(usdc, 'Transfer') .withArgs(marketAddr, financierAddr, BID_SIDE_FEE); - await expect(tx) - .to.be.emit(usdc, 'Transfer') + await expect(tx) // + .emit(usdc, 'Transfer') .withArgs(marketAddr, takerAddr, askSideReward); await expect(tx) - .to.be.emit(usdc, 'Transfer') + .emit(usdc, 'Transfer') .withArgs(marketAddr, institutionAddr, institutionReward); await expect(tx) - .to.be.emit(usdc, 'Transfer') + .emit(usdc, 'Transfer') .withArgs(marketAddr, financierAddr, platformReward); - await expect(tx) - .to.be.emit(artToken, 'Transfer') // + await expect(tx) // + .emit(artToken, 'Transfer') .withArgs(takerAddr, makerAddr, TOKEN_ID); await expect(tx) - .to.be.emit(market, 'BidOrderExecuted') - .withArgs(orderHash, artTokenAddr, usdcAddr, makerAddr, takerAddr, TOKEN_ID, PRICE); - - await expect(market.orderInvalidated(maker, orderHash)).to.eventually.equal(true); + .emit(market, 'BidOrderExecuted') + .withArgs( + orderHash, + artTokenAddr, + usdcAddr, + makerAddr, + takerAddr, + TOKEN_ID, + ORDER_PRICE, + ); }); it(`should execute the order with zero maker fee`, async () => { @@ -756,7 +854,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: 0n, // Zero fee startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -782,7 +880,9 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.be.emit(usdc, 'Transfer').withArgs(makerAddr, marketAddr, PRICE); // Only price, no fee from maker + await expect(tx) // + .emit(usdc, 'Transfer') + .withArgs(makerAddr, marketAddr, ORDER_PRICE); // Only price, no fee from maker }); it(`should execute the order with zero taker fee`, async () => { @@ -794,7 +894,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: BID_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -820,7 +920,9 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.be.emit(usdc, 'Transfer').withArgs(marketAddr, takerAddr, PRICE); // Full price to taker + await expect(tx) // + .emit(usdc, 'Transfer') + .withArgs(marketAddr, takerAddr, ORDER_PRICE); // Full price to taker }); it(`should fail if the order start time is greater than the current time`, async () => { @@ -835,7 +937,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: BID_SIDE_FEE, startTime, endTime, @@ -859,7 +961,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketOrderOutsideOfTimeRange'); + await expect(tx).rejectedWith('MarketOrderOutsideOfTimeRange'); }); it(`should fail if the order end time is less than the current time`, async () => { @@ -874,7 +976,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: BID_SIDE_FEE, startTime, endTime, @@ -898,7 +1000,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketOrderOutsideOfTimeRange'); + await expect(tx).rejectedWith('MarketOrderOutsideOfTimeRange'); }); it(`should fail if the order signer is not the maker`, async () => { @@ -910,7 +1012,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: BID_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -934,7 +1036,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketUnauthorizedOrder'); + await expect(tx).rejectedWith('MarketUnauthorizedOrder'); }); it(`should fail if the permit order hash and the order hash do not match`, async () => { @@ -946,7 +1048,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: BID_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -970,7 +1072,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketInvalidOrderHash'); + await expect(tx).rejectedWith('MarketInvalidOrderHash'); }); it(`should fail if the permit signer is not the market signer`, async () => { @@ -982,7 +1084,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: BID_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -1006,7 +1108,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('AuthorizationUnauthorizedAction'); + await expect(tx).rejectedWith('AuthorizationUnauthorizedAction'); }); it(`should fail if the order is invalidated`, async () => { @@ -1018,7 +1120,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: BID_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -1046,7 +1148,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketOrderInvalidated'); + await expect(tx).rejectedWith('MarketOrderInvalidated'); }); it(`should fail if the order side is not Bid`, async () => { @@ -1058,7 +1160,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: BID_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -1082,7 +1184,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketInvalidOrderSide'); + await expect(tx).rejectedWith('MarketInvalidOrderSide'); }); it(`should fail if the ask side fee is greater than or equal to the price`, async () => { @@ -1094,7 +1196,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: BID_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -1103,7 +1205,7 @@ describe('Market', function () { const orderExecutionPermit: OrderExecutionPermit.TypeStruct = { orderHash: MarketUtils.hashOrder(order), taker: takerAddr, - takerFee: PRICE, // Fee equals price + takerFee: ORDER_PRICE, // Fee equals price participants: [institutionAddr], rewards: [ASK_SIDE_FEE], deadline: latestBlockTimestamp + HOUR, @@ -1118,7 +1220,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketInvalidAskSideFee'); + await expect(tx).rejectedWith('MarketInvalidAskSideFee'); }); it(`should fail if the currency is not allowed`, async () => { @@ -1130,7 +1232,7 @@ describe('Market', function () { currency: randomAccountAddr, // Invalid currency maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: BID_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -1154,10 +1256,10 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketCurrencyInvalid'); + await expect(tx).rejectedWith('MarketCurrencyInvalid'); }); - it(`should fail if the permit taker is not the sender`, async () => { + it(`should fail if the sender is not the permitted taker`, async () => { const latestBlockTimestamp = await getLatestBlockTimestamp(); const order: Order.TypeStruct = { @@ -1166,7 +1268,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: BID_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -1190,7 +1292,7 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('MarketUnauthorizedAccount'); + await expect(tx).rejectedWith('MarketUnauthorizedAccount'); }); it(`should fail if the permit deadline has expired`, async () => { @@ -1202,7 +1304,7 @@ describe('Market', function () { currency: usdcAddr, maker: makerAddr, tokenId: TOKEN_ID, - price: PRICE, + price: ORDER_PRICE, makerFee: BID_SIDE_FEE, startTime: latestBlockTimestamp, endTime: latestBlockTimestamp + HOUR, @@ -1226,19 +1328,81 @@ describe('Market', function () { sender: taker, }); - await expect(tx).to.eventually.rejectedWith('AuthorizationDeadlineExpired'); + await expect(tx).rejectedWith('AuthorizationDeadlineExpired'); }); - }); - describe(`method 'orderInvalidated'`, () => { - it(`should return the correct value`, async () => { - const orderHash = randomBytes(32); + it(`should fail if the sum of rewards is greater than the ask side fee`, async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); - await expect(market.orderInvalidated(maker, orderHash)).to.eventually.equal(false); + const order: Order.TypeStruct = { + side: BID_SIDE, + collection: artTokenAddr, + currency: usdcAddr, + maker: makerAddr, + tokenId: TOKEN_ID, + price: ORDER_PRICE, + makerFee: BID_SIDE_FEE, + startTime: latestBlockTimestamp, + endTime: latestBlockTimestamp + HOUR, + }; - await market.connect(maker).invalidateOrder(maker, orderHash); + const orderExecutionPermit: OrderExecutionPermit.TypeStruct = { + orderHash: MarketUtils.hashOrder(order), + taker: takerAddr, + takerFee: ASK_SIDE_FEE, + participants: [institutionAddr], + rewards: [ASK_SIDE_FEE + 1n], // Incorrect rewards sum + deadline: latestBlockTimestamp + HOUR, + }; - await expect(market.orderInvalidated(maker, orderHash)).to.eventually.equal(true); + await usdc.connect(taker).transfer(marketAddr, 1n); + + const tx = MarketUtils.executeBid({ + market, + order, + permit: orderExecutionPermit, + orderSigner: maker, + permitSigner: marketSigner, + sender: taker, + }); + + await expect(tx).rejectedWith('SafeERC20BulkTransferIncorrectTotalAmount'); + }); + + it(`should fail if the sum of rewards is less than the ask side fee`, async () => { + const latestBlockTimestamp = await getLatestBlockTimestamp(); + + const order: Order.TypeStruct = { + side: BID_SIDE, + collection: artTokenAddr, + currency: usdcAddr, + maker: makerAddr, + tokenId: TOKEN_ID, + price: ORDER_PRICE, + makerFee: BID_SIDE_FEE, + startTime: latestBlockTimestamp, + endTime: latestBlockTimestamp + HOUR, + }; + + const orderExecutionPermit: OrderExecutionPermit.TypeStruct = { + orderHash: MarketUtils.hashOrder(order), + taker: takerAddr, + takerFee: ASK_SIDE_FEE, + participants: [institutionAddr], + rewards: [ASK_SIDE_FEE - 1n], // Incorrect rewards sum + deadline: latestBlockTimestamp + HOUR, + }; + + const tx = MarketUtils.executeBid({ + market, + order, + permit: orderExecutionPermit, + orderSigner: maker, + permitSigner: marketSigner, + sender: taker, + }); + + await expect(tx).rejectedWith('SafeERC20BulkTransferIncorrectTotalAmount'); }); }); @@ -1252,7 +1416,9 @@ describe('Market', function () { expect(invalidated).equal(true); - await expect(tx).to.be.emit(market, 'OrderInvalidated').withArgs(makerAddr, orderHash); + await expect(tx) // + .emit(market, 'OrderInvalidated') + .withArgs(makerAddr, orderHash); }); it(`should invalidate the order if the sender is the market admin`, async () => { @@ -1264,7 +1430,9 @@ describe('Market', function () { expect(invalidated).equal(true); - await expect(tx).to.be.emit(market, 'OrderInvalidated').withArgs(makerAddr, orderHash); + await expect(tx) // + .emit(market, 'OrderInvalidated') + .withArgs(makerAddr, orderHash); }); it(`should fail when trying to invalidate an already invalidated order`, async () => { @@ -1276,7 +1444,7 @@ describe('Market', function () { // Second invalidation attempt const tx = market.connect(maker).invalidateOrder(maker, orderHash); - await expect(tx).to.eventually.rejectedWith('MarketOrderInvalidated'); + await expect(tx).rejectedWith('MarketOrderInvalidated'); }); it(`should fail if the sender is not the maker or the market admin`, async () => { @@ -1284,7 +1452,23 @@ describe('Market', function () { const tx = market.connect(randomAccount).invalidateOrder(maker, orderHash); - await expect(tx).to.eventually.rejectedWith('MarketUnauthorizedAccount'); + await expect(tx).rejectedWith('MarketUnauthorizedAccount'); + }); + }); + + describe(`method 'orderInvalidated'`, () => { + it(`should return the correct value`, async () => { + const orderHash = randomBytes(32); + + const orderInvalidatedBefore = await market.orderInvalidated(maker, orderHash); + + expect(orderInvalidatedBefore).equal(false); + + await market.connect(maker).invalidateOrder(maker, orderHash); + + const orderInvalidatedAfter = await market.orderInvalidated(maker, orderHash); + + expect(orderInvalidatedAfter).equal(true); }); }); }); diff --git a/tests/RoleSystem.ts b/tests/RoleSystem.ts index 89bbc45..e867bb8 100644 --- a/tests/RoleSystem.ts +++ b/tests/RoleSystem.ts @@ -29,19 +29,21 @@ describe('RoleSystem', function () { describe(`roles`, () => { describe(`method 'grantRole'`, () => { it(`should grant a role`, async () => { - const transaction = await roleSystem.grantRole(ADMIN_ROLE, account); + const tx = await roleSystem.grantRole(ADMIN_ROLE, account); - await expect(transaction) - .to.be.emit(roleSystem, 'RoleGranted') - .withArgs(ADMIN_ROLE, accountAddr); + const hasRole = await roleSystem.hasRole(ADMIN_ROLE, account); + + expect(hasRole).equal(true); - await expect(roleSystem.hasRole(ADMIN_ROLE, account)).to.eventually.equal(true); + await expect(tx) // + .emit(roleSystem, 'RoleGranted') + .withArgs(ADMIN_ROLE, accountAddr); }); it(`should fail if the sender is not the main account`, async () => { - await expect( - roleSystem.connect(account).grantRole(ADMIN_ROLE, account), - ).to.eventually.rejectedWith('RoleSystemNotMain'); + const tx = roleSystem.connect(account).grantRole(ADMIN_ROLE, account); + + await expect(tx).rejectedWith('RoleSystemNotMain'); }); }); @@ -51,19 +53,21 @@ describe('RoleSystem', function () { }); it(`should revoke a role`, async () => { - const transaction = await roleSystem.revokeRole(ADMIN_ROLE, account); + const tx = await roleSystem.revokeRole(ADMIN_ROLE, account); - await expect(transaction) - .to.be.emit(roleSystem, 'RoleRevoked') - .withArgs(ADMIN_ROLE, accountAddr); + const hasRole = await roleSystem.hasRole(ADMIN_ROLE, account); + + expect(hasRole).equal(false); - await expect(roleSystem.hasRole(ADMIN_ROLE, account)).to.eventually.equal(false); + await expect(tx) // + .emit(roleSystem, 'RoleRevoked') + .withArgs(ADMIN_ROLE, accountAddr); }); it(`should fail if the sender is not the main account`, async () => { - await expect( - roleSystem.connect(account).revokeRole(ADMIN_ROLE, account), - ).to.eventually.rejectedWith('RoleSystemNotMain'); + const tx = roleSystem.connect(account).revokeRole(ADMIN_ROLE, account); + + await expect(tx).rejectedWith('RoleSystemNotMain'); }); }); @@ -71,16 +75,21 @@ describe('RoleSystem', function () { it(`should return the correct value`, async () => { await roleSystem.grantRole(ADMIN_ROLE, account); - await expect(roleSystem.hasRole(ADMIN_ROLE, account)).to.eventually.equal(true); + const hasRoleAfterGrant = await roleSystem.hasRole(ADMIN_ROLE, account); + + expect(hasRoleAfterGrant).equal(true); await roleSystem.revokeRole(ADMIN_ROLE, account); - await expect(roleSystem.hasRole(ADMIN_ROLE, account)).to.eventually.equal(false); + const hasRoleAfterRevoke = await roleSystem.hasRole(ADMIN_ROLE, account); + + expect(hasRoleAfterRevoke).equal(false); }); it(`should fail if the account is the zero address`, async () => { - await expect(roleSystem.hasRole(ADMIN_ROLE, ZeroAddress)) // - .to.eventually.rejectedWith('RoleSystemZeroAddress'); + const hasRole = roleSystem.hasRole(ADMIN_ROLE, ZeroAddress); + + await expect(hasRole).rejectedWith('RoleSystemZeroAddress'); }); }); }); @@ -91,20 +100,20 @@ describe('RoleSystem', function () { const tx1 = await roleSystem.transferUniqueRole(ADMIN_ROLE, account); await expect(tx1) - .to.be.emit(roleSystem, 'UniqueRoleTransferred') + .emit(roleSystem, 'UniqueRoleTransferred') .withArgs(ADMIN_ROLE, accountAddr); const tx2 = await roleSystem.transferUniqueRole(ADMIN_ROLE, ZeroAddress); await expect(tx2) - .to.be.emit(roleSystem, 'UniqueRoleTransferred') + .emit(roleSystem, 'UniqueRoleTransferred') .withArgs(ADMIN_ROLE, ZeroAddress); }); it(`should fail if the sender is not the main account`, async () => { const tx = roleSystem.connect(account).transferUniqueRole(ADMIN_ROLE, account); - await expect(tx).to.eventually.rejectedWith('RoleSystemNotMain'); + await expect(tx).rejectedWith('RoleSystemNotMain'); }); }); @@ -112,14 +121,15 @@ describe('RoleSystem', function () { it(`should return the owner`, async () => { await roleSystem.transferUniqueRole(ADMIN_ROLE, account); - await expect(roleSystem.uniqueRoleOwner(ADMIN_ROLE)) // - .to.eventually.equal(accountAddr); + const uniqueRoleOwner = await roleSystem.uniqueRoleOwner(ADMIN_ROLE); + + expect(uniqueRoleOwner).equal(accountAddr); }); it(`should fail if the role does not have an owner`, async () => { const tx = roleSystem.uniqueRoleOwner(ADMIN_ROLE); - await expect(tx).to.eventually.rejectedWith('RoleSystemZeroAddress'); + await expect(tx).rejectedWith('RoleSystemZeroAddress'); }); }); }); diff --git a/tests/SafeERC20BulkTransfer.ts b/tests/SafeERC20BulkTransfer.ts index fcd4290..bb33d63 100644 --- a/tests/SafeERC20BulkTransfer.ts +++ b/tests/SafeERC20BulkTransfer.ts @@ -1,3 +1,3 @@ describe('SafeERC20BulkTransfer', function () { - // TODO + it('should perform bulk transfer successfully'); }); diff --git a/tests/constants/art-token.ts b/tests/constants/art-token.ts index 7c1f899..1688bda 100644 --- a/tests/constants/art-token.ts +++ b/tests/constants/art-token.ts @@ -1,5 +1,6 @@ -import { ZeroAddress } from 'ethers'; import { TokenConfig } from '../../typechain-types/contracts/art-token/ArtToken'; +import { ONE_HUNDRED } from './general'; +import { REGULATION_MODE_REGULATED } from './token-config'; export const ART_TOKEN_DOMAIN_NAME = 'ArtToken'; export const ART_TOKEN_DOMAIN_VERSION = '1'; @@ -8,6 +9,7 @@ export const TOKEN_MINTING_PERMIT_TYPE = { TokenMintingPermit: [ { name: 'tokenId', type: 'uint256' }, { name: 'minter', type: 'address' }, + { name: 'currency', type: 'address' }, { name: 'price', type: 'uint256' }, { name: 'fee', type: 'uint256' }, { name: 'tokenURI', type: 'string' }, @@ -18,17 +20,19 @@ export const TOKEN_MINTING_PERMIT_TYPE = { ], }; -export const TOKEN_CONFIG_TYPE = { - TokenConfig: [ - { name: 'creator', type: 'address' }, - { name: 'regulationMode', type: 'uint8' }, - ], -}; - export const TOKEN_ID = 1; +export const NON_EXISTENT_TOKEN_ID = 9999; export const TOKEN_URI = 'ipfs://QmbQ9c4KN5FcGreai5rjTRUs1N2FFMaY819JGZZMGDcSLQ'; +export const SECOND_TOKEN_URI = 'ipfs://QmbqKeWzBDUwKzVye3RxeD67N7rQrfgTaPTevucfbP3BST'; + +export const TOKEN_PRICE = 1_000_000_000n; +export const TOKEN_FEE = 100_000_000n; +export const TOKEN_ROYALTY_PERCENT = ONE_HUNDRED / 20n; // 5% + +export const TOKEN_CREATOR_ADDR = '0x1000000000000000000000000000000000000000'; +export const TOKEN_REGULATION_MODE = REGULATION_MODE_REGULATED; export const TOKEN_CONFIG: TokenConfig.TypeStruct = { - creator: ZeroAddress, - regulationMode: 0, -} as const; + creator: TOKEN_CREATOR_ADDR, + regulationMode: TOKEN_REGULATION_MODE, +}; diff --git a/tests/constants/auction-house.ts b/tests/constants/auction-house.ts index 6f6ff88..8a130be 100644 --- a/tests/constants/auction-house.ts +++ b/tests/constants/auction-house.ts @@ -5,6 +5,7 @@ export const AUCTION_CREATION_PERMIT_TYPE = { AuctionCreationPermit: [ { name: 'auctionId', type: 'uint256' }, { name: 'tokenId', type: 'uint256' }, + { name: 'currency', type: 'address' }, { name: 'price', type: 'uint256' }, { name: 'fee', type: 'uint256' }, { name: 'step', type: 'uint256' }, @@ -17,7 +18,12 @@ export const AUCTION_CREATION_PERMIT_TYPE = { ], }; +export const MIN_AUCTION_DURATION = 1800; + export const AUCTION_ID = 1; +export const NON_EXISTENT_AUCTION_ID = 9999; export const SECOND_AUCTION_ID = 2; + export const AUCTION_STEP = 1_000_000n; -export const MIN_AUCTION_DURATION = 1800; +export const AUCTION_PRICE = 1_000_000_000n; +export const AUCTION_FEE = 100_000_000n; diff --git a/tests/constants/distribution.ts b/tests/constants/distribution.ts deleted file mode 100644 index 87300bc..0000000 --- a/tests/constants/distribution.ts +++ /dev/null @@ -1 +0,0 @@ -export const TOTAL_SHARE = 10_000n; diff --git a/tests/constants/general.ts b/tests/constants/general.ts new file mode 100644 index 0000000..e608174 --- /dev/null +++ b/tests/constants/general.ts @@ -0,0 +1,3 @@ +export const HOUR = 3600; +export const ONE_HUNDRED = 10_000n; +export const ETHER_ADDR = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; diff --git a/tests/constants/market.ts b/tests/constants/market.ts index 2c5a39b..977ae08 100644 --- a/tests/constants/market.ts +++ b/tests/constants/market.ts @@ -29,6 +29,6 @@ export const ORDER_EXECUTION_PERMIT_TYPE = { export const ASK_SIDE = 0; export const BID_SIDE = 1; -export const PRICE = 10_000_000_000n; +export const ORDER_PRICE = 10_000_000_000n; export const ASK_SIDE_FEE = 100_000_000n; export const BID_SIDE_FEE = 100_000_000n; diff --git a/tests/constants/min-price-and-fee.ts b/tests/constants/min-price-and-fee.ts deleted file mode 100644 index c0eec4e..0000000 --- a/tests/constants/min-price-and-fee.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const MIN_PRICE = 100_000_000n; -export const MIN_FEE = 100_000_000n; diff --git a/tests/constants/time.ts b/tests/constants/time.ts deleted file mode 100644 index 82340ca..0000000 --- a/tests/constants/time.ts +++ /dev/null @@ -1 +0,0 @@ -export const HOUR = 3600; diff --git a/tests/constants/token-config.ts b/tests/constants/token-config.ts new file mode 100644 index 0000000..ee4d15e --- /dev/null +++ b/tests/constants/token-config.ts @@ -0,0 +1,10 @@ +export const TOKEN_CONFIG_TYPE = { + TokenConfig: [ + { name: 'creator', type: 'address' }, + { name: 'regulationMode', type: 'uint8' }, + ], +}; + +export const REGULATION_MODE_NONE = 0; +export const REGULATION_MODE_UNREGULATED = 1; +export const REGULATION_MODE_REGULATED = 2; diff --git a/tests/utils/art-token-utils.ts b/tests/utils/art-token-utils.ts index e2b1028..a9aeac9 100644 --- a/tests/utils/art-token-utils.ts +++ b/tests/utils/art-token-utils.ts @@ -1,18 +1,15 @@ -import { Signer, TypedDataDomain, TypedDataEncoder } from 'ethers'; +import { Signer, TypedDataDomain } from 'ethers'; import { ART_TOKEN_DOMAIN_NAME, ART_TOKEN_DOMAIN_VERSION, - TOKEN_CONFIG_TYPE, TOKEN_MINTING_PERMIT_TYPE, } from '../constants/art-token'; +import { TokenConfigUtils } from './token-config-utils'; import { ArtToken } from '../../typechain-types'; import { getChainId } from './get-chain-id'; -import { - TokenConfig, - TokenMintingPermit, -} from '../../typechain-types/contracts/art-token/ArtToken'; +import { TokenMintingPermit } from '../../typechain-types/contracts/art-token/ArtToken'; -type BuyArgs = { +type MintArgs = { artToken: ArtToken; permit: TokenMintingPermit.TypeStruct; permitSigner: Signer; @@ -20,12 +17,12 @@ type BuyArgs = { }; export class ArtTokenUtils { - static async mint(args: BuyArgs) { + static async mint(args: MintArgs) { const { artToken, permit, permitSigner, sender } = args; const domain = await this.buildDomain(artToken); - const tokenConfigHash = this.hashTokenConfig(permit.tokenConfig); + const tokenConfigHash = TokenConfigUtils.hash(permit.tokenConfig); const permitSignature = await permitSigner.signTypedData( domain, @@ -36,10 +33,6 @@ export class ArtTokenUtils { return artToken.connect(sender).mint(permit, permitSignature); } - static hashTokenConfig(tokenConfig: TokenConfig.TypeStruct) { - return TypedDataEncoder.from(TOKEN_CONFIG_TYPE).hash(tokenConfig); - } - static async buildDomain(artToken: ArtToken): Promise { const [chainId, verifyingContract] = await Promise.all([ getChainId(), diff --git a/tests/utils/auction-house-utils.ts b/tests/utils/auction-house-utils.ts index c489014..588a046 100644 --- a/tests/utils/auction-house-utils.ts +++ b/tests/utils/auction-house-utils.ts @@ -7,7 +7,7 @@ import { AUCTION_HOUSE_DOMAIN_VERSION, AUCTION_CREATION_PERMIT_TYPE, } from '../constants/auction-house'; -import { ArtTokenUtils } from './art-token-utils'; +import { TokenConfigUtils } from './token-config-utils'; type CreateArgs = { auctionHouse: AuctionHouse; @@ -22,7 +22,7 @@ export class AuctionHouseUtils { const domain = await this.buildDomain(auctionHouse); - const tokenConfigHash = ArtTokenUtils.hashTokenConfig(permit.tokenConfig); + const tokenConfigHash = TokenConfigUtils.hash(permit.tokenConfig); const permitSignature = await permitSigner.signTypedData( domain, diff --git a/tests/utils/deploy-all.ts b/tests/utils/deploy-all.ts index 6e6e71a..5865593 100644 --- a/tests/utils/deploy-all.ts +++ b/tests/utils/deploy-all.ts @@ -8,7 +8,6 @@ import { OwnershipTransferredEvent } from '../../typechain-types/@openzeppelin/c import { DeployedEvent } from '../../typechain-types/contracts/tests/AllDeployer'; import { deploy } from '../../scripts/deploy'; import { MIN_AUCTION_DURATION } from '../constants/auction-house'; -import { MIN_FEE, MIN_PRICE } from '../constants/min-price-and-fee'; type Params = { signer: AddressLike; @@ -27,7 +26,7 @@ export async function deployAll(params: Params, deployer?: Signer) { const { receipt } = await deploy( { name: 'AllDeployer', - constructorArgs: [signer, financier, admin, MIN_PRICE, MIN_FEE, MIN_AUCTION_DURATION], + constructorArgs: [signer, financier, admin, MIN_AUCTION_DURATION], }, deployer, ); diff --git a/tests/utils/token-config-utils.ts b/tests/utils/token-config-utils.ts new file mode 100644 index 0000000..6c026c8 --- /dev/null +++ b/tests/utils/token-config-utils.ts @@ -0,0 +1,9 @@ +import { TypedDataEncoder } from 'ethers'; +import { TOKEN_CONFIG_TYPE } from '../constants/token-config'; +import { TokenConfig } from '../../typechain-types/contracts/art-token/ArtToken'; + +export class TokenConfigUtils { + static hash(tokenConfig: TokenConfig.TypeStruct) { + return TypedDataEncoder.from(TOKEN_CONFIG_TYPE).hash(tokenConfig); + } +} diff --git a/types/environment.ts b/types/environment.ts index 62345fd..6490136 100644 --- a/types/environment.ts +++ b/types/environment.ts @@ -1,47 +1,71 @@ -export type ChainConfig = { +/* ################### Chain Config ############################# */ +export type ChainConfigYaml = { + [chainName: string]: ChainChainConfigYaml; +}; + +type ChainChainConfigYaml = { chainId: number; url: string; deployerPrivateKey: string; - usdc: string; main: string; }; -export type CollectionConfig = CollectionData & { - minPriceUsd: number; - minFeeUsd: number; +/* ################### Collection Config ############################# */ + +export type CollectionConfigYaml = CollectionDataYaml & { + [chainName: string]: ChainCollectionConfigYaml; +}; + +type CollectionDataYaml = { + name: string; + symbol: string; +}; + +type ChainCollectionConfigYaml = { minAuctionDurationHours: number; artToken: UpgradeableContractConfig; auctionHouse: UpgradeableContractConfig; }; -export type MarketConfig = { - market: UpgradeableContractConfig; -}; +/* ################### Market Config ############################# */ -export type ProtocolConfig = Pick & { - collection: CollectionConfig; - market: MarketConfig; +export type MarketConfigYaml = { + [chainName: string]: ChainMarketConfigYaml; }; -export type ChainConfigTop = { - [chainName: string]: ChainConfig; +type ChainMarketConfigYaml = { + market: UpgradeableContractConfig; }; -export type CollectionConfigTop = CollectionData & { - [chainName: string]: Omit; +/* ################### Env Config ############################# */ + +export type EnvConfigYaml = { + fork: { + name: string; + chainId: number; + url: string; + }; + reportGas: boolean; + etherscanApiKey: string; + coinmarketcapApiKey: string; }; -export type MarketConfigTop = { - [chainName: string]: MarketConfig; +/* ################### Formatted Configs ############################# */ + +export type EnvConfig = EnvConfigYaml; +export type ChainConfig = ChainChainConfigYaml; +export type CollectionConfig = CollectionDataYaml & ChainCollectionConfigYaml; +export type MarketConfig = ChainMarketConfigYaml; + +export type ProtocolConfig = Pick & { + collection: CollectionConfig; + market: MarketConfig; }; +/* ################### Common Types ############################# */ + type UpgradeableContractConfig = { proxy: string; impl: string; admin: string; }; - -type CollectionData = { - name: string; - symbol: string; -};